001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
002: *
003: * ***** BEGIN LICENSE BLOCK *****
004: * Version: MPL 1.1/GPL 2.0
005: *
006: * The contents of this file are subject to the Mozilla Public License Version
007: * 1.1 (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: * http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the
014: * License.
015: *
016: * The Original Code is Rhino code, released
017: * May 6, 1999.
018: *
019: * The Initial Developer of the Original Code is
020: * Netscape Communications Corporation.
021: * Portions created by the Initial Developer are Copyright (C) 1997-2000
022: * the Initial Developer. All Rights Reserved.
023: *
024: * Contributor(s):
025: * Norris Boyd
026: * Cameron McCormack
027: * Frank Mitchell
028: * Mike Shaver
029: * Kurt Westerfeld
030: *
031: * Alternatively, the contents of this file may be used under the terms of
032: * the GNU General Public License Version 2 or later (the "GPL"), in which
033: * case the provisions of the GPL are applicable instead of those above. If
034: * you wish to allow use of your version of this file only under the terms of
035: * the GPL and not to allow others to use your version of this file under the
036: * MPL, indicate your decision by deleting the provisions above and replacing
037: * them with the notice and other provisions required by the GPL. If you do
038: * not delete the provisions above, a recipient may use your version of this
039: * file under either the MPL or the GPL.
040: *
041: * ***** END LICENSE BLOCK ***** */
042:
043: package org.mozilla.javascript;
044:
045: import java.lang.reflect.*;
046: import java.util.Arrays;
047: import java.util.HashMap;
048: import java.util.Hashtable;
049: import java.util.Enumeration;
050: import java.util.Map;
051:
052: /**
053: *
054: * @author Mike Shaver
055: * @author Norris Boyd
056: * @see NativeJavaObject
057: * @see NativeJavaClass
058: */
059: class JavaMembers {
060: JavaMembers(Scriptable scope, Class cl) {
061: this (scope, cl, false);
062: }
063:
064: JavaMembers(Scriptable scope, Class cl, boolean includeProtected) {
065: Context cx = Context.getContext();
066: ClassShutter shutter = cx.getClassShutter();
067: if (shutter != null && !shutter.visibleToScripts(cl.getName())) {
068: throw Context.reportRuntimeError1("msg.access.prohibited",
069: cl.getName());
070: }
071: this .members = new Hashtable(23);
072: this .staticMembers = new Hashtable(7);
073: this .cl = cl;
074: reflect(scope, includeProtected);
075: }
076:
077: boolean has(String name, boolean isStatic) {
078: Hashtable ht = isStatic ? staticMembers : members;
079: Object obj = ht.get(name);
080: if (obj != null) {
081: return true;
082: } else {
083: return null != findExplicitFunction(name, isStatic);
084: }
085: }
086:
087: Object get(Scriptable scope, String name, Object javaObject,
088: boolean isStatic) {
089: Hashtable ht = isStatic ? staticMembers : members;
090: Object member = ht.get(name);
091: if (!isStatic && member == null) {
092: // Try to get static member from instance (LC3)
093: member = staticMembers.get(name);
094: }
095: if (member == null) {
096: member = this .getExplicitFunction(scope, name, javaObject,
097: isStatic);
098: if (member == null)
099: return Scriptable.NOT_FOUND;
100: }
101: if (member instanceof Scriptable) {
102: return member;
103: }
104: Context cx = Context.getContext();
105: Object rval;
106: Class type;
107: try {
108: if (member instanceof BeanProperty) {
109: BeanProperty bp = (BeanProperty) member;
110: if (bp.getter == null)
111: return Scriptable.NOT_FOUND;
112: rval = bp.getter.invoke(javaObject, Context.emptyArgs);
113: type = bp.getter.method().getReturnType();
114: } else {
115: Field field = (Field) member;
116: rval = field.get(isStatic ? null : javaObject);
117: type = field.getType();
118: }
119: } catch (Exception ex) {
120: throw Context.throwAsScriptRuntimeEx(ex);
121: }
122: // Need to wrap the object before we return it.
123: scope = ScriptableObject.getTopLevelScope(scope);
124: return cx.getWrapFactory().wrap(cx, scope, rval, type);
125: }
126:
127: void put(Scriptable scope, String name, Object javaObject,
128: Object value, boolean isStatic) {
129: Hashtable ht = isStatic ? staticMembers : members;
130: Object member = ht.get(name);
131: if (!isStatic && member == null) {
132: // Try to get static member from instance (LC3)
133: member = staticMembers.get(name);
134: }
135: if (member == null)
136: throw reportMemberNotFound(name);
137: if (member instanceof FieldAndMethods) {
138: FieldAndMethods fam = (FieldAndMethods) ht.get(name);
139: member = fam.field;
140: }
141:
142: // Is this a bean property "set"?
143: if (member instanceof BeanProperty) {
144: BeanProperty bp = (BeanProperty) member;
145: if (bp.setter == null) {
146: throw reportMemberNotFound(name);
147: }
148: // If there's only one setter or if the value is null, use the
149: // main setter. Otherwise, let the NativeJavaMethod decide which
150: // setter to use:
151: if (bp.setters == null || value == null) {
152: Class setType = bp.setter.argTypes[0];
153: Object[] args = { Context.jsToJava(value, setType) };
154: try {
155: bp.setter.invoke(javaObject, args);
156: } catch (Exception ex) {
157: throw Context.throwAsScriptRuntimeEx(ex);
158: }
159: } else {
160: Object[] args = { value };
161: bp.setters.call(Context.getContext(), ScriptableObject
162: .getTopLevelScope(scope), scope, args);
163: }
164: } else {
165: if (!(member instanceof Field)) {
166: String str = (member == null) ? "msg.java.internal.private"
167: : "msg.java.method.assign";
168: throw Context.reportRuntimeError1(str, name);
169: }
170: Field field = (Field) member;
171: Object javaValue = Context.jsToJava(value, field.getType());
172: try {
173: field.set(javaObject, javaValue);
174: } catch (IllegalAccessException accessEx) {
175: throw new RuntimeException(
176: "unexpected IllegalAccessException "
177: + "accessing Java field");
178: } catch (IllegalArgumentException argEx) {
179: throw Context.reportRuntimeError3(
180: "msg.java.internal.field.type", value
181: .getClass().getName(), field,
182: javaObject.getClass().getName());
183: }
184: }
185: }
186:
187: Object[] getIds(boolean isStatic) {
188: Hashtable ht = isStatic ? staticMembers : members;
189: int len = ht.size();
190: Object[] result = new Object[len];
191: Enumeration keys = ht.keys();
192: for (int i = 0; i < len; i++)
193: result[i] = keys.nextElement();
194: return result;
195: }
196:
197: static String javaSignature(Class type) {
198: if (!type.isArray()) {
199: return type.getName();
200: } else {
201: int arrayDimension = 0;
202: do {
203: ++arrayDimension;
204: type = type.getComponentType();
205: } while (type.isArray());
206: String name = type.getName();
207: String suffix = "[]";
208: if (arrayDimension == 1) {
209: return name.concat(suffix);
210: } else {
211: int length = name.length() + arrayDimension
212: * suffix.length();
213: StringBuffer sb = new StringBuffer(length);
214: sb.append(name);
215: while (arrayDimension != 0) {
216: --arrayDimension;
217: sb.append(suffix);
218: }
219: return sb.toString();
220: }
221: }
222: }
223:
224: static String liveConnectSignature(Class[] argTypes) {
225: int N = argTypes.length;
226: if (N == 0) {
227: return "()";
228: }
229: StringBuffer sb = new StringBuffer();
230: sb.append('(');
231: for (int i = 0; i != N; ++i) {
232: if (i != 0) {
233: sb.append(',');
234: }
235: sb.append(javaSignature(argTypes[i]));
236: }
237: sb.append(')');
238: return sb.toString();
239: }
240:
241: private MemberBox findExplicitFunction(String name, boolean isStatic) {
242: int sigStart = name.indexOf('(');
243: if (sigStart < 0) {
244: return null;
245: }
246:
247: Hashtable ht = isStatic ? staticMembers : members;
248: MemberBox[] methodsOrCtors = null;
249: boolean isCtor = (isStatic && sigStart == 0);
250:
251: if (isCtor) {
252: // Explicit request for an overloaded constructor
253: methodsOrCtors = ctors;
254: } else {
255: // Explicit request for an overloaded method
256: String trueName = name.substring(0, sigStart);
257: Object obj = ht.get(trueName);
258: if (!isStatic && obj == null) {
259: // Try to get static member from instance (LC3)
260: obj = staticMembers.get(trueName);
261: }
262: if (obj instanceof NativeJavaMethod) {
263: NativeJavaMethod njm = (NativeJavaMethod) obj;
264: methodsOrCtors = njm.methods;
265: }
266: }
267:
268: if (methodsOrCtors != null) {
269: for (int i = 0; i < methodsOrCtors.length; i++) {
270: Class[] type = methodsOrCtors[i].argTypes;
271: String sig = liveConnectSignature(type);
272: if (sigStart + sig.length() == name.length()
273: && name.regionMatches(sigStart, sig, 0, sig
274: .length())) {
275: return methodsOrCtors[i];
276: }
277: }
278: }
279:
280: return null;
281: }
282:
283: private Object getExplicitFunction(Scriptable scope, String name,
284: Object javaObject, boolean isStatic) {
285: Hashtable ht = isStatic ? staticMembers : members;
286: Object member = null;
287: MemberBox methodOrCtor = findExplicitFunction(name, isStatic);
288:
289: if (methodOrCtor != null) {
290: Scriptable prototype = ScriptableObject
291: .getFunctionPrototype(scope);
292:
293: if (methodOrCtor.isCtor()) {
294: NativeJavaConstructor fun = new NativeJavaConstructor(
295: methodOrCtor);
296: fun.setPrototype(prototype);
297: member = fun;
298: ht.put(name, fun);
299: } else {
300: String trueName = methodOrCtor.getName();
301: member = ht.get(trueName);
302:
303: if (member instanceof NativeJavaMethod
304: && ((NativeJavaMethod) member).methods.length > 1) {
305: NativeJavaMethod fun = new NativeJavaMethod(
306: methodOrCtor, name);
307: fun.setPrototype(prototype);
308: ht.put(name, fun);
309: member = fun;
310: }
311: }
312: }
313:
314: return member;
315: }
316:
317: /**
318: * Retrieves mapping of methods to accessible methods for a class.
319: * In case the class is not public, retrieves methods with same
320: * signature as its public methods from public superclasses and
321: * interfaces (if they exist). Basically upcasts every method to the
322: * nearest accessible method.
323: */
324: private static Method[] discoverAccessibleMethods(Class clazz,
325: boolean includeProtected) {
326: Map map = new HashMap();
327: discoverAccessibleMethods(clazz, map, includeProtected);
328: return (Method[]) map.values().toArray(new Method[map.size()]);
329: }
330:
331: private static void discoverAccessibleMethods(Class clazz, Map map,
332: boolean includeProtected) {
333: if (Modifier.isPublic(clazz.getModifiers())) {
334: try {
335: if (includeProtected) {
336: while (clazz != null) {
337: Method[] methods = clazz.getDeclaredMethods();
338: for (int i = 0; i < methods.length; i++) {
339: Method method = methods[i];
340: int mods = method.getModifiers();
341: if (Modifier.isPublic(mods)
342: || Modifier.isProtected(mods)) {
343: MethodSignature sig = new MethodSignature(
344: method);
345: map.put(sig, method);
346: }
347: }
348: clazz = clazz.getSuperclass();
349: }
350: } else {
351: Method[] methods = clazz.getMethods();
352: for (int i = 0; i < methods.length; i++) {
353: Method method = methods[i];
354: MethodSignature sig = new MethodSignature(
355: method);
356: map.put(sig, method);
357: }
358: }
359: return;
360: } catch (SecurityException e) {
361: Context.reportWarning(
362: "Could not discover accessible methods of class "
363: + clazz.getName()
364: + " due to lack of privileges, "
365: + "attemping superclasses/interfaces."
366: // <netbeans>
367: , "discoverAccessibleMethods",
368: new Object[] { clazz }
369: // </netbeans>
370: );
371: // Fall through and attempt to discover superclass/interface
372: // methods
373: }
374: }
375:
376: Class[] interfaces = clazz.getInterfaces();
377: for (int i = 0; i < interfaces.length; i++) {
378: discoverAccessibleMethods(interfaces[i], map,
379: includeProtected);
380: }
381: Class super class = clazz.getSuperclass();
382: if (super class != null) {
383: discoverAccessibleMethods(super class, map, includeProtected);
384: }
385: }
386:
387: private static final class MethodSignature {
388: private final String name;
389: private final Class[] args;
390:
391: private MethodSignature(String name, Class[] args) {
392: this .name = name;
393: this .args = args;
394: }
395:
396: MethodSignature(Method method) {
397: this (method.getName(), method.getParameterTypes());
398: }
399:
400: public boolean equals(Object o) {
401: if (o instanceof MethodSignature) {
402: MethodSignature ms = (MethodSignature) o;
403: return ms.name.equals(name)
404: && Arrays.equals(args, ms.args);
405: }
406: return false;
407: }
408:
409: public int hashCode() {
410: return name.hashCode() ^ args.length;
411: }
412: }
413:
414: private void reflect(Scriptable scope, boolean includeProtected) {
415: // We reflect methods first, because we want overloaded field/method
416: // names to be allocated to the NativeJavaMethod before the field
417: // gets in the way.
418:
419: Method[] methods = discoverAccessibleMethods(cl,
420: includeProtected);
421: for (int i = 0; i < methods.length; i++) {
422: Method method = methods[i];
423: int mods = method.getModifiers();
424: boolean isStatic = Modifier.isStatic(mods);
425: Hashtable ht = isStatic ? staticMembers : members;
426: String name = method.getName();
427: Object value = ht.get(name);
428: if (value == null) {
429: ht.put(name, method);
430: } else {
431: ObjArray overloadedMethods;
432: if (value instanceof ObjArray) {
433: overloadedMethods = (ObjArray) value;
434: } else {
435: if (!(value instanceof Method))
436: Kit.codeBug();
437: // value should be instance of Method as at this stage
438: // staticMembers and members can only contain methods
439: overloadedMethods = new ObjArray();
440: overloadedMethods.add(value);
441: ht.put(name, overloadedMethods);
442: }
443: overloadedMethods.add(method);
444: }
445: }
446:
447: // replace Method instances by wrapped NativeJavaMethod objects
448: // first in staticMembers and then in members
449: for (int tableCursor = 0; tableCursor != 2; ++tableCursor) {
450: boolean isStatic = (tableCursor == 0);
451: Hashtable ht = (isStatic) ? staticMembers : members;
452: Enumeration e = ht.keys();
453: while (e.hasMoreElements()) {
454: String name = (String) e.nextElement();
455: MemberBox[] methodBoxes;
456: Object value = ht.get(name);
457: if (value instanceof Method) {
458: methodBoxes = new MemberBox[1];
459: methodBoxes[0] = new MemberBox((Method) value);
460: } else {
461: ObjArray overloadedMethods = (ObjArray) value;
462: int N = overloadedMethods.size();
463: if (N < 2)
464: Kit.codeBug();
465: methodBoxes = new MemberBox[N];
466: for (int i = 0; i != N; ++i) {
467: Method method = (Method) overloadedMethods
468: .get(i);
469: methodBoxes[i] = new MemberBox(method);
470: }
471: }
472: NativeJavaMethod fun = new NativeJavaMethod(methodBoxes);
473: if (scope != null) {
474: ScriptRuntime.setFunctionProtoAndParent(fun, scope);
475: }
476: ht.put(name, fun);
477: }
478: }
479:
480: // Reflect fields.
481: Field[] fields = cl.getFields();
482: for (int i = 0; i < fields.length; i++) {
483: Field field = fields[i];
484: int mods = field.getModifiers();
485: if (!Modifier.isPublic(mods)) {
486: continue;
487: }
488: boolean isStatic = Modifier.isStatic(mods);
489: Hashtable ht = isStatic ? staticMembers : members;
490: String name = field.getName();
491: Object member = ht.get(name);
492: if (member == null) {
493: ht.put(name, field);
494: } else if (member instanceof NativeJavaMethod) {
495: NativeJavaMethod method = (NativeJavaMethod) member;
496: FieldAndMethods fam = new FieldAndMethods(scope,
497: method.methods, field);
498: Hashtable fmht = isStatic ? staticFieldAndMethods
499: : fieldAndMethods;
500: if (fmht == null) {
501: fmht = new Hashtable(4);
502: if (isStatic) {
503: staticFieldAndMethods = fmht;
504: } else {
505: fieldAndMethods = fmht;
506: }
507: }
508: fmht.put(name, fam);
509: ht.put(name, fam);
510: } else if (member instanceof Field) {
511: Field oldField = (Field) member;
512: // If this newly reflected field shadows an inherited field,
513: // then replace it. Otherwise, since access to the field
514: // would be ambiguous from Java, no field should be reflected.
515: // For now, the first field found wins, unless another field
516: // explicitly shadows it.
517: if (oldField.getDeclaringClass().isAssignableFrom(
518: field.getDeclaringClass())) {
519: ht.put(name, field);
520: }
521: } else {
522: // "unknown member type"
523: Kit.codeBug();
524: }
525: }
526:
527: // Create bean propeties from corresponding get/set methods first for
528: // static members and then for instance members
529: for (int tableCursor = 0; tableCursor != 2; ++tableCursor) {
530: boolean isStatic = (tableCursor == 0);
531: Hashtable ht = (isStatic) ? staticMembers : members;
532:
533: Hashtable toAdd = new Hashtable();
534:
535: // Now, For each member, make "bean" properties.
536: for (Enumeration e = ht.keys(); e.hasMoreElements();) {
537:
538: // Is this a getter?
539: String name = (String) e.nextElement();
540: boolean memberIsGetMethod = name.startsWith("get");
541: boolean memberIsSetMethod = name.startsWith("set");
542: boolean memberIsIsMethod = name.startsWith("is");
543: if (memberIsGetMethod || memberIsIsMethod
544: || memberIsSetMethod) {
545: // Double check name component.
546: String nameComponent = name
547: .substring(memberIsIsMethod ? 2 : 3);
548: if (nameComponent.length() == 0)
549: continue;
550:
551: // Make the bean property name.
552: String beanPropertyName = nameComponent;
553: char ch0 = nameComponent.charAt(0);
554: if (Character.isUpperCase(ch0)) {
555: if (nameComponent.length() == 1) {
556: beanPropertyName = nameComponent
557: .toLowerCase();
558: } else {
559: char ch1 = nameComponent.charAt(1);
560: if (!Character.isUpperCase(ch1)) {
561: beanPropertyName = Character
562: .toLowerCase(ch0)
563: + nameComponent.substring(1);
564: }
565: }
566: }
567:
568: // If we already have a member by this name, don't do this
569: // property.
570: if (ht.containsKey(beanPropertyName)
571: || toAdd.containsKey(beanPropertyName)) {
572: continue;
573: }
574:
575: // Find the getter method, or if there is none, the is-
576: // method.
577: MemberBox getter = null;
578: getter = findGetter(isStatic, ht, "get",
579: nameComponent);
580: // If there was no valid getter, check for an is- method.
581: if (getter == null) {
582: getter = findGetter(isStatic, ht, "is",
583: nameComponent);
584: }
585:
586: // setter
587: MemberBox setter = null;
588: NativeJavaMethod setters = null;
589: String setterName = "set".concat(nameComponent);
590:
591: if (ht.containsKey(setterName)) {
592: // Is this value a method?
593: Object member = ht.get(setterName);
594: if (member instanceof NativeJavaMethod) {
595: NativeJavaMethod njmSet = (NativeJavaMethod) member;
596: if (getter != null) {
597: // We have a getter. Now, do we have a matching
598: // setter?
599: Class type = getter.method()
600: .getReturnType();
601: setter = extractSetMethod(type,
602: njmSet.methods, isStatic);
603: } else {
604: // No getter, find any set method
605: setter = extractSetMethod(
606: njmSet.methods, isStatic);
607: }
608: if (njmSet.methods.length > 1) {
609: setters = njmSet;
610: }
611: }
612: }
613: // Make the property.
614: BeanProperty bp = new BeanProperty(getter, setter,
615: setters);
616: toAdd.put(beanPropertyName, bp);
617: }
618: }
619:
620: // Add the new bean properties.
621: for (Enumeration e = toAdd.keys(); e.hasMoreElements();) {
622: Object key = e.nextElement();
623: Object value = toAdd.get(key);
624: ht.put(key, value);
625: }
626: }
627:
628: // Reflect constructors
629: Constructor[] constructors = cl.getConstructors();
630: ctors = new MemberBox[constructors.length];
631: for (int i = 0; i != constructors.length; ++i) {
632: ctors[i] = new MemberBox(constructors[i]);
633: }
634: }
635:
636: private MemberBox findGetter(boolean isStatic, Hashtable ht,
637: String prefix, String propertyName) {
638: String getterName = prefix.concat(propertyName);
639: if (ht.containsKey(getterName)) {
640: // Check that the getter is a method.
641: Object member = ht.get(getterName);
642: if (member instanceof NativeJavaMethod) {
643: NativeJavaMethod njmGet = (NativeJavaMethod) member;
644: return extractGetMethod(njmGet.methods, isStatic);
645: }
646: }
647: return null;
648: }
649:
650: private static MemberBox extractGetMethod(MemberBox[] methods,
651: boolean isStatic) {
652: // Inspect the list of all MemberBox for the only one having no
653: // parameters
654: for (int methodIdx = 0; methodIdx < methods.length; methodIdx++) {
655: MemberBox method = methods[methodIdx];
656: // Does getter method have an empty parameter list with a return
657: // value (eg. a getSomething() or isSomething())?
658: if (method.argTypes.length == 0
659: && (!isStatic || method.isStatic())) {
660: Class type = method.method().getReturnType();
661: if (type != Void.TYPE) {
662: return method;
663: }
664: break;
665: }
666: }
667: return null;
668: }
669:
670: private static MemberBox extractSetMethod(Class type,
671: MemberBox[] methods, boolean isStatic) {
672: //
673: // Note: it may be preferable to allow NativeJavaMethod.findFunction()
674: // to find the appropriate setter; unfortunately, it requires an
675: // instance of the target arg to determine that.
676: //
677:
678: // Make two passes: one to find a method with direct type assignment,
679: // and one to find a widening conversion.
680: for (int pass = 1; pass <= 2; ++pass) {
681: for (int i = 0; i < methods.length; ++i) {
682: MemberBox method = methods[i];
683: if (!isStatic || method.isStatic()) {
684: if (method.method().getReturnType() == Void.TYPE) {
685: Class[] params = method.argTypes;
686: if (params.length == 1) {
687: if (pass == 1) {
688: if (params[0] == type) {
689: return method;
690: }
691: } else {
692: if (pass != 2)
693: Kit.codeBug();
694: if (params[0].isAssignableFrom(type)) {
695: return method;
696: }
697: }
698: }
699: }
700: }
701: }
702: }
703: return null;
704: }
705:
706: private static MemberBox extractSetMethod(MemberBox[] methods,
707: boolean isStatic) {
708:
709: for (int i = 0; i < methods.length; ++i) {
710: MemberBox method = methods[i];
711: if (!isStatic || method.isStatic()) {
712: if (method.method().getReturnType() == Void.TYPE) {
713: if (method.argTypes.length == 1) {
714: return method;
715: }
716: }
717: }
718: }
719: return null;
720: }
721:
722: Hashtable getFieldAndMethodsObjects(Scriptable scope,
723: Object javaObject, boolean isStatic) {
724: Hashtable ht = isStatic ? staticFieldAndMethods
725: : fieldAndMethods;
726: if (ht == null)
727: return null;
728: int len = ht.size();
729: Hashtable result = new Hashtable(len);
730: Enumeration e = ht.elements();
731: while (len-- > 0) {
732: FieldAndMethods fam = (FieldAndMethods) e.nextElement();
733: FieldAndMethods famNew = new FieldAndMethods(scope,
734: fam.methods, fam.field);
735: famNew.javaObject = javaObject;
736: result.put(fam.field.getName(), famNew);
737: }
738: return result;
739: }
740:
741: static JavaMembers lookupClass(Scriptable scope, Class dynamicType,
742: Class staticType, boolean includeProtected) {
743: JavaMembers members;
744: ClassCache cache = ClassCache.get(scope);
745: Hashtable ct = cache.classTable;
746:
747: Class cl = dynamicType;
748: for (;;) {
749: members = (JavaMembers) ct.get(cl);
750: if (members != null) {
751: return members;
752: }
753: try {
754: members = new JavaMembers(cache.scope, cl,
755: includeProtected);
756: break;
757: } catch (SecurityException e) {
758: // Reflection may fail for objects that are in a restricted
759: // access package (e.g. sun.*). If we get a security
760: // exception, try again with the static type if it is interface.
761: // Otherwise, try superclass
762: if (staticType != null && staticType.isInterface()) {
763: cl = staticType;
764: staticType = null; // try staticType only once
765: } else {
766: Class parent = cl.getSuperclass();
767: if (parent == null) {
768: if (cl.isInterface()) {
769: // last resort after failed staticType interface
770: parent = ScriptRuntime.ObjectClass;
771: } else {
772: throw e;
773: }
774: }
775: cl = parent;
776: }
777: }
778: }
779:
780: if (cache.isCachingEnabled())
781: ct.put(cl, members);
782: return members;
783: }
784:
785: RuntimeException reportMemberNotFound(String memberName) {
786: return Context.reportRuntimeError2("msg.java.member.not.found",
787: cl.getName(), memberName);
788: }
789:
790: private Class cl;
791: private Hashtable members;
792: private Hashtable fieldAndMethods;
793: private Hashtable staticMembers;
794: private Hashtable staticFieldAndMethods;
795: MemberBox[] ctors;
796: }
797:
798: class BeanProperty {
799: BeanProperty(MemberBox getter, MemberBox setter,
800: NativeJavaMethod setters) {
801: this .getter = getter;
802: this .setter = setter;
803: this .setters = setters;
804: }
805:
806: MemberBox getter;
807: MemberBox setter;
808: NativeJavaMethod setters;
809: }
810:
811: class FieldAndMethods extends NativeJavaMethod {
812: static final long serialVersionUID = -9222428244284796755L;
813:
814: FieldAndMethods(Scriptable scope, MemberBox[] methods, Field field) {
815: super (methods);
816: this .field = field;
817: setParentScope(scope);
818: setPrototype(ScriptableObject.getFunctionPrototype(scope));
819: }
820:
821: public Object getDefaultValue(Class hint) {
822: if (hint == ScriptRuntime.FunctionClass)
823: return this ;
824: Object rval;
825: Class type;
826: try {
827: rval = field.get(javaObject);
828: type = field.getType();
829: } catch (IllegalAccessException accEx) {
830: throw Context.reportRuntimeError1(
831: "msg.java.internal.private", field.getName());
832: }
833: Context cx = Context.getContext();
834: rval = cx.getWrapFactory().wrap(cx, this , rval, type);
835: if (rval instanceof Scriptable) {
836: rval = ((Scriptable) rval).getDefaultValue(hint);
837: }
838: return rval;
839: }
840:
841: Field field;
842: Object javaObject;
843: }
|