diff options
author | Egil Moeller <egil.moller@freecode.no> | 2010-03-22 00:16:53 +0100 |
---|---|---|
committer | Egil Moeller <egil.moller@freecode.no> | 2010-03-22 00:16:53 +0100 |
commit | fc00cfedd6c25d1634a1e0d28a7b7bc5f42e1cd7 (patch) | |
tree | 928419d6bfe794865e4b8f0634bd792f795c4b8a /infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java | |
parent | 0fdab3db005c4fa31fb8306b573c0b35073d3e56 (diff) | |
parent | d56b9b3b82cdebcaeb00eec0fcb4326ad21adaa8 (diff) | |
download | etherpad-fc00cfedd6c25d1634a1e0d28a7b7bc5f42e1cd7.tar.gz etherpad-fc00cfedd6c25d1634a1e0d28a7b7bc5f42e1cd7.tar.xz etherpad-fc00cfedd6c25d1634a1e0d28a7b7bc5f42e1cd7.zip |
Merge branch 'master' into plugin-framework
Diffstat (limited to 'infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java')
-rw-r--r-- | infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java | 935 |
1 files changed, 935 insertions, 0 deletions
diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java new file mode 100644 index 0000000..84ef2d4 --- /dev/null +++ b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaMembers.java @@ -0,0 +1,935 @@ +/* -*- 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 Hashtable(23); + this.staticMembers = new Hashtable(7); + this.cl = cl; + reflect(scope, includeProtected); + } finally { + Context.exit(); + } + } + + boolean has(String name, boolean isStatic) + { + Hashtable 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) + { + Hashtable 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) + { + Hashtable 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) + { + Hashtable ht = isStatic ? staticMembers : members; + int len = ht.size(); + Object[] result = new Object[len]; + Enumeration keys = ht.keys(); + for (int i=0; i < len; i++) + result[i] = keys.nextElement(); + return result; + } + + 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; } + + Hashtable 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) + { + Hashtable 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 (Method[])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()); + } + + 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; + } + + 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); + Hashtable 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); + Hashtable ht = (isStatic) ? staticMembers : members; + Enumeration e = ht.keys(); + while (e.hasMoreElements()) { + String name = (String)e.nextElement(); + 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); + Hashtable 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); + Hashtable fmht = isStatic ? staticFieldAndMethods + : fieldAndMethods; + if (fmht == null) { + fmht = new Hashtable(4); + 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 propeties 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); + Hashtable ht = (isStatic) ? staticMembers : members; + + Hashtable toAdd = new Hashtable(); + + // Now, For each member, make "bean" properties. + for (Enumeration e = ht.keys(); e.hasMoreElements(); ) { + + // Is this a getter? + String name = (String) e.nextElement(); + 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 (ht.containsKey(beanPropertyName) + || toAdd.containsKey(beanPropertyName)) { + 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 (Enumeration e = toAdd.keys(); e.hasMoreElements();) { + Object key = e.nextElement(); + 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 { + ArrayList 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 (Field[]) fieldsList.toArray( + new Field[fieldsList.size()]); + } catch (SecurityException e) { + // fall through to !includePrivate case + } + } + return cl.getFields(); + } + + private MemberBox findGetter(boolean isStatic, Hashtable 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; + } + + Hashtable getFieldAndMethodsObjects(Scriptable scope, Object javaObject, + boolean isStatic) + { + Hashtable ht = isStatic ? staticFieldAndMethods : fieldAndMethods; + if (ht == null) + return null; + int len = ht.size(); + Hashtable result = new Hashtable(len); + Enumeration e = ht.elements(); + while (len-- > 0) { + FieldAndMethods fam = (FieldAndMethods) e.nextElement(); + 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<Class<?>,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 Hashtable members; + private Hashtable fieldAndMethods; + private Hashtable staticMembers; + private Hashtable 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)); + } + + 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; +} |