Source Code Cross Referenced for ReflectionUtils.java in  » 6.0-JDK-Core » beans » java » beans » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
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
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » beans » java.beans 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025        package java.beans;
026
027        import java.lang.reflect.Constructor;
028        import java.lang.reflect.Field;
029        import java.lang.reflect.Method;
030        import java.lang.reflect.Modifier;
031
032        import java.lang.ref.Reference;
033        import java.lang.ref.SoftReference;
034
035        import java.util.*;
036
037        import com.sun.beans.ObjectHandler;
038        import sun.reflect.misc.MethodUtil;
039        import sun.reflect.misc.ConstructorUtil;
040        import sun.reflect.misc.ReflectUtil;
041
042        /**
043         * A utility class for reflectively finding methods, constuctors and fields
044         * using reflection.
045         */
046        class ReflectionUtils {
047
048            private static Reference methodCacheRef;
049
050            public static Class typeToClass(Class type) {
051                return type.isPrimitive() ? ObjectHandler.typeNameToClass(type
052                        .getName()) : type;
053            }
054
055            public static boolean isPrimitive(Class type) {
056                return primitiveTypeFor(type) != null;
057            }
058
059            public static Class primitiveTypeFor(Class wrapper) {
060                if (wrapper == Boolean.class)
061                    return Boolean.TYPE;
062                if (wrapper == Byte.class)
063                    return Byte.TYPE;
064                if (wrapper == Character.class)
065                    return Character.TYPE;
066                if (wrapper == Short.class)
067                    return Short.TYPE;
068                if (wrapper == Integer.class)
069                    return Integer.TYPE;
070                if (wrapper == Long.class)
071                    return Long.TYPE;
072                if (wrapper == Float.class)
073                    return Float.TYPE;
074                if (wrapper == Double.class)
075                    return Double.TYPE;
076                if (wrapper == Void.class)
077                    return Void.TYPE;
078                return null;
079            }
080
081            /**
082             * Tests each element on the class arrays for assignability.
083             *
084             * @param argClasses arguments to be tested
085             * @param argTypes arguments from Method
086             * @return true if each class in argTypes is assignable from the 
087             *         corresponding class in argClasses.
088             */
089            private static boolean matchArguments(Class[] argClasses,
090                    Class[] argTypes) {
091                return matchArguments(argClasses, argTypes, false);
092            }
093
094            /**
095             * Tests each element on the class arrays for equality.
096             *
097             * @param argClasses arguments to be tested
098             * @param argTypes arguments from Method
099             * @return true if each class in argTypes is equal to the 
100             *         corresponding class in argClasses.
101             */
102            private static boolean matchExplicitArguments(Class[] argClasses,
103                    Class[] argTypes) {
104                return matchArguments(argClasses, argTypes, true);
105            }
106
107            private static boolean matchArguments(Class[] argClasses,
108                    Class[] argTypes, boolean explicit) {
109
110                boolean match = (argClasses.length == argTypes.length);
111                for (int j = 0; j < argClasses.length && match; j++) {
112                    Class argType = argTypes[j];
113                    if (argType.isPrimitive()) {
114                        argType = typeToClass(argType);
115                    }
116                    if (explicit) {
117                        // Test each element for equality
118                        if (argClasses[j] != argType) {
119                            match = false;
120                        }
121                    } else {
122                        // Consider null an instance of all classes.
123                        if (argClasses[j] != null
124                                && !(argType.isAssignableFrom(argClasses[j]))) {
125                            match = false;
126                        }
127                    }
128                }
129                return match;
130            }
131
132            /**
133             * @return the method which best matches the signature or throw an exception
134             *         if it can't be found or the method is ambiguous.
135             */
136            static Method getPublicMethod(Class declaringClass,
137                    String methodName, Class[] argClasses)
138                    throws NoSuchMethodException {
139                Method m;
140
141                m = findPublicMethod(declaringClass, methodName, argClasses);
142                if (m == null)
143                    throw new NoSuchMethodException(declaringClass.getName()
144                            + "." + methodName);
145                return m;
146            }
147
148            /**
149             * @return the method which best matches the signature or null if it cant be found or 
150             *         the method is ambiguous.
151             */
152            public static Method findPublicMethod(Class declaringClass,
153                    String methodName, Class[] argClasses) {
154                // Many methods are "getters" which take no arguments.
155                // This permits the following optimisation which
156                // avoids the expensive call to getMethods().
157                if (argClasses.length == 0) {
158                    try {
159                        return MethodUtil.getMethod(declaringClass, methodName,
160                                argClasses);
161                    } catch (NoSuchMethodException e) {
162                        return null;
163                    } catch (SecurityException se) {
164                        // fall through
165                    }
166                }
167                Method[] methods = MethodUtil.getPublicMethods(declaringClass);
168                List list = new ArrayList();
169                for (int i = 0; i < methods.length; i++) {
170                    // Collect all the methods which match the signature.
171                    Method method = methods[i];
172                    if (method.getName().equals(methodName)) {
173                        if (matchArguments(argClasses, method
174                                .getParameterTypes())) {
175                            list.add(method);
176                        }
177                    }
178                }
179                if (list.size() > 0) {
180                    if (list.size() == 1) {
181                        return (Method) list.get(0);
182                    } else {
183                        ListIterator iterator = list.listIterator();
184                        Method method;
185                        while (iterator.hasNext()) {
186                            method = (Method) iterator.next();
187                            if (matchExplicitArguments(argClasses, method
188                                    .getParameterTypes())) {
189                                return method;
190                            }
191                        }
192                        // There are more than one method which matches this signature.
193                        // try to return the most specific method.
194                        return getMostSpecificMethod(list, argClasses);
195                    }
196                }
197                return null;
198            }
199
200            /**
201             * Return the most specific method from the list of methods which 
202             * matches the args. The most specific method will have the most
203             * number of equal parameters or will be closest in the inheritance
204             * heirarchy to the runtime execution arguments.
205             * <p>
206             * See the JLS section 15.12
207             * http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#20448
208             * 
209             * @param methods List of methods which already have the same param length
210             *                and arg types are assignable to param types
211             * @param args an array of param types to match
212             * @return method or null if a specific method cannot be determined
213             */
214            private static Method getMostSpecificMethod(List methods,
215                    Class[] args) {
216                Method method = null;
217
218                int matches = 0;
219                int lastMatch = matches;
220
221                ListIterator iterator = methods.listIterator();
222                while (iterator.hasNext()) {
223                    Method m = (Method) iterator.next();
224                    Class[] mArgs = m.getParameterTypes();
225                    matches = 0;
226                    for (int i = 0; i < args.length; i++) {
227                        Class mArg = mArgs[i];
228                        if (mArg.isPrimitive()) {
229                            mArg = typeToClass(mArg);
230                        }
231                        if (args[i] == mArg) {
232                            matches++;
233                        }
234                    }
235                    if (matches == 0 && lastMatch == 0) {
236                        if (method == null) {
237                            method = m;
238                        } else {
239                            // Test existing method. We already know that the args can 
240                            // be assigned to all the method params. However, if the
241                            // current method parameters is higher in the inheritance 
242                            // hierarchy then replace it.
243                            if (!matchArguments(method.getParameterTypes(), m
244                                    .getParameterTypes())) {
245                                method = m;
246                            }
247                        }
248                    } else if (matches > lastMatch) {
249                        lastMatch = matches;
250                        method = m;
251                    } else if (matches == lastMatch) {
252                        // ambiguous method selection.
253                        method = null;
254                    }
255                }
256                return method;
257            }
258
259            /**
260             * @return the method or null if it can't be found or is ambiguous.
261             */
262            public static Method findMethod(Class targetClass,
263                    String methodName, Class[] argClasses) {
264                Method m = findPublicMethod(targetClass, methodName, argClasses);
265                if (m != null
266                        && Modifier.isPublic(m.getDeclaringClass()
267                                .getModifiers())) {
268                    return m;
269                }
270
271                /*
272                Search the interfaces for a public version of this method.
273
274                Example: the getKeymap() method of a JTextField
275                returns a package private implementation of the
276                of the public Keymap interface. In the Keymap
277                interface there are a number of "properties" one
278                being the "resolveParent" property implied by the
279                getResolveParent() method. This getResolveParent()
280                cannot be called reflectively because the class
281                itself is not public. Instead we search the class's
282                interfaces and find the getResolveParent()
283                method of the Keymap interface - on which invoke
284                may be applied without error.
285
286                So in :-
287
288                    JTextField o = new JTextField("Hello, world");
289                    Keymap km = o.getKeymap();
290                    Method m1 = km.getClass().getMethod("getResolveParent", new Class[0]);
291                    Method m2 = Keymap.class.getMethod("getResolveParent", new Class[0]);
292
293                Methods m1 and m2 are different. The invocation of method
294                m1 unconditionally throws an IllegalAccessException where
295                the invocation of m2 will invoke the implementation of the
296                method. Note that (ignoring the overloading of arguments)
297                there is only one implementation of the named method which
298                may be applied to this target.
299                 */
300                for (Class type = targetClass; type != null; type = type
301                        .getSuperclass()) {
302                    Class[] interfaces = type.getInterfaces();
303                    for (int i = 0; i < interfaces.length; i++) {
304                        m = findPublicMethod(interfaces[i], methodName,
305                                argClasses);
306                        if (m != null) {
307                            return m;
308                        }
309                    }
310                }
311                return null;
312            }
313
314            /** 
315             * A class that represents the unique elements of a method that will be a
316             * key in the method cache.
317             */
318            private static class Signature {
319                private Class targetClass;
320                private String methodName;
321                private Class[] argClasses;
322
323                private volatile int hashCode = 0;
324
325                public Signature(Class targetClass, String methodName,
326                        Class[] argClasses) {
327                    this .targetClass = targetClass;
328                    this .methodName = methodName;
329                    this .argClasses = argClasses;
330                }
331
332                public boolean equals(Object o2) {
333                    if (this  == o2) {
334                        return true;
335                    }
336                    Signature that = (Signature) o2;
337                    if (!(targetClass == that.targetClass)) {
338                        return false;
339                    }
340                    if (!(methodName.equals(that.methodName))) {
341                        return false;
342                    }
343                    if (argClasses.length != that.argClasses.length) {
344                        return false;
345                    }
346                    for (int i = 0; i < argClasses.length; i++) {
347                        if (!(argClasses[i] == that.argClasses[i])) {
348                            return false;
349                        }
350                    }
351                    return true;
352                }
353
354                /**
355                 * Hash code computed using algorithm suggested in 
356                 * Effective Java, Item 8.
357                 */
358                public int hashCode() {
359                    if (hashCode == 0) {
360                        int result = 17;
361                        result = 37 * result + targetClass.hashCode();
362                        result = 37 * result + methodName.hashCode();
363                        if (argClasses != null) {
364                            for (int i = 0; i < argClasses.length; i++) {
365                                result = 37
366                                        * result
367                                        + ((argClasses[i] == null) ? 0
368                                                : argClasses[i].hashCode());
369                            }
370                        }
371                        hashCode = result;
372                    }
373                    return hashCode;
374                }
375            }
376
377            /** 
378             * A wrapper to findMethod(), which will search or populate the method
379             * in a cache.
380             * @throws exception if the method is ambiguios.
381             */
382            public static synchronized Method getMethod(Class targetClass,
383                    String methodName, Class[] argClasses) {
384                Object signature = new Signature(targetClass, methodName,
385                        argClasses);
386
387                Method method = null;
388                Map methodCache = null;
389                boolean cache = false;
390                if (ReflectUtil.isPackageAccessible(targetClass)) {
391                    cache = true;
392                }
393
394                if (cache && methodCacheRef != null
395                        && (methodCache = (Map) methodCacheRef.get()) != null) {
396                    method = (Method) methodCache.get(signature);
397                    if (method != null) {
398                        return method;
399                    }
400                }
401                method = findMethod(targetClass, methodName, argClasses);
402                if (cache && method != null) {
403                    if (methodCache == null) {
404                        methodCache = new HashMap();
405                        methodCacheRef = new SoftReference(methodCache);
406                    }
407                    methodCache.put(signature, method);
408                }
409                return method;
410            }
411
412            /**
413             * Return a constructor on the class with the arguments.
414             *
415             * @throws exception if the method is ambiguios.
416             */
417            public static Constructor getConstructor(Class cls, Class[] args) {
418                Constructor constructor = null;
419
420                // PENDING: Implement the resolutuion of ambiguities properly.
421                Constructor[] ctors = ConstructorUtil.getConstructors(cls);
422                for (int i = 0; i < ctors.length; i++) {
423                    if (matchArguments(args, ctors[i].getParameterTypes())) {
424                        constructor = ctors[i];
425                    }
426                }
427                return constructor;
428            }
429
430            public static Object getPrivateField(Object instance, Class cls,
431                    String name) {
432                return getPrivateField(instance, cls, name, null);
433            }
434
435            /**
436             * Returns the value of a private field. 
437             *
438             * @param instance object instance 
439             * @param cls class 
440             * @param name name of the field
441             * @param el an exception listener to handle exceptions; or null
442             * @return value of the field; null if not found or an error is encountered
443             */
444            public static Object getPrivateField(Object instance, Class cls,
445                    String name, ExceptionListener el) {
446                try {
447                    Field f = cls.getDeclaredField(name);
448                    f.setAccessible(true);
449                    return f.get(instance);
450                } catch (Exception e) {
451                    if (el != null) {
452                        el.exceptionThrown(e);
453                    }
454                }
455                return null;
456            }
457        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.