Source Code Cross Referenced for Reflect.java in  » Scripting » beanshell » bsh » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » beanshell » bsh 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*****************************************************************************
002:         *                                                                           *
003:         *  This file is part of the BeanShell Java Scripting distribution.          *
004:         *  Documentation and updates may be found at http://www.beanshell.org/      *
005:         *                                                                           *
006:         *  Sun Public License Notice:                                               *
007:         *                                                                           *
008:         *  The contents of this file are subject to the Sun Public License Version  *
009:         *  1.0 (the "License"); you may not use this file except in compliance with *
010:         *  the License. A copy of the License is available at http://www.sun.com    * 
011:         *                                                                           *
012:         *  The Original Code is BeanShell. The Initial Developer of the Original    *
013:         *  Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright     *
014:         *  (C) 2000.  All Rights Reserved.                                          *
015:         *                                                                           *
016:         *  GNU Public License Notice:                                               *
017:         *                                                                           *
018:         *  Alternatively, the contents of this file may be used under the terms of  *
019:         *  the GNU Lesser General Public License (the "LGPL"), in which case the    *
020:         *  provisions of LGPL are applicable instead of those above. If you wish to *
021:         *  allow use of your version of this file only under the  terms of the LGPL *
022:         *  and not to allow others to use your version of this file under the SPL,  *
023:         *  indicate your decision by deleting the provisions above and replace      *
024:         *  them with the notice and other provisions required by the LGPL.  If you  *
025:         *  do not delete the provisions above, a recipient may use your version of  *
026:         *  this file under either the SPL or the LGPL.                              *
027:         *                                                                           *
028:         *  Patrick Niemeyer (pat@pat.net)                                           *
029:         *  Author of Learning Java, O'Reilly & Associates                           *
030:         *  http://www.pat.net/~pat/                                                 *
031:         *                                                                           *
032:         *****************************************************************************/package bsh;
033:
034:        import java.lang.reflect.*;
035:        import java.util.Vector;
036:
037:        /**
038:         * All of the reflection API code lies here.  It is in the form of static
039:         * utilities.  Maybe this belongs in LHS.java or a generic object
040:         * wrapper class.
041:         * 
042:         * @author Pat Niemeyer
043:         * @author Daniel Leuck
044:         */
045:        /*
046:         Note: This class is messy.  The method and field resolution need to be
047:         rewritten.  Various methods in here catch NoSuchMethod or NoSuchField
048:         exceptions during their searches.  These should be rewritten to avoid
049:         having to catch the exceptions.  Method lookups are now cached at a high 
050:         level so they are less important, however the logic is messy.
051:         */
052:        class Reflect {
053:            /**
054:            	Invoke method on arbitrary object instance.
055:            	invocation may be static (through the object instance) or dynamic.
056:            	Object may be a bsh scripted object (bsh.This type).
057:             	@return the result of the method call
058:             */
059:            public static Object invokeObjectMethod(Object object,
060:                    String methodName, Object[] args, Interpreter interpreter,
061:                    CallStack callstack, SimpleNode callerInfo)
062:                    throws ReflectError, EvalError, InvocationTargetException {
063:                // Bsh scripted object
064:                if (object instanceof  This
065:                        && !This.isExposedThisMethod(methodName))
066:                    return ((This) object).invokeMethod(methodName, args,
067:                            interpreter, callstack, callerInfo, false/*delcaredOnly*/
068:                    );
069:
070:                // Plain Java object, find the java method
071:                try {
072:                    BshClassManager bcm = interpreter == null ? null
073:                            : interpreter.getClassManager();
074:                    Class clas = object.getClass();
075:
076:                    Method method = resolveExpectedJavaMethod(bcm, clas,
077:                            object, methodName, args, false);
078:
079:                    return invokeMethod(method, object, args);
080:                } catch (UtilEvalError e) {
081:                    throw e.toEvalError(callerInfo, callstack);
082:                }
083:            }
084:
085:            /** 
086:            	Invoke a method known to be static.
087:            	No object instance is needed and there is no possibility of the 
088:            	method being a bsh scripted method.
089:             */
090:            public static Object invokeStaticMethod(BshClassManager bcm,
091:                    Class clas, String methodName, Object[] args)
092:                    throws ReflectError, UtilEvalError,
093:                    InvocationTargetException {
094:                Interpreter.debug("invoke static Method");
095:                Method method = resolveExpectedJavaMethod(bcm, clas, null,
096:                        methodName, args, true);
097:                return invokeMethod(method, null, args);
098:            }
099:
100:            /**
101:            	Invoke the Java method on the specified object, performing needed
102:             	type mappings on arguments and return values.
103:            	@param args may be null
104:             */
105:            static Object invokeMethod(Method method, Object object,
106:                    Object[] args) throws ReflectError,
107:                    InvocationTargetException {
108:                if (args == null)
109:                    args = new Object[0];
110:
111:                logInvokeMethod("Invoking method (entry): ", method, args);
112:
113:                // Map types to assignable forms, need to keep this fast...
114:                Object[] tmpArgs = new Object[args.length];
115:                Class[] types = method.getParameterTypes();
116:                try {
117:                    for (int i = 0; i < args.length; i++)
118:                        tmpArgs[i] = Types.castObject(args[i]/*rhs*/,
119:                                types[i]/*lhsType*/, Types.ASSIGNMENT);
120:                } catch (UtilEvalError e) {
121:                    throw new InterpreterError(
122:                            "illegal argument type in method invocation: " + e);
123:                }
124:
125:                // unwrap any primitives
126:                tmpArgs = Primitive.unwrap(tmpArgs);
127:
128:                logInvokeMethod("Invoking method (after massaging values): ",
129:                        method, tmpArgs);
130:
131:                try {
132:                    Object returnValue = method.invoke(object, tmpArgs);
133:                    if (returnValue == null)
134:                        returnValue = Primitive.NULL;
135:                    Class returnType = method.getReturnType();
136:
137:                    return Primitive.wrap(returnValue, returnType);
138:                } catch (IllegalAccessException e) {
139:                    throw new ReflectError("Cannot access method "
140:                            + StringUtil.methodString(method.getName(), method
141:                                    .getParameterTypes()) + " in '"
142:                            + method.getDeclaringClass() + "' :" + e);
143:                }
144:            }
145:
146:            public static Object getIndex(Object array, int index)
147:                    throws ReflectError, UtilTargetError {
148:                if (Interpreter.DEBUG)
149:                    Interpreter
150:                            .debug("getIndex: " + array + ", index=" + index);
151:                try {
152:                    Object val = Array.get(array, index);
153:                    return Primitive.wrap(val, array.getClass()
154:                            .getComponentType());
155:                } catch (ArrayIndexOutOfBoundsException e1) {
156:                    throw new UtilTargetError(e1);
157:                } catch (Exception e) {
158:                    throw new ReflectError("Array access:" + e);
159:                }
160:            }
161:
162:            public static void setIndex(Object array, int index, Object val)
163:                    throws ReflectError, UtilTargetError {
164:                try {
165:                    val = Primitive.unwrap(val);
166:                    Array.set(array, index, val);
167:                } catch (ArrayStoreException e2) {
168:                    throw new UtilTargetError(e2);
169:                } catch (IllegalArgumentException e1) {
170:                    throw new UtilTargetError(new ArrayStoreException(e1
171:                            .toString()));
172:                } catch (Exception e) {
173:                    throw new ReflectError("Array access:" + e);
174:                }
175:            }
176:
177:            public static Object getStaticFieldValue(Class clas,
178:                    String fieldName) throws UtilEvalError, ReflectError {
179:                return getFieldValue(clas, null, fieldName, true/*onlystatic*/);
180:            }
181:
182:            /**
183:             * Check for a field with the given name in a java object or scripted object
184:             * if the field exists fetch the value, if not check for a property value.
185:             * If neither is found return Primitive.VOID. 
186:             */
187:            public static Object getObjectFieldValue(Object object,
188:                    String fieldName) throws UtilEvalError, ReflectError {
189:                if (object instanceof  This) {
190:                    This t = (This) object;
191:                    return t.namespace.getVariableOrProperty(fieldName, null);
192:                } else {
193:                    try {
194:                        return getFieldValue(object.getClass(), object,
195:                                fieldName, false/*onlystatic*/);
196:                    } catch (ReflectError e) {
197:                        // no field, try property acces
198:
199:                        if (hasObjectPropertyGetter(object.getClass(),
200:                                fieldName))
201:                            return getObjectProperty(object, fieldName);
202:                        else
203:                            throw e;
204:                    }
205:                }
206:            }
207:
208:            static LHS getLHSStaticField(Class clas, String fieldName)
209:                    throws UtilEvalError, ReflectError {
210:                Field f = resolveExpectedJavaField(clas, fieldName, true/*onlystatic*/);
211:                return new LHS(f);
212:            }
213:
214:            /**
215:            	Get an LHS reference to an object field.
216:
217:            	This method also deals with the field style property access.
218:            	In the field does not exist we check for a property setter.
219:             */
220:            static LHS getLHSObjectField(Object object, String fieldName)
221:                    throws UtilEvalError, ReflectError {
222:                if (object instanceof  This) {
223:                    // I guess this is when we pass it as an argument?
224:                    // Setting locally
225:                    boolean recurse = false;
226:                    return new LHS(((This) object).namespace, fieldName,
227:                            recurse);
228:                }
229:
230:                try {
231:                    Field f = resolveExpectedJavaField(object.getClass(),
232:                            fieldName, false/*staticOnly*/);
233:                    return new LHS(object, f);
234:                } catch (ReflectError e) {
235:                    // not a field, try property access
236:                    if (hasObjectPropertySetter(object.getClass(), fieldName))
237:                        return new LHS(object, fieldName);
238:                    else
239:                        throw e;
240:                }
241:            }
242:
243:            private static Object getFieldValue(Class clas, Object object,
244:                    String fieldName, boolean staticOnly) throws UtilEvalError,
245:                    ReflectError {
246:                try {
247:                    Field f = resolveExpectedJavaField(clas, fieldName,
248:                            staticOnly);
249:
250:                    Object value = f.get(object);
251:                    Class returnType = f.getType();
252:                    return Primitive.wrap(value, returnType);
253:
254:                } catch (NullPointerException e) { // shouldn't happen
255:                    throw new ReflectError("???" + fieldName
256:                            + " is not a static field.");
257:                } catch (IllegalAccessException e) {
258:                    throw new ReflectError("Can't access field: " + fieldName);
259:                }
260:            }
261:
262:            /*
263:            	Note: this method and resolveExpectedJavaField should be rewritten
264:            	to invert this logic so that no exceptions need to be caught
265:            	unecessarily.  This is just a temporary impl.
266:            	@return the field or null if not found
267:             */
268:            protected static Field resolveJavaField(Class clas,
269:                    String fieldName, boolean staticOnly) throws UtilEvalError {
270:                try {
271:                    return resolveExpectedJavaField(clas, fieldName, staticOnly);
272:                } catch (ReflectError e) {
273:                    return null;
274:                }
275:            }
276:
277:            /**
278:            	@throws ReflectError if the field is not found.
279:             */
280:            /*
281:            	Note: this should really just throw NoSuchFieldException... need
282:            	to change related signatures and code.
283:             */
284:            protected static Field resolveExpectedJavaField(Class clas,
285:                    String fieldName, boolean staticOnly) throws UtilEvalError,
286:                    ReflectError {
287:                Field field;
288:                try {
289:                    if (Capabilities.haveAccessibility())
290:                        field = findAccessibleField(clas, fieldName);
291:                    else
292:                        // Class getField() finds only public (and in interfaces, etc.)
293:                        field = clas.getField(fieldName);
294:                } catch (NoSuchFieldException e) {
295:                    throw new ReflectError("No such field: " + fieldName);
296:                } catch (SecurityException e) {
297:                    throw new UtilTargetError(
298:                            "Security Exception while searching fields of: "
299:                                    + clas, e);
300:                }
301:
302:                if (staticOnly && !Modifier.isStatic(field.getModifiers()))
303:                    throw new UtilEvalError("Can't reach instance field: "
304:                            + fieldName + " from static context: "
305:                            + clas.getName());
306:
307:                return field;
308:            }
309:
310:            /**
311:            	Used when accessibility capability is available to locate an occurrance
312:            	of the field in the most derived class or superclass and set its 
313:            	accessibility flag.
314:            	Note that this method is not needed in the simple non accessible
315:            	case because we don't have to hunt for fields.
316:            	Note that classes may declare overlapping private fields, so the 
317:            	distinction about the most derived is important.  Java doesn't normally
318:            	allow this kind of access (super won't show private variables) so 
319:            	there is no real syntax for specifying which class scope to use...
320:
321:            	@return the Field or throws NoSuchFieldException
322:            	@throws NoSuchFieldException if the field is not found
323:             */
324:            /*
325:            	This method should be rewritten to use getFields() and avoid catching
326:            	exceptions during the search.
327:             */
328:            private static Field findAccessibleField(Class clas,
329:                    String fieldName) throws UtilEvalError,
330:                    NoSuchFieldException {
331:                Field field;
332:
333:                // Quick check catches public fields include those in interfaces
334:                try {
335:                    field = clas.getField(fieldName);
336:                    ReflectManager.RMSetAccessible(field);
337:                    return field;
338:                } catch (NoSuchFieldException e) {
339:                }
340:
341:                // Now, on with the hunt...
342:                while (clas != null) {
343:                    try {
344:                        field = clas.getDeclaredField(fieldName);
345:                        ReflectManager.RMSetAccessible(field);
346:                        return field;
347:
348:                        // Not found, fall through to next class
349:
350:                    } catch (NoSuchFieldException e) {
351:                    }
352:
353:                    clas = clas.getSuperclass();
354:                }
355:                throw new NoSuchFieldException(fieldName);
356:            }
357:
358:            /**
359:            	This method wraps resolveJavaMethod() and expects a non-null method
360:             	result. If the method is not found it throws a descriptive ReflectError.
361:             */
362:            protected static Method resolveExpectedJavaMethod(
363:                    BshClassManager bcm, Class clas, Object object,
364:                    String name, Object[] args, boolean staticOnly)
365:                    throws ReflectError, UtilEvalError {
366:                if (object == Primitive.NULL)
367:                    throw new UtilTargetError(new NullPointerException(
368:                            "Attempt to invoke method " + name
369:                                    + " on null value"));
370:
371:                Class[] types = Types.getTypes(args);
372:                Method method = resolveJavaMethod(bcm, clas, name, types,
373:                        staticOnly);
374:
375:                if (method == null)
376:                    throw new ReflectError((staticOnly ? "Static method "
377:                            : "Method ")
378:                            + StringUtil.methodString(name, types)
379:                            + " not found in class'" + clas.getName() + "'");
380:
381:                return method;
382:            }
383:
384:            /**
385:                The full blown resolver method.  All other method invocation methods
386:            	delegate to this.  The method may be static or dynamic unless
387:            	staticOnly is set (in which case object may be null).
388:            	If staticOnly is set then only static methods will be located.
389:            	<p/>
390:
391:            	This method performs caching (caches discovered methods through the
392:             	class manager and utilizes cached methods.)
393:             	<p/>
394:
395:             	This method determines whether to attempt to use non-public methods
396:             	based on Capabilities.haveAccessibility() and will set the accessibilty
397:             	flag on the method as necessary.
398:             	<p/>
399:
400:            	If, when directed to find a static method, this method locates a more 
401:            	specific matching instance method it will throw a descriptive exception 
402:            	analogous to the error that the Java compiler would produce.
403:            	Note: as of 2.0.x this is a problem because there is no way to work
404:            	around this with a cast. 
405:            	<p/>
406:
407:            	@param staticOnly
408:            		The method located must be static, the object param may be null.
409:            	@return the method or null if no matching method was found.
410:             */
411:            protected static Method resolveJavaMethod(BshClassManager bcm,
412:                    Class clas, String name, Class[] types, boolean staticOnly)
413:                    throws UtilEvalError {
414:                if (clas == null)
415:                    throw new InterpreterError("null class");
416:
417:                // Lookup previously cached method
418:                Method method = null;
419:                if (bcm == null)
420:                    Interpreter.debug("resolveJavaMethod UNOPTIMIZED lookup");
421:                else
422:                    method = bcm.getResolvedMethod(clas, name, types,
423:                            staticOnly);
424:
425:                if (method == null) {
426:                    boolean publicOnly = !Capabilities.haveAccessibility();
427:                    // Searching for the method may, itself be a priviledged action
428:                    try {
429:                        method = findOverloadedMethod(clas, name, types,
430:                                publicOnly);
431:                    } catch (SecurityException e) {
432:                        throw new UtilTargetError(
433:                                "Security Exception while searching methods of: "
434:                                        + clas, e);
435:                    }
436:
437:                    checkFoundStaticMethod(method, staticOnly, clas);
438:
439:                    // This is the first time we've seen this method, set accessibility
440:                    // Note: even if it's a public method, we may have found it in a
441:                    // non-public class
442:                    if (method != null && !publicOnly) {
443:                        try {
444:                            ReflectManager.RMSetAccessible(method);
445:                        } catch (UtilEvalError e) { /*ignore*/
446:                        }
447:                    }
448:
449:                    // If succeeded cache the resolved method.
450:                    if (method != null && bcm != null)
451:                        bcm.cacheResolvedMethod(clas, types, method);
452:                }
453:
454:                return method;
455:            }
456:
457:            /**
458:            	Get the candidate methods by searching the class and interface graph
459:             	of baseClass and resolve the most specific.
460:             	@return the method or null for not found
461:             */
462:            private static Method findOverloadedMethod(Class baseClass,
463:                    String methodName, Class[] types, boolean publicOnly) {
464:                if (Interpreter.DEBUG)
465:                    Interpreter.debug("Searching for method: "
466:                            + StringUtil.methodString(methodName, types)
467:                            + " in '" + baseClass.getName() + "'");
468:
469:                Method[] methods = getCandidateMethods(baseClass, methodName,
470:                        types.length, publicOnly);
471:
472:                if (Interpreter.DEBUG)
473:                    Interpreter.debug("Looking for most specific method: "
474:                            + methodName);
475:                Method method = findMostSpecificMethod(types, methods);
476:
477:                return method;
478:            }
479:
480:            /**
481:            	Climb the class and interface inheritence graph of the type and collect
482:            	all methods matching the specified name and criterion.  If publicOnly
483:            	is true then only public methods in *public* classes or interfaces will
484:            	be returned.  In the normal (non-accessible) case this addresses the
485:            	problem that arises when a package private class or private inner class
486:            	implements a public interface or derives from a public type.
487:             	<p/>
488:
489:             	This method primarily just delegates to gatherMethodsRecursive()
490:             	@see #gatherMethodsRecursive(
491:            		Class, String, int, boolean, java.util.Vector)
492:             */
493:            static Method[] getCandidateMethods(Class baseClass,
494:                    String methodName, int numArgs, boolean publicOnly) {
495:                Vector candidates = gatherMethodsRecursive(baseClass,
496:                        methodName, numArgs, publicOnly, null/*candidates*/);
497:
498:                // return the methods in an array
499:                Method[] ma = new Method[candidates.size()];
500:                candidates.copyInto(ma);
501:                return ma;
502:            }
503:
504:            /**
505:            	Accumulate all methods, optionally including non-public methods,
506:             	class and interface, in the inheritence tree of baseClass.
507:
508:            	This method is analogous to Class getMethods() which returns all public
509:            	methods in the inheritence tree.
510:
511:            	In the normal (non-accessible) case this also addresses the problem
512:            	that arises when a package private class or private inner class
513:            	implements a public interface or derives from a public type.  In other
514:            	words, sometimes we'll find public methods that we can't use directly
515:            	and we have to find the same public method in a parent class or
516:            	interface.
517:
518:            	@return the candidate methods vector
519:             */
520:            private static Vector gatherMethodsRecursive(Class baseClass,
521:                    String methodName, int numArgs, boolean publicOnly,
522:                    Vector candidates) {
523:                if (candidates == null)
524:                    candidates = new Vector();
525:
526:                // Add methods of the current class to the vector.
527:                // In public case be careful to only add methods from a public class
528:                // and to use getMethods() instead of getDeclaredMethods()
529:                // (This addresses secure environments)
530:                if (publicOnly) {
531:                    if (isPublic(baseClass))
532:                        addCandidates(baseClass.getMethods(), methodName,
533:                                numArgs, publicOnly, candidates);
534:                } else
535:                    addCandidates(baseClass.getDeclaredMethods(), methodName,
536:                            numArgs, publicOnly, candidates);
537:
538:                // Does the class or interface implement interfaces?
539:                Class[] intfs = baseClass.getInterfaces();
540:                for (int i = 0; i < intfs.length; i++)
541:                    gatherMethodsRecursive(intfs[i], methodName, numArgs,
542:                            publicOnly, candidates);
543:
544:                // Do we have a superclass? (interfaces don't, etc.)
545:                Class super class = baseClass.getSuperclass();
546:                if (super class != null)
547:                    gatherMethodsRecursive(super class, methodName, numArgs,
548:                            publicOnly, candidates);
549:
550:                return candidates;
551:            }
552:
553:            private static Vector addCandidates(Method[] methods,
554:                    String methodName, int numArgs, boolean publicOnly,
555:                    Vector candidates) {
556:                for (int i = 0; i < methods.length; i++) {
557:                    Method m = methods[i];
558:                    if (m.getName().equals(methodName)
559:                            && (m.getParameterTypes().length == numArgs)
560:                            && (!publicOnly || isPublic(m)))
561:                        candidates.add(m);
562:                }
563:                return candidates;
564:            }
565:
566:            /**
567:            	Primary object constructor
568:            	This method is simpler than those that must resolve general method
569:            	invocation because constructors are not inherited.
570:             <p/>
571:             This method determines whether to attempt to use non-public constructors
572:             based on Capabilities.haveAccessibility() and will set the accessibilty
573:             flag on the method as necessary.
574:             <p/>
575:             */
576:            static Object constructObject(Class clas, Object[] args)
577:                    throws ReflectError, InvocationTargetException {
578:                if (clas.isInterface())
579:                    throw new ReflectError(
580:                            "Can't create instance of an interface: " + clas);
581:
582:                Object obj = null;
583:                Class[] types = Types.getTypes(args);
584:                Constructor con = null;
585:
586:                // Find the constructor.
587:                // (there are no inherited constructors to worry about)
588:                Constructor[] constructors = Capabilities.haveAccessibility() ? clas
589:                        .getDeclaredConstructors()
590:                        : clas.getConstructors();
591:
592:                if (Interpreter.DEBUG)
593:                    Interpreter.debug("Looking for most specific constructor: "
594:                            + clas);
595:                con = findMostSpecificConstructor(types, constructors);
596:                if (con == null)
597:                    throw cantFindConstructor(clas, types);
598:
599:                if (!isPublic(con))
600:                    try {
601:                        ReflectManager.RMSetAccessible(con);
602:                    } catch (UtilEvalError e) { /*ignore*/
603:                    }
604:
605:                args = Primitive.unwrap(args);
606:                try {
607:                    obj = con.newInstance(args);
608:                } catch (InstantiationException e) {
609:                    throw new ReflectError("The class " + clas
610:                            + " is abstract ");
611:                } catch (IllegalAccessException e) {
612:                    throw new ReflectError(
613:                            "We don't have permission to create an instance."
614:                                    + "Use setAccessibility(true) to enable access.");
615:                } catch (IllegalArgumentException e) {
616:                    throw new ReflectError("The number of arguments was wrong");
617:                }
618:                if (obj == null)
619:                    throw new ReflectError("Couldn't construct the object");
620:
621:                return obj;
622:            }
623:
624:            /*
625:                This method should parallel findMostSpecificMethod()
626:            	The only reason it can't be combined is that Method and Constructor
627:            	don't have a common interface for their signatures
628:             */
629:            static Constructor findMostSpecificConstructor(Class[] idealMatch,
630:                    Constructor[] constructors) {
631:                int match = findMostSpecificConstructorIndex(idealMatch,
632:                        constructors);
633:                return (match == -1) ? null : constructors[match];
634:            }
635:
636:            static int findMostSpecificConstructorIndex(Class[] idealMatch,
637:                    Constructor[] constructors) {
638:                Class[][] candidates = new Class[constructors.length][];
639:                for (int i = 0; i < candidates.length; i++)
640:                    candidates[i] = constructors[i].getParameterTypes();
641:
642:                return findMostSpecificSignature(idealMatch, candidates);
643:            }
644:
645:            /**
646:            	Find the best match for signature idealMatch.
647:            	It is assumed that the methods array holds only valid candidates
648:            	(e.g. method name and number of args already matched).
649:            	This method currently does not take into account Java 5 covariant
650:            	return types... which I think will require that we find the most
651:            	derived return type of otherwise identical best matches.
652:
653:             	@see #findMostSpecificSignature(Class[], Class[][])
654:            	@param methods the set of candidate method which differ only in the
655:             		types of their arguments.
656:             */
657:            static Method findMostSpecificMethod(Class[] idealMatch,
658:                    Method[] methods) {
659:                // copy signatures into array for findMostSpecificMethod()
660:                Class[][] candidateSigs = new Class[methods.length][];
661:                for (int i = 0; i < methods.length; i++)
662:                    candidateSigs[i] = methods[i].getParameterTypes();
663:
664:                int match = findMostSpecificSignature(idealMatch, candidateSigs);
665:                return match == -1 ? null : methods[match];
666:            }
667:
668:            /**
669:                Implement JLS 15.11.2
670:            	Return the index of the most specific arguments match or -1 if no
671:            	match is found.
672:            	This method is used by both methods and constructors (which
673:             	unfortunately don't share a common interface for signature info).
674:
675:             @return the index of the most specific candidate
676:
677:             */
678:            /*
679:             Note: Two methods which are equally specific should not be allowed by
680:             the Java compiler.  In this case BeanShell currently chooses the first
681:             one it finds.  We could add a test for this case here (I believe) by
682:             adding another isSignatureAssignable() in the other direction between
683:             the target and "best" match.  If the assignment works both ways then
684:             neither is more specific and they are ambiguous.  I'll leave this test
685:             out for now because I'm not sure how much another test would impact
686:             performance.  Method selection is now cached at a high level, so a few
687:             friendly extraneous tests shouldn't be a problem.
688:             */
689:            static int findMostSpecificSignature(Class[] idealMatch,
690:                    Class[][] candidates) {
691:                for (int round = Types.FIRST_ROUND_ASSIGNABLE; round <= Types.LAST_ROUND_ASSIGNABLE; round++) {
692:                    Class[] bestMatch = null;
693:                    int bestMatchIndex = -1;
694:
695:                    for (int i = 0; i < candidates.length; i++) {
696:                        Class[] targetMatch = candidates[i];
697:
698:                        // If idealMatch fits targetMatch and this is the first match
699:                        // or targetMatch is more specific than the best match, make it
700:                        // the new best match.
701:                        if (Types.isSignatureAssignable(idealMatch,
702:                                targetMatch, round)
703:                                && ((bestMatch == null) || (Types
704:                                        .isSignatureAssignable(targetMatch,
705:                                                bestMatch,
706:                                                Types.JAVA_BASE_ASSIGNABLE) && !Types
707:                                        .areSignaturesEqual(targetMatch,
708:                                                bestMatch)))) {
709:                            bestMatch = targetMatch;
710:                            bestMatchIndex = i;
711:                        }
712:                    }
713:
714:                    if (bestMatch != null)
715:                        return bestMatchIndex;
716:                }
717:
718:                return -1;
719:            }
720:
721:            static String accessorName(String getorset, String propName) {
722:                return getorset
723:                        + String.valueOf(Character.toUpperCase(propName
724:                                .charAt(0))) + propName.substring(1);
725:            }
726:
727:            public static boolean hasObjectPropertyGetter(Class clas,
728:                    String propName) {
729:                String getterName = accessorName("get", propName);
730:                try {
731:                    clas.getMethod(getterName, new Class[0]);
732:                    return true;
733:                } catch (NoSuchMethodException e) { /* fall through */
734:                }
735:                getterName = accessorName("is", propName);
736:                try {
737:                    Method m = clas.getMethod(getterName, new Class[0]);
738:                    return (m.getReturnType() == Boolean.TYPE);
739:                } catch (NoSuchMethodException e) {
740:                    return false;
741:                }
742:            }
743:
744:            public static boolean hasObjectPropertySetter(Class clas,
745:                    String propName) {
746:                String setterName = accessorName("set", propName);
747:                Method[] methods = clas.getMethods();
748:
749:                // we don't know the right hand side of the assignment yet.
750:                // has at least one setter of the right name?
751:                for (int i = 0; i < methods.length; i++)
752:                    if (methods[i].getName().equals(setterName))
753:                        return true;
754:                return false;
755:            }
756:
757:            public static Object getObjectProperty(Object obj, String propName)
758:                    throws UtilEvalError, ReflectError {
759:                Object[] args = new Object[] {};
760:
761:                Interpreter.debug("property access: ");
762:                Method method = null;
763:
764:                Exception e1 = null, e2 = null;
765:                try {
766:                    String accessorName = accessorName("get", propName);
767:                    method = resolveExpectedJavaMethod(null/*bcm*/, obj
768:                            .getClass(), obj, accessorName, args, false);
769:                } catch (Exception e) {
770:                    e1 = e;
771:                }
772:                if (method == null)
773:                    try {
774:                        String accessorName = accessorName("is", propName);
775:                        method = resolveExpectedJavaMethod(null/*bcm*/, obj
776:                                .getClass(), obj, accessorName, args, false);
777:                        if (method.getReturnType() != Boolean.TYPE)
778:                            method = null;
779:                    } catch (Exception e) {
780:                        e2 = e;
781:                    }
782:                if (method == null)
783:                    throw new ReflectError("Error in property getter: " + e1
784:                            + (e2 != null ? " : " + e2 : ""));
785:
786:                try {
787:                    return invokeMethod(method, obj, args);
788:                } catch (InvocationTargetException e) {
789:                    throw new UtilEvalError(
790:                            "Property accessor threw exception: "
791:                                    + e.getTargetException());
792:                }
793:            }
794:
795:            public static void setObjectProperty(Object obj, String propName,
796:                    Object value) throws ReflectError, UtilEvalError {
797:                String accessorName = accessorName("set", propName);
798:                Object[] args = new Object[] { value };
799:
800:                Interpreter.debug("property access: ");
801:                try {
802:                    Method method = resolveExpectedJavaMethod(null/*bcm*/, obj
803:                            .getClass(), obj, accessorName, args, false);
804:                    invokeMethod(method, obj, args);
805:                } catch (InvocationTargetException e) {
806:                    throw new UtilEvalError(
807:                            "Property accessor threw exception: "
808:                                    + e.getTargetException());
809:                }
810:            }
811:
812:            /**
813:            	Return a more human readable version of the type name.
814:            	Specifically, array types are returned with postfix "[]" dimensions.
815:            	e.g. return "int []" for integer array instead of "class [I" as
816:            	would be returned by Class getName() in that case.
817:             */
818:            public static String normalizeClassName(Class type) {
819:                if (!type.isArray())
820:                    return type.getName();
821:
822:                StringBuffer className = new StringBuffer();
823:                try {
824:                    className.append(getArrayBaseType(type).getName() + " ");
825:                    for (int i = 0; i < getArrayDimensions(type); i++)
826:                        className.append("[]");
827:                } catch (ReflectError e) { /*shouldn't happen*/
828:                }
829:
830:                return className.toString();
831:            }
832:
833:            /**
834:            	returns the dimensionality of the Class
835:            	returns 0 if the Class is not an array class
836:             */
837:            public static int getArrayDimensions(Class arrayClass) {
838:                if (!arrayClass.isArray())
839:                    return 0;
840:
841:                return arrayClass.getName().lastIndexOf('[') + 1; // why so cute?
842:            }
843:
844:            /**
845:
846:            	Returns the base type of an array Class.
847:            	throws ReflectError if the Class is not an array class.
848:             */
849:            public static Class getArrayBaseType(Class arrayClass)
850:                    throws ReflectError {
851:                if (!arrayClass.isArray())
852:                    throw new ReflectError("The class is not an array.");
853:
854:                return arrayClass.getComponentType();
855:
856:            }
857:
858:            /**
859:            	A command may be implemented as a compiled Java class containing one or
860:            	more static invoke() methods of the correct signature.  The invoke()
861:            	methods must accept two additional leading arguments of the interpreter
862:            	and callstack, respectively. e.g. invoke(interpreter, callstack, ... )
863:            	This method adds the arguments and invokes the static method, returning
864:            	the result.
865:             */
866:            public static Object invokeCompiledCommand(Class commandClass,
867:                    Object[] args, Interpreter interpreter, CallStack callstack)
868:                    throws UtilEvalError {
869:                // add interpereter and namespace to args list
870:                Object[] invokeArgs = new Object[args.length + 2];
871:                invokeArgs[0] = interpreter;
872:                invokeArgs[1] = callstack;
873:                System.arraycopy(args, 0, invokeArgs, 2, args.length);
874:                BshClassManager bcm = interpreter.getClassManager();
875:                try {
876:                    return Reflect.invokeStaticMethod(bcm, commandClass,
877:                            "invoke", invokeArgs);
878:                } catch (InvocationTargetException e) {
879:                    throw new UtilEvalError("Error in compiled command: "
880:                            + e.getTargetException());
881:                } catch (ReflectError e) {
882:                    throw new UtilEvalError("Error invoking compiled command: "
883:                            + e);
884:                }
885:            }
886:
887:            private static void logInvokeMethod(String msg, Method method,
888:                    Object[] args) {
889:                if (Interpreter.DEBUG) {
890:                    Interpreter.debug(msg + method + " with args:");
891:                    for (int i = 0; i < args.length; i++)
892:                        Interpreter.debug("args[" + i + "] = " + args[i]
893:                                + " type = " + args[i].getClass());
894:                }
895:            }
896:
897:            private static void checkFoundStaticMethod(Method method,
898:                    boolean staticOnly, Class clas) throws UtilEvalError {
899:                // We're looking for a static method but found an instance method
900:                if (method != null && staticOnly && !isStatic(method))
901:                    throw new UtilEvalError("Cannot reach instance method: "
902:                            + StringUtil.methodString(method.getName(), method
903:                                    .getParameterTypes())
904:                            + " from static context: " + clas.getName());
905:            }
906:
907:            private static ReflectError cantFindConstructor(Class clas,
908:                    Class[] types) {
909:                if (types.length == 0)
910:                    return new ReflectError(
911:                            "Can't find default constructor for: " + clas);
912:                else
913:                    return new ReflectError("Can't find constructor: "
914:                            + StringUtil.methodString(clas.getName(), types)
915:                            + " in class: " + clas.getName());
916:            }
917:
918:            private static boolean isPublic(Class c) {
919:                return Modifier.isPublic(c.getModifiers());
920:            }
921:
922:            private static boolean isPublic(Method m) {
923:                return Modifier.isPublic(m.getModifiers());
924:            }
925:
926:            private static boolean isPublic(Constructor c) {
927:                return Modifier.isPublic(c.getModifiers());
928:            }
929:
930:            private static boolean isStatic(Method m) {
931:                return Modifier.isStatic(m.getModifiers());
932:            }
933:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.