KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > util > ReflectionUtils


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.util;
18
19 import java.lang.reflect.Field JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.lang.reflect.Modifier JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.LinkedList JavaDoc;
25 import java.util.List JavaDoc;
26
27 /**
28  * Simple utility class for handling reflection exceptions.
29  * Only intended for internal use.
30  *
31  * @author Juergen Hoeller
32  * @author Rob Harrop
33  * @author Rod Johnson
34  * @author Costin Leau
35  * @since 1.2.2
36  */

37 public abstract class ReflectionUtils {
38
39     /**
40      * Handle the given reflection exception. Should only be called if
41      * no checked exception is expected to be thrown by the target method.
42      * <p>Throws the underlying RuntimeException or Error in case of an
43      * InvocationTargetException with such a root cause. Throws an
44      * IllegalStateException with an appropriate message else.
45      * @param ex the reflection exception to handle
46      */

47     public static void handleReflectionException(Exception JavaDoc ex) {
48         if (ex instanceof NoSuchMethodException JavaDoc) {
49             throw new IllegalStateException JavaDoc("Method not found: " + ex.getMessage());
50         }
51         if (ex instanceof IllegalAccessException JavaDoc) {
52             throw new IllegalStateException JavaDoc("Could not access method: " + ex.getMessage());
53         }
54         if (ex instanceof InvocationTargetException JavaDoc) {
55             handleInvocationTargetException((InvocationTargetException JavaDoc) ex);
56         }
57         throw new IllegalStateException JavaDoc(
58                 "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage());
59     }
60
61     /**
62      * Handle the given invocation target exception. Should only be called if
63      * no checked exception is expected to be thrown by the target method.
64      * <p>Throws the underlying RuntimeException or Error in case of such
65      * a root cause. Throws an IllegalStateException else.
66      * @param ex the invocation target exception to handle
67      */

68     public static void handleInvocationTargetException(InvocationTargetException JavaDoc ex) {
69         if (ex.getTargetException() instanceof RuntimeException JavaDoc) {
70             throw (RuntimeException JavaDoc) ex.getTargetException();
71         }
72         if (ex.getTargetException() instanceof Error JavaDoc) {
73             throw (Error JavaDoc) ex.getTargetException();
74         }
75         throw new IllegalStateException JavaDoc(
76                 "Unexpected exception thrown by method - " + ex.getTargetException().getClass().getName() +
77                 ": " + ex.getTargetException().getMessage());
78     }
79
80     /**
81      * Attempt to find a {@link Method} on the supplied type with the supplied name
82      * and parameter types. Searches all superclasses up to <code>Object</code>.
83      * Returns <code>null</code> if no {@link Method} can be found.
84      */

85     public static Method JavaDoc findMethod(Class JavaDoc type, String JavaDoc name, Class JavaDoc[] paramTypes) {
86         Assert.notNull(type, "'type' cannot be null.");
87         Assert.notNull(name, "'name' cannot be null.");
88         Class JavaDoc searchType = type;
89         while(!Object JavaDoc.class.equals(searchType) && searchType != null) {
90             Method JavaDoc[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());
91             for (int i = 0; i < methods.length; i++) {
92                 Method JavaDoc method = methods[i];
93                 if(name.equals(method.getName()) && Arrays.equals(paramTypes, method.getParameterTypes())) {
94                     return method;
95                 }
96             }
97             searchType = searchType.getSuperclass();
98         }
99         return null;
100     }
101
102     /**
103      * Invoke the specified {@link Method} against the supplied target object
104      * with no arguments. The target object can be <code>null</code> when
105      * invoking a static {@link Method}.
106      * <p>Thrown exceptions are handled via a call to {@link #handleReflectionException}.
107      * @see #invokeMethod(java.lang.reflect.Method, Object, Object[])
108      */

109     public static Object JavaDoc invokeMethod(Method JavaDoc method, Object JavaDoc target) {
110         return invokeMethod(method, target, null);
111     }
112
113     /**
114      * Invoke the specified {@link Method} against the supplied target object
115      * with the supplied arguments. The target object can be <code>null</code>
116      * when invoking a static {@link Method}.
117      * <p>Thrown exceptions are handled via a call to {@link #handleReflectionException}.
118      * @see #invokeMethod(java.lang.reflect.Method, Object, Object[])
119      */

120     public static Object JavaDoc invokeMethod(Method JavaDoc method, Object JavaDoc target, Object JavaDoc[] args) {
121         try {
122             return method.invoke(target, args);
123         }
124         catch (IllegalAccessException JavaDoc ex) {
125             handleReflectionException(ex);
126             throw new IllegalStateException JavaDoc(
127                     "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage());
128         }
129         catch (InvocationTargetException JavaDoc ex) {
130             handleReflectionException(ex);
131             throw new IllegalStateException JavaDoc(
132                     "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage());
133         }
134     }
135
136     /**
137      * Determine whether the given field is a "public static final" constant.
138      * @param field the field to check
139      */

140     public static boolean isPublicStaticFinal(Field JavaDoc field) {
141         int modifiers = field.getModifiers();
142         return (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers));
143     }
144
145     /**
146      * Make the given field accessible, explicitly setting it accessible if necessary.
147      * The <code>setAccessible(true)</code> method is only called when actually necessary,
148      * to avoid unnecessary conflicts with a JVM SecurityManager (if active).
149      * @param field the field to make accessible
150      * @see java.lang.reflect.Field#setAccessible
151      */

152     public static void makeAccessible(Field JavaDoc field) {
153         if (!Modifier.isPublic(field.getModifiers()) ||
154                 !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
155             field.setAccessible(true);
156         }
157     }
158
159
160     /**
161      * Perform the given callback operation on all matching methods of the
162      * given class and superclasses.
163      * <p>The same named method occurring on subclass and superclass will
164      * appear twice, unless excluded by a {@link MethodFilter}.
165      * @param targetClass class to start looking at
166      * @param mc the callback to invoke for each method
167      * @see #doWithMethods(Class, MethodCallback, MethodFilter)
168      */

169     public static void doWithMethods(Class JavaDoc targetClass, MethodCallback mc) throws IllegalArgumentException JavaDoc {
170         doWithMethods(targetClass, mc, null);
171     }
172
173     /**
174      * Perform the given callback operation on all matching methods of the
175      * given class and superclasses.
176      * <p>The same named method occurring on subclass and superclass will
177      * appear twice, unless excluded by the specified {@link MethodFilter}.
178      * @param targetClass class to start looking at
179      * @param mc the callback to invoke for each method
180      * @param mf the filter that determines the methods to apply the callback to
181      */

182     public static void doWithMethods(Class JavaDoc targetClass, MethodCallback mc, MethodFilter mf)
183             throws IllegalArgumentException JavaDoc {
184
185         // Keep backing up the inheritance hierarchy.
186
do {
187             Method JavaDoc[] methods = targetClass.getDeclaredMethods();
188             for (int i = 0; i < methods.length; i++) {
189                 if (mf != null && !mf.matches(methods[i])) {
190                     continue;
191                 }
192                 try {
193                     mc.doWith(methods[i]);
194                 }
195                 catch (IllegalAccessException JavaDoc ex) {
196                     throw new IllegalStateException JavaDoc(
197                             "Shouldn't be illegal to access method '" + methods[i].getName() + "': " + ex);
198                 }
199             }
200             targetClass = targetClass.getSuperclass();
201         }
202         while (targetClass != null);
203     }
204
205     /**
206      * Get all declared methods on the leaf class and all superclasses.
207      * Leaf class methods are included first.
208      */

209     public static Method JavaDoc[] getAllDeclaredMethods(Class JavaDoc leafClass) throws IllegalArgumentException JavaDoc {
210         final List JavaDoc l = new LinkedList JavaDoc();
211         doWithMethods(leafClass, new MethodCallback() {
212             public void doWith(Method JavaDoc m) {
213                 l.add(m);
214             }
215         });
216         return (Method JavaDoc[]) l.toArray(new Method JavaDoc[l.size()]);
217     }
218
219     /**
220      * Invoke the given callback on all private fields in the target class,
221      * going up the class hierarchy to get all declared fields.
222      * @param targetClass the target class to analyze
223      * @param fc the callback to invoke for each field
224      */

225     public static void doWithFields(Class JavaDoc targetClass, FieldCallback fc) throws IllegalArgumentException JavaDoc {
226         doWithFields(targetClass, fc, null);
227     }
228
229     /**
230      * Invoke the given callback on all private fields in the target class,
231      * going up the class hierarchy to get all declared fields.
232      * @param targetClass the target class to analyze
233      * @param fc the callback to invoke for each field
234      * @param ff the filter that determines the fields to apply the callback to
235      */

236     public static void doWithFields(Class JavaDoc targetClass, FieldCallback fc, FieldFilter ff)
237             throws IllegalArgumentException JavaDoc {
238
239         // Keep backing up the inheritance hierarchy.
240
do {
241             // Copy each field declared on this class unless it's static or file.
242
Field JavaDoc[] fields = targetClass.getDeclaredFields();
243             for (int i = 0; i < fields.length; i++) {
244                 // Skip static and final fields.
245
if (ff != null && !ff.matches(fields[i])) {
246                     continue;
247                 }
248                 try {
249                     fc.doWith(fields[i]);
250                 }
251                 catch (IllegalAccessException JavaDoc ex) {
252                     throw new IllegalStateException JavaDoc(
253                             "Shouldn't be illegal to access field '" + fields[i].getName() + "': " + ex);
254                 }
255             }
256             targetClass = targetClass.getSuperclass();
257         }
258         while (targetClass != null && targetClass != Object JavaDoc.class);
259     }
260
261     /**
262      * Given the source object and the destination, which must be the same class
263      * or a subclass, copy all fields, including inherited fields. Designed to
264      * work on objects with public no-arg constructors.
265      * @throws IllegalArgumentException if the arguments are incompatible
266      */

267     public static void shallowCopyFieldState(final Object JavaDoc src, final Object JavaDoc dest) throws IllegalArgumentException JavaDoc {
268         if (src == null) {
269             throw new IllegalArgumentException JavaDoc("Source for field copy cannot be null");
270         }
271         if (dest == null) {
272             throw new IllegalArgumentException JavaDoc("Destination for field copy cannot be null");
273         }
274         if (!src.getClass().isAssignableFrom(dest.getClass())) {
275             throw new IllegalArgumentException JavaDoc("Destination class [" + dest.getClass().getName() +
276                     "] must be same or subclass as source class [" + src.getClass().getName() + "]");
277         }
278         doWithFields(src.getClass(), new ReflectionUtils.FieldCallback() {
279             public void doWith(Field JavaDoc field) throws IllegalArgumentException JavaDoc, IllegalAccessException JavaDoc {
280                 makeAccessible(field);
281                 Object JavaDoc srcValue = field.get(src);
282                 field.set(dest, srcValue);
283             }
284         }, ReflectionUtils.COPYABLE_FIELDS);
285     }
286
287
288     /**
289      * Action to take on each method.
290      */

291     public static interface MethodCallback {
292
293         /**
294          * Perform an operation using the given method.
295          * @param method the method which will have been made accessible before this invocation
296          */

297         void doWith(Method JavaDoc method) throws IllegalArgumentException JavaDoc, IllegalAccessException JavaDoc;
298     }
299
300
301     /**
302      * Callback optionally used to method fields to be operated on by a method callback.
303      */

304     public static interface MethodFilter {
305
306         /**
307          * Determine whether the given method matches.
308          * @param method the method to check
309          */

310         boolean matches(Method JavaDoc method);
311     }
312
313
314     /**
315      * Callback interface invoked on each field in the hierarchy.
316      */

317     public static interface FieldCallback {
318
319         /**
320          * Perform an operation using the given field.
321          * @param field the field which will have been made accessible before this invocation
322          */

323         void doWith(Field JavaDoc field) throws IllegalArgumentException JavaDoc, IllegalAccessException JavaDoc;
324     }
325
326
327     /**
328      * Callback optionally used to filter fields to be operated on by a field callback.
329      */

330     public static interface FieldFilter {
331
332         /**
333          * Determine whether the given field matches.
334          * @param field the field to check
335          */

336         boolean matches(Field JavaDoc field);
337     }
338
339
340     /**
341      * Pre-built FieldFilter that matches all non-static, non-final fields.
342      */

343     public static FieldFilter COPYABLE_FIELDS = new FieldFilter() {
344         public boolean matches(Field JavaDoc field) {
345             return !(Modifier.isStatic(field.getModifiers()) ||
346                     Modifier.isFinal(field.getModifiers()));
347         }
348     };
349
350 }
351
Popular Tags