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 Object getExplicitFunction( Scriptable scope, String name, Object javaObject, boolean isStatic) { Map<String, Object> 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; }
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; }
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 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<String, Object> 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<String, Object> 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<String, Object> 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<String, FieldAndMethods> fmht = isStatic ? staticFieldAndMethods : fieldAndMethods; if (fmht == null) { fmht = new HashMap<String, FieldAndMethods>(); 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<String, Object> ht = isStatic ? staticMembers : members; Map<String, BeanProperty> toAdd = new HashMap<String, BeanProperty>(); // 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 (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 (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]); } }