org.mozilla.javascript.JavaMembers Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of js Show documentation
Show all versions of js Show documentation
Rhino is an open-source implementation of JavaScript written entirely in Java. It is typically embedded into Java applications to provide scripting to end users.
The newest version!
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Cameron McCormack
* Frank Mitchell
* Mike Shaver
* Kurt Westerfeld
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.javascript;
import java.lang.reflect.*;
import java.util.*;
/**
*
* @author Mike Shaver
* @author Norris Boyd
* @see NativeJavaObject
* @see NativeJavaClass
*/
class JavaMembers
{
JavaMembers(Scriptable scope, Class> cl)
{
this(scope, cl, false);
}
JavaMembers(Scriptable scope, Class> cl, boolean includeProtected)
{
try {
Context cx = ContextFactory.getGlobal().enterContext();
ClassShutter shutter = cx.getClassShutter();
if (shutter != null && !shutter.visibleToScripts(cl.getName())) {
throw Context.reportRuntimeError1("msg.access.prohibited",
cl.getName());
}
this.includePrivate = cx.hasFeature(
Context.FEATURE_ENHANCED_JAVA_ACCESS);
this.members = new HashMap();
this.staticMembers = new HashMap();
this.cl = cl;
reflect(scope, includeProtected);
} finally {
Context.exit();
}
}
boolean has(String name, boolean isStatic)
{
Map ht = isStatic ? staticMembers : members;
Object obj = ht.get(name);
if (obj != null) {
return true;
}
return findExplicitFunction(name, isStatic) != null;
}
Object get(Scriptable scope, String name, Object javaObject,
boolean isStatic)
{
Map ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (!isStatic && member == null) {
// Try to get static member from instance (LC3)
member = staticMembers.get(name);
}
if (member == null) {
member = this.getExplicitFunction(scope, name,
javaObject, isStatic);
if (member == null)
return Scriptable.NOT_FOUND;
}
if (member instanceof Scriptable) {
return member;
}
Context cx = Context.getContext();
Object rval;
Class> type;
try {
if (member instanceof BeanProperty) {
BeanProperty bp = (BeanProperty) member;
if (bp.getter == null)
return Scriptable.NOT_FOUND;
rval = bp.getter.invoke(javaObject, Context.emptyArgs);
type = bp.getter.method().getReturnType();
} else {
Field field = (Field) member;
rval = field.get(isStatic ? null : javaObject);
type = field.getType();
}
} catch (Exception ex) {
throw Context.throwAsScriptRuntimeEx(ex);
}
// Need to wrap the object before we return it.
scope = ScriptableObject.getTopLevelScope(scope);
return cx.getWrapFactory().wrap(cx, scope, rval, type);
}
void put(Scriptable scope, String name, Object javaObject,
Object value, boolean isStatic)
{
Map ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (!isStatic && member == null) {
// Try to get static member from instance (LC3)
member = staticMembers.get(name);
}
if (member == null)
throw reportMemberNotFound(name);
if (member instanceof FieldAndMethods) {
FieldAndMethods fam = (FieldAndMethods) ht.get(name);
member = fam.field;
}
// Is this a bean property "set"?
if (member instanceof BeanProperty) {
BeanProperty bp = (BeanProperty)member;
if (bp.setter == null) {
throw reportMemberNotFound(name);
}
// If there's only one setter or if the value is null, use the
// main setter. Otherwise, let the NativeJavaMethod decide which
// setter to use:
if (bp.setters == null || value == null) {
Class> setType = bp.setter.argTypes[0];
Object[] args = { Context.jsToJava(value, setType) };
try {
bp.setter.invoke(javaObject, args);
} catch (Exception ex) {
throw Context.throwAsScriptRuntimeEx(ex);
}
} else {
Object[] args = { value };
bp.setters.call(Context.getContext(),
ScriptableObject.getTopLevelScope(scope),
scope, args);
}
}
else {
if (!(member instanceof Field)) {
String str = (member == null) ? "msg.java.internal.private"
: "msg.java.method.assign";
throw Context.reportRuntimeError1(str, name);
}
Field field = (Field)member;
Object javaValue = Context.jsToJava(value, field.getType());
try {
field.set(javaObject, javaValue);
} catch (IllegalAccessException accessEx) {
if ((field.getModifiers() & Modifier.FINAL) != 0) {
// treat Java final the same as JavaScript [[READONLY]]
return;
}
throw Context.throwAsScriptRuntimeEx(accessEx);
} catch (IllegalArgumentException argEx) {
throw Context.reportRuntimeError3(
"msg.java.internal.field.type",
value.getClass().getName(), field,
javaObject.getClass().getName());
}
}
}
Object[] getIds(boolean isStatic)
{
Map map = isStatic ? staticMembers : members;
return map.keySet().toArray(new Object[map.size()]);
}
static String javaSignature(Class> type)
{
if (!type.isArray()) {
return type.getName();
} else {
int arrayDimension = 0;
do {
++arrayDimension;
type = type.getComponentType();
} while (type.isArray());
String name = type.getName();
String suffix = "[]";
if (arrayDimension == 1) {
return name.concat(suffix);
} else {
int length = name.length() + arrayDimension * suffix.length();
StringBuffer sb = new StringBuffer(length);
sb.append(name);
while (arrayDimension != 0) {
--arrayDimension;
sb.append(suffix);
}
return sb.toString();
}
}
}
static String liveConnectSignature(Class>[] argTypes)
{
int N = argTypes.length;
if (N == 0) { return "()"; }
StringBuffer sb = new StringBuffer();
sb.append('(');
for (int i = 0; i != N; ++i) {
if (i != 0) {
sb.append(',');
}
sb.append(javaSignature(argTypes[i]));
}
sb.append(')');
return sb.toString();
}
private MemberBox findExplicitFunction(String name, boolean isStatic)
{
int sigStart = name.indexOf('(');
if (sigStart < 0) { return null; }
Map ht = isStatic ? staticMembers : members;
MemberBox[] methodsOrCtors = null;
boolean isCtor = (isStatic && sigStart == 0);
if (isCtor) {
// Explicit request for an overloaded constructor
methodsOrCtors = ctors;
} else {
// Explicit request for an overloaded method
String trueName = name.substring(0,sigStart);
Object obj = ht.get(trueName);
if (!isStatic && obj == null) {
// Try to get static member from instance (LC3)
obj = staticMembers.get(trueName);
}
if (obj instanceof NativeJavaMethod) {
NativeJavaMethod njm = (NativeJavaMethod)obj;
methodsOrCtors = njm.methods;
}
}
if (methodsOrCtors != null) {
for (int i = 0; i < methodsOrCtors.length; i++) {
Class>[] type = methodsOrCtors[i].argTypes;
String sig = liveConnectSignature(type);
if (sigStart + sig.length() == name.length()
&& name.regionMatches(sigStart, sig, 0, sig.length()))
{
return methodsOrCtors[i];
}
}
}
return null;
}
private Object getExplicitFunction(Scriptable scope, String name,
Object javaObject, boolean isStatic)
{
Map ht = isStatic ? staticMembers : members;
Object member = null;
MemberBox methodOrCtor = findExplicitFunction(name, isStatic);
if (methodOrCtor != null) {
Scriptable prototype =
ScriptableObject.getFunctionPrototype(scope);
if (methodOrCtor.isCtor()) {
NativeJavaConstructor fun =
new NativeJavaConstructor(methodOrCtor);
fun.setPrototype(prototype);
member = fun;
ht.put(name, fun);
} else {
String trueName = methodOrCtor.getName();
member = ht.get(trueName);
if (member instanceof NativeJavaMethod &&
((NativeJavaMethod)member).methods.length > 1 ) {
NativeJavaMethod fun =
new NativeJavaMethod(methodOrCtor, name);
fun.setPrototype(prototype);
ht.put(name, fun);
member = fun;
}
}
}
return member;
}
/**
* Retrieves mapping of methods to accessible methods for a class.
* In case the class is not public, retrieves methods with same
* signature as its public methods from public superclasses and
* interfaces (if they exist). Basically upcasts every method to the
* nearest accessible method.
*/
private static Method[] discoverAccessibleMethods(Class> clazz,
boolean includeProtected,
boolean includePrivate)
{
Map map = new HashMap();
discoverAccessibleMethods(clazz, map, includeProtected, includePrivate);
return map.values().toArray(new Method[map.size()]);
}
private static void discoverAccessibleMethods(Class> clazz,
Map map, boolean includeProtected,
boolean includePrivate)
{
if (Modifier.isPublic(clazz.getModifiers()) || includePrivate) {
try {
if (includeProtected || includePrivate) {
while (clazz != null) {
try {
Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
int mods = method.getModifiers();
if (Modifier.isPublic(mods) ||
Modifier.isProtected(mods) ||
includePrivate)
{
if (includePrivate)
method.setAccessible(true);
map.put(new MethodSignature(method), method);
}
}
clazz = clazz.getSuperclass();
} catch (SecurityException e) {
// Some security settings (i.e., applets) disallow
// access to Class.getDeclaredMethods. Fall back to
// Class.getMethods.
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
MethodSignature sig
= new MethodSignature(method);
if (map.get(sig) == null)
map.put(sig, method);
}
break; // getMethods gets superclass methods, no
// need to loop any more
}
}
} else {
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
MethodSignature sig = new MethodSignature(method);
map.put(sig, method);
}
}
return;
} catch (SecurityException e) {
Context.reportWarning(
"Could not discover accessible methods of class " +
clazz.getName() + " due to lack of privileges, " +
"attemping superclasses/interfaces.");
// Fall through and attempt to discover superclass/interface
// methods
}
}
Class>[] interfaces = clazz.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
discoverAccessibleMethods(interfaces[i], map, includeProtected,
includePrivate);
}
Class> superclass = clazz.getSuperclass();
if (superclass != null) {
discoverAccessibleMethods(superclass, map, includeProtected,
includePrivate);
}
}
private static final class MethodSignature
{
private final String name;
private final Class>[] args;
private MethodSignature(String name, Class>[] args)
{
this.name = name;
this.args = args;
}
MethodSignature(Method method)
{
this(method.getName(), method.getParameterTypes());
}
@Override
public boolean equals(Object o)
{
if(o instanceof MethodSignature)
{
MethodSignature ms = (MethodSignature)o;
return ms.name.equals(name) && Arrays.equals(args, ms.args);
}
return false;
}
@Override
public int hashCode()
{
return name.hashCode() ^ args.length;
}
}
private void reflect(Scriptable scope, boolean includeProtected)
{
// We reflect methods first, because we want overloaded field/method
// names to be allocated to the NativeJavaMethod before the field
// gets in the way.
Method[] methods = discoverAccessibleMethods(cl, includeProtected,
includePrivate);
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
int mods = method.getModifiers();
boolean isStatic = Modifier.isStatic(mods);
Map ht = isStatic ? staticMembers : members;
String name = method.getName();
Object value = ht.get(name);
if (value == null) {
ht.put(name, method);
} else {
ObjArray overloadedMethods;
if (value instanceof ObjArray) {
overloadedMethods = (ObjArray)value;
} else {
if (!(value instanceof Method)) Kit.codeBug();
// value should be instance of Method as at this stage
// staticMembers and members can only contain methods
overloadedMethods = new ObjArray();
overloadedMethods.add(value);
ht.put(name, overloadedMethods);
}
overloadedMethods.add(method);
}
}
// replace Method instances by wrapped NativeJavaMethod objects
// first in staticMembers and then in members
for (int tableCursor = 0; tableCursor != 2; ++tableCursor) {
boolean isStatic = (tableCursor == 0);
Map ht = isStatic ? staticMembers : members;
for (String name: ht.keySet()) {
MemberBox[] methodBoxes;
Object value = ht.get(name);
if (value instanceof Method) {
methodBoxes = new MemberBox[1];
methodBoxes[0] = new MemberBox((Method)value);
} else {
ObjArray overloadedMethods = (ObjArray)value;
int N = overloadedMethods.size();
if (N < 2) Kit.codeBug();
methodBoxes = new MemberBox[N];
for (int i = 0; i != N; ++i) {
Method method = (Method)overloadedMethods.get(i);
methodBoxes[i] = new MemberBox(method);
}
}
NativeJavaMethod fun = new NativeJavaMethod(methodBoxes);
if (scope != null) {
ScriptRuntime.setFunctionProtoAndParent(fun, scope);
}
ht.put(name, fun);
}
}
// Reflect fields.
Field[] fields = getAccessibleFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
String name = field.getName();
int mods = field.getModifiers();
if (!includePrivate && !Modifier.isPublic(mods)) {
continue;
}
try {
boolean isStatic = Modifier.isStatic(mods);
Map ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (member == null) {
ht.put(name, field);
} else if (member instanceof NativeJavaMethod) {
NativeJavaMethod method = (NativeJavaMethod) member;
FieldAndMethods fam
= new FieldAndMethods(scope, method.methods, field);
Map fmht = isStatic ? staticFieldAndMethods
: fieldAndMethods;
if (fmht == null) {
fmht = new HashMap();
if (isStatic) {
staticFieldAndMethods = fmht;
} else {
fieldAndMethods = fmht;
}
}
fmht.put(name, fam);
ht.put(name, fam);
} else if (member instanceof Field) {
Field oldField = (Field) member;
// If this newly reflected field shadows an inherited field,
// then replace it. Otherwise, since access to the field
// would be ambiguous from Java, no field should be
// reflected.
// For now, the first field found wins, unless another field
// explicitly shadows it.
if (oldField.getDeclaringClass().
isAssignableFrom(field.getDeclaringClass()))
{
ht.put(name, field);
}
} else {
// "unknown member type"
Kit.codeBug();
}
} catch (SecurityException e) {
// skip this field
Context.reportWarning("Could not access field "
+ name + " of class " + cl.getName() +
" due to lack of privileges.");
}
}
// Create bean properties from corresponding get/set methods first for
// static members and then for instance members
for (int tableCursor = 0; tableCursor != 2; ++tableCursor) {
boolean isStatic = (tableCursor == 0);
Map ht = isStatic ? staticMembers : members;
Map toAdd = new HashMap();
// Now, For each member, make "bean" properties.
for (String name: ht.keySet()) {
// Is this a getter?
boolean memberIsGetMethod = name.startsWith("get");
boolean memberIsSetMethod = name.startsWith("set");
boolean memberIsIsMethod = name.startsWith("is");
if (memberIsGetMethod || memberIsIsMethod
|| memberIsSetMethod) {
// Double check name component.
String nameComponent
= name.substring(memberIsIsMethod ? 2 : 3);
if (nameComponent.length() == 0)
continue;
// Make the bean property name.
String beanPropertyName = nameComponent;
char ch0 = nameComponent.charAt(0);
if (Character.isUpperCase(ch0)) {
if (nameComponent.length() == 1) {
beanPropertyName = nameComponent.toLowerCase();
} else {
char ch1 = nameComponent.charAt(1);
if (!Character.isUpperCase(ch1)) {
beanPropertyName = Character.toLowerCase(ch0)
+nameComponent.substring(1);
}
}
}
// If we already have a member by this name, don't do this
// property.
if (toAdd.containsKey(beanPropertyName))
continue;
Object v = ht.get(beanPropertyName);
if (v != null) {
// A private field shouldn't mask a public getter/setter
if (!includePrivate || !(v instanceof Member) ||
!Modifier.isPrivate(((Member)v).getModifiers()))
{
continue;
}
}
// Find the getter method, or if there is none, the is-
// method.
MemberBox getter = null;
getter = findGetter(isStatic, ht, "get", nameComponent);
// If there was no valid getter, check for an is- method.
if (getter == null) {
getter = findGetter(isStatic, ht, "is", nameComponent);
}
// setter
MemberBox setter = null;
NativeJavaMethod setters = null;
String setterName = "set".concat(nameComponent);
if (ht.containsKey(setterName)) {
// Is this value a method?
Object member = ht.get(setterName);
if (member instanceof NativeJavaMethod) {
NativeJavaMethod njmSet = (NativeJavaMethod)member;
if (getter != null) {
// We have a getter. Now, do we have a matching
// setter?
Class> type = getter.method().getReturnType();
setter = extractSetMethod(type, njmSet.methods,
isStatic);
} else {
// No getter, find any set method
setter = extractSetMethod(njmSet.methods,
isStatic);
}
if (njmSet.methods.length > 1) {
setters = njmSet;
}
}
}
// Make the property.
BeanProperty bp = new BeanProperty(getter, setter,
setters);
toAdd.put(beanPropertyName, bp);
}
}
// Add the new bean properties.
for (String key: toAdd.keySet()) {
Object value = toAdd.get(key);
ht.put(key, value);
}
}
// Reflect constructors
Constructor>[] constructors = getAccessibleConstructors();
ctors = new MemberBox[constructors.length];
for (int i = 0; i != constructors.length; ++i) {
ctors[i] = new MemberBox(constructors[i]);
}
}
private Constructor>[] getAccessibleConstructors()
{
// The JVM currently doesn't allow changing access on java.lang.Class
// constructors, so don't try
if (includePrivate && cl != ScriptRuntime.ClassClass) {
try {
Constructor>[] cons = cl.getDeclaredConstructors();
Constructor.setAccessible(cons, true);
return cons;
} catch (SecurityException e) {
// Fall through to !includePrivate case
Context.reportWarning("Could not access constructor " +
" of class " + cl.getName() +
" due to lack of privileges.");
}
}
return cl.getConstructors();
}
private Field[] getAccessibleFields() {
if (includePrivate) {
try {
List fieldsList = new ArrayList();
Class> currentClass = cl;
while (currentClass != null) {
// get all declared fields in this class, make them
// accessible, and save
Field[] declared = currentClass.getDeclaredFields();
for (int i = 0; i < declared.length; i++) {
declared[i].setAccessible(true);
fieldsList.add(declared[i]);
}
// walk up superclass chain. no need to deal specially with
// interfaces, since they can't have fields
currentClass = currentClass.getSuperclass();
}
return fieldsList.toArray(new Field[fieldsList.size()]);
} catch (SecurityException e) {
// fall through to !includePrivate case
}
}
return cl.getFields();
}
private MemberBox findGetter(boolean isStatic, Map ht, String prefix,
String propertyName)
{
String getterName = prefix.concat(propertyName);
if (ht.containsKey(getterName)) {
// Check that the getter is a method.
Object member = ht.get(getterName);
if (member instanceof NativeJavaMethod) {
NativeJavaMethod njmGet = (NativeJavaMethod) member;
return extractGetMethod(njmGet.methods, isStatic);
}
}
return null;
}
private static MemberBox extractGetMethod(MemberBox[] methods,
boolean isStatic)
{
// Inspect the list of all MemberBox for the only one having no
// parameters
for (int methodIdx = 0; methodIdx < methods.length; methodIdx++) {
MemberBox method = methods[methodIdx];
// Does getter method have an empty parameter list with a return
// value (eg. a getSomething() or isSomething())?
if (method.argTypes.length == 0
&& (!isStatic || method.isStatic()))
{
Class> type = method.method().getReturnType();
if (type != Void.TYPE) {
return method;
}
break;
}
}
return null;
}
private static MemberBox extractSetMethod(Class> type, MemberBox[] methods,
boolean isStatic)
{
//
// Note: it may be preferable to allow NativeJavaMethod.findFunction()
// to find the appropriate setter; unfortunately, it requires an
// instance of the target arg to determine that.
//
// Make two passes: one to find a method with direct type assignment,
// and one to find a widening conversion.
for (int pass = 1; pass <= 2; ++pass) {
for (int i = 0; i < methods.length; ++i) {
MemberBox method = methods[i];
if (!isStatic || method.isStatic()) {
Class>[] params = method.argTypes;
if (params.length == 1) {
if (pass == 1) {
if (params[0] == type) {
return method;
}
} else {
if (pass != 2) Kit.codeBug();
if (params[0].isAssignableFrom(type)) {
return method;
}
}
}
}
}
}
return null;
}
private static MemberBox extractSetMethod(MemberBox[] methods,
boolean isStatic)
{
for (int i = 0; i < methods.length; ++i) {
MemberBox method = methods[i];
if (!isStatic || method.isStatic()) {
if (method.method().getReturnType() == Void.TYPE) {
if (method.argTypes.length == 1) {
return method;
}
}
}
}
return null;
}
Map getFieldAndMethodsObjects(Scriptable scope,
Object javaObject, boolean isStatic)
{
Map ht = isStatic ? staticFieldAndMethods : fieldAndMethods;
if (ht == null)
return null;
int len = ht.size();
Map result = new HashMap(len);
for (FieldAndMethods fam: ht.values()) {
FieldAndMethods famNew = new FieldAndMethods(scope, fam.methods,
fam.field);
famNew.javaObject = javaObject;
result.put(fam.field.getName(), famNew);
}
return result;
}
static JavaMembers lookupClass(Scriptable scope, Class> dynamicType,
Class> staticType, boolean includeProtected)
{
JavaMembers members;
scope = ScriptableObject.getTopLevelScope(scope);
ClassCache cache = ClassCache.get(scope);
Map,JavaMembers> ct = cache.getClassCacheMap();
Class> cl = dynamicType;
for (;;) {
members = ct.get(cl);
if (members != null) {
return members;
}
try {
members = new JavaMembers(scope, cl, includeProtected);
break;
} catch (SecurityException e) {
// Reflection may fail for objects that are in a restricted
// access package (e.g. sun.*). If we get a security
// exception, try again with the static type if it is interface.
// Otherwise, try superclass
if (staticType != null && staticType.isInterface()) {
cl = staticType;
staticType = null; // try staticType only once
} else {
Class> parent = cl.getSuperclass();
if (parent == null) {
if (cl.isInterface()) {
// last resort after failed staticType interface
parent = ScriptRuntime.ObjectClass;
} else {
throw e;
}
}
cl = parent;
}
}
}
if (cache.isCachingEnabled())
ct.put(cl, members);
return members;
}
RuntimeException reportMemberNotFound(String memberName)
{
return Context.reportRuntimeError2(
"msg.java.member.not.found", cl.getName(), memberName);
}
private Class> cl;
private Map members;
private Map fieldAndMethods;
private Map staticMembers;
private Map staticFieldAndMethods;
MemberBox[] ctors;
private boolean includePrivate;
}
class BeanProperty
{
BeanProperty(MemberBox getter, MemberBox setter, NativeJavaMethod setters)
{
this.getter = getter;
this.setter = setter;
this.setters = setters;
}
MemberBox getter;
MemberBox setter;
NativeJavaMethod setters;
}
class FieldAndMethods extends NativeJavaMethod
{
static final long serialVersionUID = -9222428244284796755L;
FieldAndMethods(Scriptable scope, MemberBox[] methods, Field field)
{
super(methods);
this.field = field;
setParentScope(scope);
setPrototype(ScriptableObject.getFunctionPrototype(scope));
}
@Override
public Object getDefaultValue(Class> hint)
{
if (hint == ScriptRuntime.FunctionClass)
return this;
Object rval;
Class> type;
try {
rval = field.get(javaObject);
type = field.getType();
} catch (IllegalAccessException accEx) {
throw Context.reportRuntimeError1(
"msg.java.internal.private", field.getName());
}
Context cx = Context.getContext();
rval = cx.getWrapFactory().wrap(cx, this, rval, type);
if (rval instanceof Scriptable) {
rval = ((Scriptable) rval).getDefaultValue(hint);
}
return rval;
}
Field field;
Object javaObject;
}