KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > nightlabs > util > reflect > ReflectUtil


1 /* ************************************************************************** *
2  * Copyright (C) 2004 NightLabs GmbH, Marco Schulze *
3  * All rights reserved. *
4  * http://www.NightLabs.de *
5  * *
6  * This program and the accompanying materials are free software; you can re- *
7  * distribute it and/or modify it under the terms of the GNU General Public *
8  * License as published by the Free Software Foundation; either ver 2 of the *
9  * License, or any later version. *
10  * *
11  * This module is distributed in the hope that it will be useful, but WITHOUT *
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FIT- *
13  * NESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more *
14  * details. *
15  * *
16  * You should have received a copy of the GNU General Public License along *
17  * with this module; if not, write to the Free Software Foundation, Inc.: *
18  * 59 Temple Place, Suite 330 *
19  * Boston MA 02111-1307 *
20  * USA *
21  * *
22  * Or get it online: *
23  * http://www.opensource.org/licenses/gpl-license.php *
24  * *
25  * In case, you want to use this module or parts of it in a proprietary pro- *
26  * ject, you can purchase it under the NightLabs Commercial License. Please *
27  * contact NightLabs GmbH under info AT nightlabs DOT com for more infos or *
28  * visit http://www.NightLabs.com *
29  * ************************************************************************** */

30
31 /*
32  * Project: NightLabsBase
33  * Copyright: Copyright (c) 2004
34  * Company: NightLabs GmbH (Germany)
35  * Author: Daniel Mazurek
36  * Creation Date: 13.08.2004
37  */

38
39 package com.nightlabs.util.reflect;
40
41 import java.lang.reflect.Array JavaDoc;
42 import java.lang.reflect.Field JavaDoc;
43 import java.lang.reflect.InvocationTargetException JavaDoc;
44 import java.lang.reflect.Method JavaDoc;
45 import java.lang.reflect.Modifier JavaDoc;
46 import java.util.ArrayList JavaDoc;
47 import java.util.HashMap JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.List JavaDoc;
50 import java.util.Map JavaDoc;
51
52
53 /**
54  * @author Daniel Mazurek
55  * @author Marc Klinger - marc at nightlabs dot de (API documentation fixes)
56  */

57 public class ReflectUtil
58 {
59
60     public ReflectUtil()
61     {
62         super();
63     }
64
65     /**
66      * Does the same as {@link com.nightlabs.util.reflect.ReflectUtil#clone(Object original, Class stopClass)}
67      * but has Object.class as stopClass
68      *
69      * @param original The instance to clone
70      * @return a cloned instance of the Param original
71      * @see #clone(Object original, Class stopClass)
72      */

73     public static Object JavaDoc clone(Object JavaDoc original) {
74         return clone(original, Object JavaDoc.class);
75     }
76
77     public static Object JavaDoc clone(Object JavaDoc original, String JavaDoc[] ignoredMembers) {
78         return clone(original, Object JavaDoc.class, ignoredMembers);
79     }
80     
81     public static Object JavaDoc clone(Object JavaDoc original, Class JavaDoc[] cloneDelegates) {
82         return clone(original, Object JavaDoc.class, null, cloneDelegates);
83     }
84     
85     public static Object JavaDoc clone(Object JavaDoc original, String JavaDoc[] ignoredMembers, Class JavaDoc[] cloneDelegtes) {
86         return clone(original, Object JavaDoc.class, ignoredMembers, cloneDelegtes);
87     }
88     
89     public static Map JavaDoc initCloneDelegates(Class JavaDoc[] cloneDelegates)
90     throws CloneException
91     {
92         Map JavaDoc class2CloneDelegate = new HashMap JavaDoc(cloneDelegates.length);
93         for (int i=0; i<cloneDelegates.length; ++i) {
94             Class JavaDoc cdClass = cloneDelegates[i];
95             if (CloneDelegate.class.isAssignableFrom(cdClass)) {
96                 try {
97                     Method JavaDoc getCloneClass = cdClass.getMethod("getCloneClass", null);
98                     Class JavaDoc cloneClass = (Class JavaDoc) getCloneClass.invoke(null, null);
99                     class2CloneDelegate.put(cloneClass, cdClass);
100                 }
101                 catch (SecurityException JavaDoc e) {
102                     throw new CloneException(e);
103                 }
104                 catch (NoSuchMethodException JavaDoc e) {
105                     throw new CloneException(e);
106                 }
107                 catch (IllegalArgumentException JavaDoc e) {
108                     throw new CloneException(e);
109                 }
110                 catch (IllegalAccessException JavaDoc e) {
111                     throw new CloneException(e);
112                 }
113                 catch (InvocationTargetException JavaDoc e) {
114                     throw new CloneException(e);
115                 }
116             }
117         }
118         return class2CloneDelegate;
119     }
120     
121   public static Object JavaDoc clone(Object JavaDoc original,
122                                              Class JavaDoc stopClass,
123                                              String JavaDoc[] ignoredMembers,
124                                              Class JavaDoc[] cloneDelegates)
125   {
126     try
127     {
128         Class JavaDoc orgClass = original.getClass();
129         List JavaDoc fields = collectAllFields(orgClass, stopClass, true, ignoredMembers);
130         boolean cloneDelegate = false;
131         HashMap JavaDoc class2CloneDelegate = new HashMap JavaDoc(0);
132         if (cloneDelegates != null) {
133             class2CloneDelegate = new HashMap JavaDoc(initCloneDelegates(cloneDelegates));
134             cloneDelegate = true;
135         }
136         
137         try
138             {
139             // Iterate through all collected fields (except static and final)
140
// and clone the values for the created instance
141
Object JavaDoc dcInstance = orgClass.newInstance();
142             for (Iterator JavaDoc it = fields.iterator(); it.hasNext(); )
143             {
144                 Field JavaDoc field = (Field JavaDoc) it.next();
145                 Class JavaDoc fieldType = field.getType();
146                 
147                 // if a CloneDelegate is registered
148
if (cloneDelegate && class2CloneDelegate.containsKey(fieldType))
149                 {
150                     Class JavaDoc cdClass = (Class JavaDoc) class2CloneDelegate.get(fieldType);
151                     Method JavaDoc clone = cdClass.getMethod("clone", new Class JavaDoc[] {fieldType});
152                     Object JavaDoc clonedField = clone.invoke(cdClass.newInstance(), new Object JavaDoc[] {field.get(dcInstance)});
153                     field.set(dcInstance, clonedField);
154                 }
155                 // check if primitive
156
else if (fieldType.isPrimitive())
157                 {
158                     field.set(dcInstance, field.get(original));
159                 }
160                 // check if Array
161
else if (fieldType.isArray())
162                 {
163                     Object JavaDoc array = field.get(original);
164                     if (array == null)
165                         continue;
166                     
167                     int length = Array.getLength(array);
168                     Class JavaDoc arrayType = array.getClass();
169                     Object JavaDoc clonedArray = Array.newInstance(arrayType.getComponentType(), length);
170                     for (int i=0; i<length; ++i) {
171                         Object JavaDoc value = Array.get(array, i);
172                         Array.set(clonedArray, i, value);
173                     }
174                     field.set(dcInstance, clonedArray);
175                 }
176                 // check if Cloneable
177
else if (Cloneable JavaDoc.class.isAssignableFrom(fieldType))
178                 {
179                     Object JavaDoc org = field.get(original);
180                     field.set(dcInstance,
181                         org.getClass().getMethod(CLONE, null).invoke(org, null)
182                     );
183                 }
184                 else
185                     throw new IllegalStateException JavaDoc("Not all members are primitive or Cloneable! Class=\""+original.getClass().getName()+"\" Member=\""+field.getType().getName()+" "+field.getName()+"\"");
186             }
187             return dcInstance;
188             }
189         catch (NoSuchMethodException JavaDoc e) {
190                 throw new CloneException(e);
191             }
192         catch (IllegalAccessException JavaDoc e) {
193                 throw new CloneException(e);
194             }
195         catch (InstantiationException JavaDoc e) {
196                 throw new CloneException(e);
197             }
198         catch (InvocationTargetException JavaDoc e) {
199                 throw new CloneException(e);
200             }
201         }
202         catch (CloneException x) {
203             throw new RuntimeException JavaDoc(x);
204         }
205   }
206  
207   private static String JavaDoc CLONE = "clone";
208   public static Object JavaDoc clone(Object JavaDoc original,
209                                                      Class JavaDoc stopClass,
210                                                          String JavaDoc[] ignoredMembers)
211     {
212     return clone(original, stopClass, ignoredMembers, null);
213 // try
214
// {
215
// Class orgClass = original.getClass();
216
// List fields = collectAllFields(orgClass, stopClass, true, ignoredMembers);
217
//
218
// // Iterate through all collected fields (except static and final)
219
// // and clone the values for the created instance
220
// Object dcInstance = orgClass.newInstance();
221
// for (Iterator it = fields.iterator(); it.hasNext(); )
222
// {
223
// Field field = (Field) it.next();
224
// // check if primitive
225
// if (field.getType().isPrimitive())
226
// {
227
// field.set(dcInstance, field.get(original));
228
// }
229
// // check if Array
230
// else if (field.getType().isArray())
231
// {
232
// Object array = field.get(original);
233
// int length = Array.getLength(array);
234
// Class arrayType = array.getClass();
235
// Object clonedArray = Array.newInstance(arrayType.getComponentType(), length);
236
// for (int i=0; i<length; ++i) {
237
// Object value = Array.get(array, i);
238
// Array.set(clonedArray, i, value);
239
// }
240
// field.set(dcInstance, clonedArray);
241
// }
242
// // check if Cloneable
243
// else if (Cloneable.class.isAssignableFrom(field.getType()))
244
// {
245
// Object org = field.get(original);
246
// field.set(dcInstance,
247
// org.getClass().getMethod(CLONE, null).invoke(org, null)
248
// );
249
// }
250
// else
251
// throw new IllegalStateException("Not all members are primitive or Cloneable! Class=\""+original.getClass().getName()+"\" Member=\""+field.getType().getName()+" "+field.getName()+"\"");
252
// }
253
// return dcInstance;
254
// }
255
// catch (Exception x) {
256
// throw new RuntimeException(x);
257
// }
258
}
259
260     
261   /**
262    * a generic clone-Method for all Classes based on java.lang.reflect.
263    * <p>
264    * The basic Mechanism works as following:
265    * This methods iterates through all superClasses and collects,
266    * all declared Fields (private, protected, public)
267    * until it reaches the stopClass. Then it creates a new Instance
268    * of the original class (a standard Constructor is needed) and
269    * clones the values of all fields (except FINAL and STATIC) to
270    * the new instance. If one field is not a primitive Type (int, boolean, ...)
271    * it has to implement the Cloneable Interface, otherwise a
272    * IllegalStateException is thrown.
273    *
274    * @throws IllegalStateException if a field is not primitive and
275    * does not implement Cloneable
276    * @throws RuntimeException if something else went wrong
277    * (e.g. InstantationException, when no Standard Constructor exists, ...)
278    * @param original The Object to be cloned
279    * @param stopClass The Class where the cloning should stop
280    * @return An cloned Instance of the original class (original.getClass())
281    * which fields have the same values as the original instance *
282    * @see java.lang.Class
283    * @see java.lang.Cloneable
284    */

285   public static Object JavaDoc clone(Object JavaDoc original, Class JavaDoc stopClass)
286   {
287     return clone(original, stopClass, null);
288 // try {
289
// Class orgClass = original.getClass();
290
// List fields = collectAllFields(orgClass, stopClass, true, null);
291
//
292
// // Iterate through all collected fields (except static and final)
293
// // and clone the values for the created instance
294
// Object dcInstance = orgClass.newInstance();
295
// for (Iterator it = fields.iterator(); it.hasNext(); ) {
296
// Field field = (Field) it.next();
297
// if (field.getType().isPrimitive()) {
298
// field.set(dcInstance, field.get(original));
299
// }
300
// else if (field.getType().isArray())
301
// {
302
// Object array = field.get(original);
303
// int length = Array.getLength(array);
304
// Class arrayType = array.getClass();
305
// Object clonedArray = Array.newInstance(arrayType.getComponentType(), length);
306
// for (int i=0; i<length; ++i) {
307
// Object value = Array.get(array, i);
308
// Array.set(clonedArray, i, value);
309
// }
310
// field.set(dcInstance, clonedArray);
311
// }
312
// else if (Cloneable.class.isAssignableFrom(field.getType()))
313
// {
314
// Object org = field.get(original);
315
// field.set(dcInstance,
316
// org.getClass().getMethod(CLONE, null).invoke(org, null)
317
// );
318
// }
319
// else
320
// throw new IllegalStateException("Not all members are primitive or Cloneable! Class=\""+original.getClass().getName()+"\" Member=\""+field.getType().getName()+" "+field.getName()+"\"");
321
// }
322
// return dcInstance;
323
// } catch (Exception x) {
324
// throw new RuntimeException(x);
325
// }
326
}
327   
328   /**
329    * collects recursivly all Fields for a certain class (originalClass)
330    * until a certain superClass is reached (stopClass)
331    *
332    * @param originalClass the Class to inspect
333    * @param stopClass the superClass where to stop
334    * @param ignoreFields determines if static and final fields should be ignored
335    * @return a List of all collected fields
336    * @see java.lang.reflect.Field
337    */

338   public static List JavaDoc collectAllFields(Class JavaDoc originalClass,
339                                                                         Class JavaDoc stopClass,
340                                                                             boolean ignoreFields,
341                                                                             String JavaDoc[] ignoredMembers)
342   {
343     List JavaDoc fields = new ArrayList JavaDoc();
344     Class JavaDoc superClass = originalClass;
345     
346     // iterate through all superclasses and
347
// collect all declared fields (public, private, protected)
348
// until the stopClass is reached
349
while (superClass != stopClass)
350     {
351         Field JavaDoc[] f = superClass.getDeclaredFields();
352             if (ignoreFields) {
353             for (int i = 0; i < f.length; ++i) {
354                 if (ignoreField(f[i]))
355                     continue;
356                 else if (ignoreMembers(f[i], ignoredMembers))
357                     continue;
358                 else {
359                     Field JavaDoc field = f[i];
360                     // makes also private Fields accessible
361
field.setAccessible(true);
362                     fields.add(field);
363                 }
364             }
365             }
366             else {
367             for (int i = 0; i < f.length; ++i)
368             {
369                 Field JavaDoc field = f[i];
370                 if (ignoreMembers(field, ignoredMembers))
371                     continue;
372                 // makes also private Fields accessible
373
field.setAccessible(true);
374                 fields.add(field);
375             }
376             }
377         superClass = superClass.getSuperclass();
378     }
379     return fields;
380   }
381   
382   /**
383    * Does the same as {@link #collectAllFields(Class, Class, boolean, String[])}
384    * but has java.lang.Object.class as stopClass and doesn't ignore any fields
385    *
386    * @param originalClass The Class for which all Fields should be collected
387    * @param ignoreFields determines if static and final fields should be ignored
388    * @return a List of all declaredFields for the originalClass
389    * @see #collectAllFields(Class, Class, boolean, String[])
390    */

391   public static List JavaDoc collectAllFields(Class JavaDoc originalClass, boolean ignoreFields) {
392     return collectAllFields(originalClass, Object JavaDoc.class, ignoreFields, null);
393   }
394   
395     /**
396      * ignores all members/fields that are static or final.
397      * This method is used to check that.
398      *
399      * @param field Ignore this field?
400      * @return true if the field should be ignored, false if not.
401      */

402     private static boolean ignoreField(Field JavaDoc field)
403     {
404         int modifiers = field.getModifiers();
405         
406         if ((modifiers & Modifier.STATIC) != 0)
407             return true;
408         
409         if ((modifiers & Modifier.FINAL) != 0)
410             return true;
411                 
412         return false;
413     }
414    
415     private static boolean ignoreMembers(Field JavaDoc field, String JavaDoc[] names)
416     {
417         if (names == null)
418             return false;
419             
420         for (int i=0; i<names.length; ++i) {
421             String JavaDoc name = names[i];
422             if (field.getName().equals(name))
423                 return true;
424         }
425         return false;
426     }
427     
428     /**
429      * a generic equals-Method for all Classes based on java.lang.reflect
430      *
431      * @param original The original Instance which should be compared
432      * @param target The target Instance which will be compared with the original
433      * @return true if the values for all Fields of both instances are equivalent,
434      * otherwise returns false
435      * @see java.lang.reflect.Field
436      * @see #collectAllFields(Class originalClass, boolean ignoreFields)
437      */

438     public static boolean equals(Object JavaDoc original, Object JavaDoc target)
439     {
440         if (original == target)
441             return true;
442         
443         Class JavaDoc originalClass = original.getClass();
444         Class JavaDoc targetClass = target.getClass();
445         
446         if (!originalClass.isAssignableFrom(targetClass))
447             return false;
448         
449         List JavaDoc originalFields = collectAllFields(originalClass, true);
450         List JavaDoc targetFields = collectAllFields(targetClass, true);
451         
452         if (originalFields.size() != targetFields.size())
453             return false;
454             
455         for (int i=0; i<originalFields.size(); ++i)
456         {
457             Field JavaDoc originalField = (Field JavaDoc) originalFields.get(i);
458             Field JavaDoc targetField = (Field JavaDoc) targetFields.get(i);
459             try {
460                 if (!originalField.get(original).equals(targetField.get(target)))
461                     return false;
462             }
463             catch (IllegalArgumentException JavaDoc e) {
464                 e.printStackTrace();
465             }
466             catch (IllegalAccessException JavaDoc e) {
467                 e.printStackTrace();
468             }
469         }
470
471         return true;
472     }
473     
474     /**
475      * a generic toString()-Method which print outs all Fieldnames and
476      * the corresponding values for an arbitary instance
477      *
478      * @param o the target instance
479      * @param withSuperClasses determines if the fields
480      * for all superclasses should be displayed as well
481      * @return a String which contains the Classname and all Fieldnames
482      * with the corresponding values
483      */

484     public static String JavaDoc toString(Object JavaDoc o, boolean withSuperClasses)
485     {
486         Class JavaDoc oClass = o.getClass();
487         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
488         // add Class Name
489
sb.append(oClass.getName());
490         sb.append("\n");
491         if (withSuperClasses)
492         {
493             List JavaDoc fields = collectAllFields(oClass, false);
494             for (Iterator JavaDoc it = fields.iterator(); it.hasNext(); ) {
495                 Field JavaDoc field = (Field JavaDoc) it.next();
496                 try {
497                     sb.append(field.getName());
498                     sb.append(" = ");
499                     sb.append(field.get(o).toString());
500                     sb.append("\n");
501                 }
502                 catch (IllegalArgumentException JavaDoc e) {
503                     e.printStackTrace();
504                 }
505                 catch (IllegalAccessException JavaDoc e) {
506                     e.printStackTrace();
507                 }
508             }
509         }
510         else {
511             Field JavaDoc[] fields = oClass.getDeclaredFields();
512             for (int i=0; i<fields.length; ++i) {
513                 Field JavaDoc field = fields[i];
514                 field.setAccessible(true);
515                 try {
516                     sb.append(field.getName());
517                     sb.append(" = ");
518                     sb.append(field.get(o).toString());
519                     sb.append("\n");
520                 }
521                 catch (IllegalArgumentException JavaDoc e) {
522                     e.printStackTrace();
523                 }
524                 catch (IllegalAccessException JavaDoc e) {
525                     e.printStackTrace();
526                 }
527             }
528         }
529         return sb.toString();
530     }
531   
532 }
533
Popular Tags