Source Code Cross Referenced for MethodUtils.java in  » Scripting » bsf-2.4.0 » org » apache » bsf » util » 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 » bsf 2.4.0 » org.apache.bsf.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2004,2004 The Apache Software Foundation.
003:         * 
004:         * Licensed under the Apache License, Version 2.0 (the "License");
005:         * you may not use this file except in compliance with the License.
006:         * You may obtain a copy of the License at
007:         * 
008:         *      http://www.apache.org/licenses/LICENSE-2.0
009:         * 
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS,
012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         * See the License for the specific language governing permissions and
014:         * limitations under the License.
015:         */
016:
017:        package org.apache.bsf.util;
018:
019:        import java.lang.reflect.Constructor;
020:        import java.lang.reflect.Method;
021:        import java.lang.reflect.Modifier;
022:        import java.util.Enumeration;
023:        import java.util.Vector;
024:
025:        /**
026:         * This file is a collection of reflection utilities for dealing with
027:         * methods and constructors.
028:         * 
029:         * @author   Sanjiva Weerawarana
030:         * @author   Joseph Kesselman
031:         */
032:        public class MethodUtils {
033:
034:            /** Internal Class for getEntryPoint(). Implements 15.11.2.2 MORE
035:            SPECIFIC rules.
036:
037:            Retains a list of methods (already known to match the
038:            arguments). As each method is added, we check against past entries
039:            to determine which if any is "more specific" -- defined as having
040:            _all_ its arguments (not just a preponderance) be
041:            method-convertable into those of another. If such a relationship
042:            is found, the more-specific method is retained and the
043:            less-specific method is discarded. At the end, if this has yielded
044:            a single winner it is considered the Most Specific Method and
045:            hence the one that should be invoked.  Otherwise, a
046:            NoSuchMethodException is thrown.
047:            
048:            PERFORMANCE VERSUS ARCHITECTURE: Arguably, this should "have-a"
049:            Vector. But the code is 6% smaller, and possibly faster, if we
050:            code it as "is-a" Vector. Since it's an inner class, nobody's
051:            likely to abuse the privilage.
052:            
053:            Note: "Static" in the case of an inner class means "Does not
054:            reference instance data in the outer class", and is required since
055:            our caller is a static method. */
056:            private static class MoreSpecific extends Vector {
057:                /** Submit an entry-point to the list. May be discarded if a past
058:                  entry is more specific, or may cause others to be discarded it
059:                  if is more specific.
060:
061:                  newEntry: Method or Constructor under consideration.
062:                 */
063:                void addItem(Object newEntry) {
064:                    if (size() == 0)
065:                        addElement(newEntry);
066:                    else {
067:                        Class[] newargs = entryGetParameterTypes(newEntry);
068:                        boolean keep = true;
069:                        for (Enumeration e = elements(); keep
070:                                & e.hasMoreElements();) {
071:                            Object oldEntry = e.nextElement();
072:                            // CAVEAT: Implicit references to enclosing class!
073:                            Class[] oldargs = entryGetParameterTypes(oldEntry);
074:                            if (areMethodConvertable(oldargs, newargs))
075:                                removeElement(oldEntry); // New more specific; discard old
076:                            else if (areMethodConvertable(newargs, oldargs))
077:                                keep = false; // Old more specific; discard new
078:                            // Else they're tied. Keep both and hope someone beats both.
079:                        }
080:                        if (keep)
081:                            addElement(newEntry);
082:                    }
083:                }
084:
085:                /** Obtain the single Most Specific entry-point. If there is no clear
086:                  winner, or if the list is empty, throw NoSuchMethodException.
087:
088:                  Arguments describe the call we were hoping to resolve. They are
089:                  used to throw a nice verbose exception if something goes wrong.
090:                 */
091:                Object getMostSpecific(Class targetClass, String methodName,
092:                        Class[] argTypes, boolean isStaticReference)
093:                        throws NoSuchMethodException {
094:                    if (size() == 1)
095:                        return firstElement();
096:                    if (size() > 1) {
097:                        StringBuffer buf = new StringBuffer();
098:                        Enumeration e = elements();
099:                        buf.append(e.nextElement());
100:                        while (e.hasMoreElements())
101:                            buf.append(" and ").append(e.nextElement());
102:                        throw new NoSuchMethodException(callToString(
103:                                targetClass, methodName, argTypes,
104:                                isStaticReference)
105:                                + " is ambiguous. It matches " + buf.toString());
106:                    }
107:                    return null;
108:                }
109:            }
110:
111:            /** Convenience method: Test an entire parameter-list/argument-list pair
112:            for isMethodConvertable(), qv. 
113:             */
114:            static private boolean areMethodConvertable(Class[] parms,
115:                    Class[] args) {
116:                if (parms.length != args.length)
117:                    return false;
118:
119:                for (int i = 0; i < parms.length; ++i)
120:                    if (!isMethodConvertable(parms[i], args[i]))
121:                        return false;
122:
123:                return true;
124:            }
125:
126:            /** Internal subroutine for getEntryPoint(): Format arguments as a
127:              string describing the function being searched for. Used in
128:              verbose exceptions. */
129:            private static String callToString(Class targetClass,
130:                    String methodName, Class[] argTypes,
131:                    boolean isStaticReference) {
132:                StringBuffer buf = new StringBuffer();
133:                if (isStaticReference)
134:                    buf.append("static ");
135:                buf.append(StringUtils.getClassName(targetClass));
136:                if (methodName != null)
137:                    buf.append(".").append(methodName);
138:                buf.append("(");
139:                if (argTypes != null && argTypes.length > 0) {
140:                    if (false) {
141:                        // ????? Sanjiva has an ArrayToString method. Using it would
142:                        // save a few bytes, at cost of giving up some reusability.
143:                    } else {
144:                        buf.append(StringUtils.getClassName(argTypes[0]));
145:                        for (int i = 1; i < argTypes.length; i++) {
146:                            buf.append(",").append(
147:                                    StringUtils.getClassName(argTypes[i]));
148:                        }
149:                    }
150:                } else
151:                    buf.append("[none]");
152:                buf.append(")");
153:                return buf.toString();
154:            }
155:
156:            /** Utility function: obtain common data from either Method or
157:              Constructor. (In lieu of an EntryPoint interface.) */
158:            static int entryGetModifiers(Object entry) {
159:                return (entry instanceof  Method) ? ((Method) entry)
160:                        .getModifiers() : ((Constructor) entry).getModifiers();
161:            }
162:
163:            // The common lookup code would be much easier if Method and
164:            // Constructor shared an "EntryPoint" Interface. Unfortunately, even
165:            // though their APIs are almost identical, they don't. These calls
166:            // are a workaround...  at the cost of additional runtime overhead
167:            // and some extra bytecodes.
168:            //
169:            // (A JDK bug report has been submitted requesting that they add the
170:            // Interface; it would be easy, harmless, and useful.)
171:
172:            /** Utility function: obtain common data from either Method or
173:              Constructor. (In lieu of an EntryPoint interface.) */
174:            static String entryGetName(Object entry) {
175:                return (entry instanceof  Method) ? ((Method) entry).getName()
176:                        : ((Constructor) entry).getName();
177:            }
178:
179:            /** Utility function: obtain common data from either Method or
180:              Constructor. (In lieu of an EntryPoint interface.) */
181:            static Class[] entryGetParameterTypes(Object entry) {
182:                return (entry instanceof  Method) ? ((Method) entry)
183:                        .getParameterTypes() : ((Constructor) entry)
184:                        .getParameterTypes();
185:            }
186:
187:            /** Utility function: obtain common data from either Method or
188:              Constructor. (In lieu of an EntryPoint interface.) */
189:            static String entryToString(Object entry) {
190:                return (entry instanceof  Method) ? ((Method) entry).toString()
191:                        : ((Constructor) entry).toString();
192:            }
193:
194:            //////////////////////////////////////////////////////////////////////////
195:
196:            /** Class.getConstructor() finds only the entry point (if any)
197:            _exactly_ matching the specified argument types. Our implmentation
198:            can decide between several imperfect matches, using the same
199:            search algorithm as the Java compiler.
200:
201:            Note that all constructors are static by definition, so
202:            isStaticReference is true.
203:
204:            @exception NoSuchMethodException if constructor not found.
205:             */
206:            static public Constructor getConstructor(Class targetClass,
207:                    Class[] argTypes) throws SecurityException,
208:                    NoSuchMethodException {
209:                return (Constructor) getEntryPoint(targetClass, null, argTypes,
210:                        true);
211:            }
212:
213:            //////////////////////////////////////////////////////////////////////////
214:
215:            /**
216:             * Search for entry point, per  Java Language Spec 1.0
217:             * as amended, verified by comparison against compiler behavior.
218:             *
219:             * @param targetClass Class object for the class to be queried.
220:             * @param methodName  Name of method to invoke, or null for constructor.
221:             *                    Only Public methods will be accepted.
222:             * @param argTypes    Classes of intended arguments.  Note that primitives
223:             *                    must be specified via their TYPE equivalents, 
224:             *                    rather than as their wrapper classes -- Integer.TYPE
225:             *                    rather than Integer. "null" may be passed in as an
226:             *                    indication that you intend to invoke the method with
227:             *                    a literal null argument and therefore can accept
228:             *                    any object type in this position.
229:             * @param isStaticReference  If true, and if the target is a Class object,
230:             *                    only static methods will be accepted as valid matches.
231:             *
232:             * @return a Method or Constructor of the appropriate signature
233:             *
234:             * @exception SecurityException     if security violation
235:             * @exception NoSuchMethodException if no such method
236:             */
237:            static private Object getEntryPoint(Class targetClass,
238:                    String methodName, Class[] argTypes,
239:                    boolean isStaticReference) throws SecurityException,
240:                    NoSuchMethodException {
241:                // 15.11.1: OBTAIN STARTING CLASS FOR SEARCH
242:                Object m = null;
243:
244:                // 15.11.2 DETERMINE ARGUMENT SIGNATURE
245:                // (Passed in as argTypes array.)
246:
247:                // Shortcut: If an exact match exists, return it.
248:                try {
249:                    if (methodName != null) {
250:                        m = targetClass.getMethod(methodName, argTypes);
251:                        if (isStaticReference
252:                                && !Modifier.isStatic(entryGetModifiers(m))) {
253:                            throw new NoSuchMethodException(callToString(
254:                                    targetClass, methodName, argTypes,
255:                                    isStaticReference)
256:                                    + " resolved to instance " + m);
257:                        }
258:                        return m;
259:                    } else
260:                        return targetClass.getConstructor(argTypes);
261:
262:                } catch (NoSuchMethodException e) {
263:                    // no-args has no alternatives!
264:                    if (argTypes == null || argTypes.length == 0) {
265:                        throw new NoSuchMethodException(callToString(
266:                                targetClass, methodName, argTypes,
267:                                isStaticReference)
268:                                + " not found.");
269:                    }
270:                    // Else fall through.
271:                }
272:
273:                // Well, _that_ didn't work. Time to search for the Most Specific
274:                // matching function. NOTE that conflicts are possible!
275:
276:                // 15.11.2.1 ACCESSIBLE: We apparently need to gather from two
277:                // sources to be sure we have both instance and static methods.
278:                Object[] methods;
279:                if (methodName != null) {
280:                    methods = targetClass.getMethods();
281:                } else {
282:                    methods = targetClass.getConstructors();
283:                }
284:                if (0 == methods.length) {
285:                    throw new NoSuchMethodException("No methods!");
286:                }
287:
288:                MoreSpecific best = new MoreSpecific();
289:                for (int i = 0; i < methods.length; ++i) {
290:                    Object mi = methods[i];
291:                    if (
292:                    // 15.11.2.1 ACCESSIBLE: Method is public.
293:                    Modifier.isPublic(entryGetModifiers(mi)) &&
294:                    // 15.11.2.1 APPLICABLE: Right method name (or c'tor)
295:                            (methodName == null || entryGetName(mi).equals(
296:                                    methodName)) &&
297:                            // 15.11.2.1 APPLICABLE: Parameters match arguments
298:                            areMethodConvertable(entryGetParameterTypes(mi),
299:                                    argTypes))
300:                        // 15.11.2.2 MORE SPECIFIC displace less specific.
301:                        best.addItem(mi);
302:                }
303:
304:                // May throw NoSuchMethodException; we pass in info needed to
305:                // create a useful exception
306:                m = best.getMostSpecific(targetClass, methodName, argTypes,
307:                        isStaticReference);
308:
309:                // 15.11.3 APPROPRIATE: Class invocation can call only static
310:                // methods. Note that the defined order of evaluation permits a
311:                // call to be resolved to an inappropriate method and then
312:                // rejected, rather than finding the best of the appropriate
313:                // methods.
314:                //
315:                // Constructors are never static, so we don't test them.
316:                if (m == null) {
317:                    throw new NoSuchMethodException(callToString(targetClass,
318:                            methodName, argTypes, isStaticReference)
319:                            + " -- no signature match");
320:                }
321:
322:                if (methodName != null && isStaticReference
323:                        && !Modifier.isStatic(entryGetModifiers(m))) {
324:                    throw new NoSuchMethodException(callToString(targetClass,
325:                            methodName, argTypes, isStaticReference)
326:                            + " resolved to instance: " + m);
327:                }
328:
329:                return m;
330:            }
331:
332:            //////////////////////////////////////////////////////////////////////////
333:
334:            /* Class.getMethod() finds only the entry point (if any) _exactly_
335:            matching the specified argument types. Our implmentation can
336:            decide between several imperfect matches, using the same search
337:            algorithm as the Java compiler.
338:
339:            This version more closely resembles Class.getMethod() -- we always
340:            ask the Class for the method. It differs in testing for
341:            appropriateness before returning the method; if the query is
342:            being made via a static reference, only static methods will be
343:            found and returned. */
344:            static public Method getMethod(Class target, String methodName,
345:                    Class[] argTypes, boolean isStaticReference)
346:                    throws SecurityException, NoSuchMethodException {
347:                return (Method) getEntryPoint(target, methodName, argTypes,
348:                        isStaticReference);
349:            }
350:
351:            //////////////////////////////////////////////////////////////////////////
352:
353:            /**
354:             * Class.getMethod() finds only the entry point (if any) _exactly_
355:             * matching the specified argument types. Our implmentation can
356:             * decide between several imperfect matches, using the same search
357:             * algorithm as the Java compiler.
358:             *
359:             * This version emulates the compiler behavior by allowing lookup to
360:             * be performed against either a class or an instance -- classname.foo()
361:             * must be a static method call, instance.foo() can invoke either static
362:             * or instance methods.
363:             *
364:             * @param target     object on which call is to be made
365:             * @param methodName name of method I'm lookin' for
366:             * @param argTypes   array of argument types of method
367:             *
368:             * @return the desired method
369:             *
370:             * @exception SecurityException     if security violation
371:             * @exception NoSuchMethodException if no such method
372:             */
373:            static public Method getMethod(Object target, String methodName,
374:                    Class[] argTypes) throws SecurityException,
375:                    NoSuchMethodException {
376:                boolean staticRef = target instanceof  Class;
377:                return getMethod(
378:                        staticRef ? (Class) target : target.getClass(),
379:                        methodName, argTypes, staticRef);
380:            }
381:
382:            /** Determine whether a given type can accept assignments of another
383:            type. Note that class.isAssignable() is _not_ a complete test!
384:            (This method is not needed by getMethod() or getConstructor(), but
385:            is provided as a convenience for other users.)
386:            
387:            parm: The type given in the method's signature.
388:            arg: The type we want to pass in.
389:
390:            Legal ASSIGNMENT CONVERSIONS (5.2) are METHOD CONVERSIONS (5.3)
391:            plus implicit narrowing of int to byte, short or char.  */
392:            static private boolean isAssignmentConvertable(Class parm, Class arg) {
393:                return (arg.equals(Integer.TYPE) && (parm.equals(Byte.TYPE)
394:                        || parm.equals(Short.TYPE) || parm
395:                        .equals(Character.TYPE)))
396:                        || isMethodConvertable(parm, arg);
397:            }
398:
399:            /** Determine whether a given method parameter type can accept
400:            arguments of another type.
401:
402:            parm: The type given in the method's signature.
403:            arg: The type we want to pass in.
404:
405:            Legal METHOD CONVERSIONS (5.3) are Identity, Widening Primitive
406:            Conversion, or Widening Reference Conversion. NOTE that this is a
407:            subset of the legal ASSIGNMENT CONVERSIONS (5.2) -- in particular,
408:            we can't implicitly narrow int to byte, short or char.
409:
410:            SPECIAL CASE: In order to permit invoking methods with literal
411:            "null" values, setting the arg Class to null will be taken as a
412:            request to match any Class type. POSSIBLE PROBLEM: This may match
413:            a primitive type, which really should not accept a null value... but
414:            I'm not sure how best to distinguish those, short of enumerating them
415:             */
416:            static private boolean isMethodConvertable(Class parm, Class arg) {
417:                if (parm.equals(arg)) // If same class, short-circuit now!
418:                    return true;
419:
420:                // Accept any type EXCEPT primitives (which can't have null values).
421:                if (arg == null) {
422:                    return !parm.isPrimitive();
423:                }
424:
425:                // Arrays are convertable if their elements are convertable
426:                // ????? Does this have to be done before isAssignableFrom, or
427:                // does it successfully handle arrays of primatives?
428:                while (parm.isArray()) {
429:                    if (!arg.isArray())
430:                        return false; // Unequal array depth
431:                    else {
432:                        parm = parm.getComponentType();
433:                        arg = arg.getComponentType();
434:                    }
435:                }
436:                if (arg.isArray())
437:                    return false; // Unequal array depth
438:
439:                // Despite its name, the 1.1.6 docs say that this function does
440:                // NOT return true for all legal ASSIGNMENT CONVERSIONS
441:                // (5.2):
442:                //   "Specifically, this method tests whether the type
443:                //   represented by the specified class can be converted
444:                //   to the type represented by this Class object via
445:                //   an identity conversion or via a widening reference
446:                //   conversion."
447:                if (parm.isAssignableFrom(arg))
448:                    return true;
449:
450:                // That leaves us the Widening Primitives case. Four possibilities:
451:                // void (can only convert to void), boolean (can only convert to boolean),
452:                // numeric (which are sequenced) and char (which inserts itself into the
453:                // numerics by promoting to int or larger)
454:
455:                if (parm.equals(Void.TYPE) || parm.equals(Boolean.TYPE)
456:                        || arg.equals(Void.TYPE) || arg.equals(Boolean.TYPE))
457:                    return false;
458:
459:                Class[] primTypes = { Character.TYPE, Byte.TYPE, Short.TYPE,
460:                        Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE };
461:                int parmscore, argscore;
462:
463:                for (parmscore = 0; parmscore < primTypes.length; ++parmscore)
464:                    if (parm.equals(primTypes[parmscore]))
465:                        break;
466:                if (parmscore >= primTypes.length)
467:                    return false; // Off the end
468:
469:                for (argscore = 0; argscore < primTypes.length; ++argscore)
470:                    if (arg.equals(primTypes[argscore]))
471:                        break;
472:                if (argscore >= primTypes.length)
473:                    return false; // Off the end
474:
475:                // OK if ordered AND NOT char-to-smaller-than-int
476:                return (argscore < parmscore && (argscore != 0 || parmscore > 2));
477:            }
478:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.