Source Code Cross Referenced for ReflectionUtils.java in  » Inversion-of-Control » JICE » org » jicengine » operation » 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 » Inversion of Control » JICE » org.jicengine.operation 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package org.jicengine.operation;
002:
003:        import java.lang.reflect.InvocationTargetException;
004:        import java.lang.reflect.Method;
005:        import java.lang.reflect.Constructor;
006:        import java.lang.reflect.Field;
007:        import java.lang.reflect.Modifier;
008:        import java.util.Map;
009:        import java.util.HashMap;
010:
011:        /**
012:         *
013:         * <p>
014:         * Copyright (C) 2004  Timo Laitinen
015:         * </p>
016:         * @author    .timo
017:         * @version   1.0
018:         */
019:
020:        public class ReflectionUtils {
021:
022:            private static final String FIELD_CLASS = "class";
023:
024:            /**
025:             *
026:             * @author    timo
027:             */
028:            protected static class NoSuchMethodException extends
029:                    java.lang.NoSuchMethodException {
030:                public NoSuchMethodException(Class actorClass, String methodName) {
031:                    super ("Class '" + actorClass.getName()
032:                            + "' doesn't have a method '" + methodName + "'.");
033:                }
034:            }
035:
036:            /**
037:             * Indicates that one or more methods with the right name were found but the
038:             * method-parameters didn't match.
039:             *
040:             * @author    timo
041:             */
042:            protected static class NoMethodWithSuchParametersException extends
043:                    java.lang.NoSuchMethodException {
044:                public NoMethodWithSuchParametersException(Class actorClass,
045:                        String methodName, Object[] arguments) {
046:                    super ("Class '" + actorClass.getName()
047:                            + "' doesn't have a method '" + methodName
048:                            + " accepting arguments ("
049:                            + getArgumentTypeList(arguments) + ")");
050:                }
051:            }
052:
053:            /**
054:             *
055:             *
056:             * @author    timo
057:             * @created   29. elokuuta 2004
058:             */
059:            protected static class NoSuchConstructorException extends
060:                    java.lang.NoSuchMethodException {
061:                public NoSuchConstructorException(Class actorClass,
062:                        Object[] arguments) {
063:                    super (
064:                            "Class '"
065:                                    + actorClass.getName()
066:                                    + "' doesn't have constructor accepting arguments ("
067:                                    + getArgumentTypeList(arguments) + ")");
068:                }
069:            }
070:
071:            private static Map objectTypesToPrimitiveTypes = new HashMap();
072:            private static Map primitiveTypesToObjectTypes = new HashMap();
073:
074:            private static final int ASSIGNABILITY_DIFFERENT_PARAMETER_COUNTS = -1;
075:            private static final int ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS = 0;
076:            private static final int ASSIGNABILITY_EXACT_MATCH = 1;
077:
078:            /**
079:             * <p>
080:             * Mimics method <code>Class.isAssignableFrom</code>, but handles the
081:             * conversions between primitives and primitive wrappers automatically.
082:             * </p>
083:             *
084:             * @param class1 Class
085:             * @param class2 Class
086:             * @return boolean
087:             */
088:            public static boolean isAssignableFrom(Class class1, Class class2) {
089:                if (class1.isAssignableFrom(class2)) {
090:                    return true;
091:                } else {
092:                    Class primitive = primitiveWrapperToPrimitiveType(class2);
093:                    if (primitive != null) {
094:                        return class1.isAssignableFrom(primitive);
095:                    } else {
096:                        return false;
097:                    }
098:                }
099:            }
100:
101:            public static void setFieldValue(Object instance, Class ownerClass,
102:                    String fieldName, Object fieldValue) throws Exception {
103:                try {
104:                    Field field = ownerClass.getField(fieldName);
105:                    field.set(instance, fieldValue);
106:
107:                } catch (NoSuchFieldException e) {
108:                    // for better error-message
109:                    throw new NoSuchFieldException("Field '" + fieldName
110:                            + "' not found in class '" + ownerClass.getName()
111:                            + "'.");
112:                }
113:            }
114:
115:            /**
116:             * @param instance  the instance whose field is referenced. may be null, if
117:             * the field in question is a static field.
118:             *
119:             * @param ownerClass  the class that 'owns' the field.
120:             * @param fieldName   the name of the field.
121:             */
122:            public static Object getFieldValue(Object instance,
123:                    Class ownerClass, String fieldName) throws Exception {
124:                if (instance == null && fieldName.equals(FIELD_CLASS)) {
125:                    // this is not a real static field but an expression 
126:                    // like 'java.lang.String.class'. 
127:                    // reflection does not understand the pseudo-field
128:                    // 'class', so we handle this situation here
129:                    // by simply returning the class.
130:                    return ownerClass;
131:                } else {
132:                    try {
133:                        Field field = ownerClass.getField(fieldName);
134:                        return field.get(instance);
135:                    } catch (NoSuchFieldException e) {
136:                        // for better error-message
137:                        throw new NoSuchFieldException("Field '" + fieldName
138:                                + "' not found in class '"
139:                                + ownerClass.getName() + "'.");
140:                    }
141:                }
142:            }
143:
144:            protected static Class getActorClass(Object instanceOrClass) {
145:                if (instanceOrClass instanceof  Class) {
146:                    return (Class) instanceOrClass;
147:                } else {
148:                    return instanceOrClass.getClass();
149:                }
150:            }
151:
152:            /**
153:             * <p>
154:             * Resolves the 'parameter assignability level' that a set of parameters
155:             * has against a set of parameter types.
156:             * </p>
157:             * <p>
158:             * The assignability level is returned as a int value that follows a little
159:             * peculiar scheme:
160:             * <ul>
161:             *  <li><b> -1 </b> - no match. even the number of parameters doesn't match. </li>
162:             *  <li><b> 0 </b> - no match. the number of parameter matches, but at least
163:             *  one of the parameters has a wrong type. </li>
164:             *  <li><b> 1 </b> - exact match. the parameter types match the runtime
165:             *  classes of the parameter objects exactly. </li>
166:             *  <li><b> 2,3,4,.. </b> - the parameters match. the parameters are assignable
167:             *  to the expected parameter types, but the expected types are superclasses
168:             *  or interfaces of the actual types of the parameter objects. the greater
169:             *  the number, the further away the parameter objects are. </li>
170:             * </ul>
171:             * <p>
172:             * THEREFORE: a positive assignability level that is closer to 1 is better
173:             * than a positive value that is further away from it. 1 is the best. values
174:             * that are 0 or negative mean that the parameters are incompatible.
175:             * </p>
176:             *
177:             * @param parameterTypes  declared parameter types of a method/constructor.
178:             * @param parameters      runtime parameters given to the method/constructor,
179:             *                        whose types are checked agains the declared types,
180:             *                        in order to find out the correct method/constructor
181:             *                        to call.
182:             *
183:             * @return                The parameterAssignabilityLevel value
184:             */
185:            private static int getParameterAssignabilityLevel(
186:                    Class[] parameterTypes, Object[] parameters) {
187:                if (parameterTypes.length == parameters.length) {
188:                    // the number of parameters matches. search further
189:
190:                    // exactly assignable by default
191:                    int assignability = ASSIGNABILITY_EXACT_MATCH;
192:
193:                    for (int i = 0; i < parameterTypes.length; i++) {
194:                        Class parameterType = parameterTypes[i];
195:                        Object parameter = parameters[i];
196:                        if (parameter == null) {
197:                            // we can't resolve the type of a null-parameter!
198:                            throw new IllegalArgumentException("parameter "
199:                                    + (i + 1) + " was null.");
200:                        }
201:
202:                        Class candidateType = parameter.getClass();
203:
204:                        if (parameterType.equals(candidateType)) {
205:                            // ok, an exact match.
206:                            assignability *= ASSIGNABILITY_EXACT_MATCH;
207:                        } else if (parameterType
208:                                .isAssignableFrom(candidateType)) {
209:                            // not an exact match but a match anyways
210:                            // TODO: calculate the distance between these two classes.
211:                            assignability *= 2;
212:                        } else if (parameterType.isPrimitive()) {
213:                            // we have still hope: lets do the primitive conversion.
214:                            Class correspondingPrimitive = primitiveWrapperToPrimitiveType(candidateType);
215:
216:                            // if the required parameter type is a primitive, we can't simply
217:                            // test for equals instead of the assignable thing. int = int,
218:                            // there are no subclasses!
219:                            if (correspondingPrimitive != null
220:                                    && correspondingPrimitive
221:                                            .equals(parameterType)) {
222:                                // this is considered as an exact match.
223:                                assignability *= ASSIGNABILITY_EXACT_MATCH;
224:                            } else {
225:                                // no match, stop the search.
226:                                assignability *= ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS;
227:                                break;
228:                            }
229:                        } else {
230:                            // no exact match, no assignable match and no match after primitive
231:                            // conversions. certainly no match!
232:                            assignability *= ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS;
233:                            break;
234:                        }
235:                    }
236:
237:                    return assignability;
238:                } else {
239:                    // even the number of parameters isn't exact. the worst case
240:                    return ASSIGNABILITY_DIFFERENT_PARAMETER_COUNTS;
241:                }
242:            }
243:
244:            /**
245:             * Invokes a method.
246:             *
247:             * @param methodName                        the name of the method, like
248:             *                                          'addLayer' or 'setName'
249:             * @param actor                             Description of the Parameter
250:             * @param arguments                        Description of the Parameter
251:             * @return                                  an Object, if the invoked method
252:             *      returned something. null if the methods return-type is void.
253:             * @throws NoSuchMethodException            if no matching method was found
254:             * @throws IllegalAccessException           see Method.invoke()
255:             * @throws IllegalArgumentException         see Method.invoke()
256:             * @throws InvocationTargetException        if the invoked method throwed an
257:             *      Exception
258:             */
259:            public static Object invokeMethod(Object actor, String methodName,
260:                    Object[] arguments) throws java.lang.NoSuchMethodException,
261:                    IllegalAccessException, IllegalArgumentException,
262:                    InvocationTargetException {
263:                if (actor == null) {
264:                    throw new NullPointerException("when calling method '"
265:                            + methodName + "' (with " + arguments.length
266:                            + " arguments)");
267:                } else {
268:                    return invokeMethod(actor, actor.getClass(), methodName,
269:                            arguments);
270:                }
271:            }
272:
273:            public static Object invokeStaticMethod(Class actorClass,
274:                    String methodName, Object[] arguments)
275:                    throws java.lang.NoSuchMethodException,
276:                    IllegalAccessException, IllegalArgumentException,
277:                    InvocationTargetException {
278:                if (actorClass == null) {
279:                    throw new NullPointerException(
280:                            "when calling static method '" + methodName
281:                                    + "' (with " + arguments.length
282:                                    + " arguments)");
283:                } else {
284:                    return invokeMethod(null, actorClass, methodName, arguments);
285:                }
286:            }
287:
288:            public static Object instantiate(Class instantiatedClass,
289:                    Object[] arguments) throws java.lang.NoSuchMethodException,
290:                    InstantiationException, IllegalAccessException,
291:                    InvocationTargetException {
292:                // find the constructor.
293:                Constructor constructor = findConstructor(instantiatedClass,
294:                        arguments);
295:
296:                // instantiate object
297:                try {
298:                    return constructor.newInstance(arguments);
299:                } catch (IllegalArgumentException e) {
300:                    throw new IllegalArgumentException(
301:                            "Problems instantiating with constructor '"
302:                                    + constructor + "'");
303:                }
304:            }
305:
306:            private static Constructor findConstructor(Class instantiatedClass,
307:                    Object[] arguments) throws java.lang.NoSuchMethodException,
308:                    InstantiationException, IllegalAccessException {
309:                Constructor[] constructors = instantiatedClass
310:                        .getConstructors();
311:                Constructor match = null;
312:                int parameterAssignability = ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS;
313:
314:                for (int i = 0; i < constructors.length; i++) {
315:                    Constructor candidate = constructors[i];
316:                    Class[] parameterTypes = candidate.getParameterTypes();
317:
318:                    int candidateParameterAssignability = getParameterAssignabilityLevel(
319:                            parameterTypes, arguments);
320:
321:                    if (candidateParameterAssignability > ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS) {
322:                        // parameters a assignable. find out how assignable
323:
324:                        if (candidateParameterAssignability == ASSIGNABILITY_EXACT_MATCH) {
325:                            // the parameters match exactly. we can stop the seach here!
326:                            match = candidate;
327:                            parameterAssignability = candidateParameterAssignability;
328:                            break;
329:                        } else if (parameterAssignability < ASSIGNABILITY_EXACT_MATCH
330:                                || candidateParameterAssignability < parameterAssignability) {
331:                            // not an exact match but a better match than our previous match
332:                            // (if had one).
333:                            // this is the best candidate so far, but we have to continue the
334:                            // search.
335:                            match = candidate;
336:                            parameterAssignability = candidateParameterAssignability;
337:                            continue;
338:                        }
339:                    }
340:                }
341:
342:                if (match == null) {
343:                    throw new NoSuchConstructorException(instantiatedClass,
344:                            arguments);
345:                } else {
346:                    return match;
347:                }
348:            }
349:
350:            /**
351:             * @param objectClass  Description of the Parameter
352:             * @return             the Class representing a primitive: if the argument
353:             *                     Class is java.lang.Integer, returns Integer.TYPe, etc.
354:             *                     null if the argument class is not a wrapper.
355:             */
356:            protected static Class primitiveWrapperToPrimitiveType(
357:                    Class objectClass) {
358:                return (Class) objectTypesToPrimitiveTypes.get(objectClass);
359:            }
360:
361:            /**
362:             * @param primitiveType  Description of the Parameter
363:             * @return               null if the argument class is not a primitive type.
364:             */
365:            protected static Class primitiveTypeToWrapperType(
366:                    Class primitiveType) {
367:                return (Class) primitiveTypesToObjectTypes.get(primitiveType);
368:            }
369:
370:            /**
371:             *
372:             * @param arguments Object[]
373:             * @return String types in format [arg1 class], [arg2 class], etc.
374:             */
375:            protected static String getArgumentTypeList(Object[] arguments) {
376:                String paramString = "";
377:                for (int i = 0; i < arguments.length; i++) {
378:                    if (arguments[i] == null) {
379:                        paramString += "" + arguments[i];
380:                    } else {
381:                        // should array and primitive types be handled separately?
382:                        paramString += arguments[i].getClass().getName();
383:                    }
384:
385:                    if ((i + 1) < arguments.length) {
386:                        paramString += ",";
387:                    }
388:                }
389:                return paramString;
390:            }
391:
392:            /**
393:             * a method for invoking both instance methods and static methods dynamically.
394:             *
395:             * @param actor                             the instance whose method is
396:             *      invoked. null, if a static method is in question. NOTE: the null means
397:             *      that the method must be static. filter unintentional null-values away
398:             *      before calling this method!
399:             * @param actorClass                        the class that owns the invoked
400:             *      method. this should be the class of the actor.
401:             * @param methodName                        name of the method
402:             * @param parameters                        parameters as Object[]
403:             * @return                                  Description of the Return Value
404:             * @throws java.lang.NoSuchMethodException  Description of the Exception
405:             * @throws IllegalAccessException           Description of the Exception
406:             * @throws IllegalArgumentException         Description of the Exception
407:             * @throws InvocationTargetException        Description of the Exception
408:             */
409:            private static Object invokeMethod(Object actor, Class actorClass,
410:                    String methodName, Object[] arguments)
411:                    throws java.lang.NoSuchMethodException,
412:                    IllegalAccessException, IllegalArgumentException,
413:                    InvocationTargetException {
414:                // some validity checks
415:                if (methodName == null) {
416:                    throw new IllegalArgumentException(
417:                            "Can't invoke a method: method name was null");
418:                }
419:                if (arguments == null) {
420:                    throw new IllegalArgumentException(
421:                            "Can't invoke a method: arguments[] was null");
422:                }
423:
424:                if (!Modifier.isPublic(actorClass.getModifiers())) {
425:                    // problem: a non-public class. we have no permissions to read it.
426:                    // this support has to be implemented later.
427:                    throw new UnsupportedOperationException(
428:                            "Class '"
429:                                    + actorClass.getName()
430:                                    + "' is private or protected. only public classes are supported currently.");
431:                }
432:
433:                Method method;
434:
435:                // we try first the method Class.getMethod().
436:                // it works only if the types of the parameters match exactly the
437:                // declared parameter types of a method in the owner class.
438:                // but it is fast - its worth trying although it might result in
439:                // exception.
440:                //
441:                // note: we could use some heuristics for deciding whether it is better
442:                // to try getMethod() or manual search first.
443:                try {
444:                    method = actorClass.getMethod(methodName,
445:                            getTypes(arguments));
446:                } catch (java.lang.NoSuchMethodException e) {
447:                    method = findMethod(actorClass, methodName, arguments);
448:                }
449:
450:                // call the method and return the result.
451:                // note: a better error message for situations where the method was supposed
452:                // to be static but wasn't? now, only a nullpointer is thrown..
453:                return method.invoke(actor, arguments);
454:            }
455:
456:            private static Method findMethod(Class actorClass,
457:                    String methodName, Object[] arguments)
458:                    throws java.lang.NoSuchMethodException,
459:                    IllegalAccessException, IllegalArgumentException,
460:                    InvocationTargetException {
461:                Method[] methods = actorClass.getMethods();
462:                Method match = null;
463:                int parameterAssignability = ASSIGNABILITY_DIFFERENT_PARAMETER_COUNTS;
464:                boolean foundMethodWithTheSameName = false;
465:
466:                for (int i = 0; i < methods.length; i++) {
467:                    Method candidate = methods[i];
468:                    if (candidate.getName().equals(methodName)) {
469:                        // good, the name matches..
470:                        foundMethodWithTheSameName = true;
471:                        Class[] parameterTypes = candidate.getParameterTypes();
472:
473:                        int candidateParameterAssignability = getParameterAssignabilityLevel(
474:                                parameterTypes, arguments);
475:
476:                        if (candidateParameterAssignability > ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS) {
477:                            // parameters a assignable. find out how assignable
478:
479:                            if (candidateParameterAssignability == ASSIGNABILITY_EXACT_MATCH) {
480:                                // the parameters match exactly. we can stop the seach here!
481:                                match = candidate;
482:                                parameterAssignability = candidateParameterAssignability;
483:                                break;
484:                            } else if (parameterAssignability < ASSIGNABILITY_EXACT_MATCH
485:                                    || candidateParameterAssignability < parameterAssignability) {
486:                                // not an exact match but a better match than our previous match
487:                                // (if had one).
488:                                // this is the best candidate so far, but we have to continue the
489:                                // search.
490:
491:                                // NOTE: 16.5.2005: is the test correct? shouldn't it use '>'
492:                                // instead of '<'..
493:
494:                                match = candidate;
495:                                parameterAssignability = candidateParameterAssignability;
496:                                continue;
497:                            }
498:                        }
499:                    }
500:                }
501:
502:                if (match == null) {
503:                    // no method found.
504:                    if (foundMethodWithTheSameName) {
505:                        throw new NoMethodWithSuchParametersException(
506:                                actorClass, methodName, arguments);
507:                    } else {
508:                        throw new ReflectionUtils.NoSuchMethodException(
509:                                actorClass, methodName);
510:                    }
511:                } else {
512:                    return match;
513:                }
514:            }
515:
516:            protected static Class[] getTypes(Object[] parameters) {
517:                Class[] types = new Class[parameters.length];
518:                for (int i = 0; i < parameters.length; i++) {
519:                    types[i] = parameters[i].getClass();
520:                }
521:                return types;
522:            }
523:
524:            static {
525:                objectTypesToPrimitiveTypes.put(Double.class, Double.TYPE);
526:                objectTypesToPrimitiveTypes.put(Integer.class, Integer.TYPE);
527:                objectTypesToPrimitiveTypes.put(Long.class, Long.TYPE);
528:                objectTypesToPrimitiveTypes
529:                        .put(Character.class, Character.TYPE);
530:                objectTypesToPrimitiveTypes.put(Boolean.class, Boolean.TYPE);
531:                objectTypesToPrimitiveTypes.put(Byte.class, Byte.TYPE);
532:                objectTypesToPrimitiveTypes.put(Float.class, Float.TYPE);
533:                objectTypesToPrimitiveTypes.put(Short.class, Short.TYPE);
534:
535:                primitiveTypesToObjectTypes.put(Double.TYPE, Double.class);
536:                primitiveTypesToObjectTypes.put(Integer.TYPE, Integer.class);
537:                primitiveTypesToObjectTypes.put(Long.TYPE, Long.class);
538:                primitiveTypesToObjectTypes
539:                        .put(Character.TYPE, Character.class);
540:                primitiveTypesToObjectTypes.put(Boolean.TYPE, Boolean.class);
541:                primitiveTypesToObjectTypes.put(Byte.TYPE, Byte.class);
542:                primitiveTypesToObjectTypes.put(Float.TYPE, Float.class);
543:                primitiveTypesToObjectTypes.put(Short.TYPE, Short.class);
544:
545:            }
546:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.