View Javadoc

1   /*
2    * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/util/ReflectionUtil.java,v 1.16 2004/10/12 15:49:46 hkollmann Exp $
3    * $Revision: 1.16 $
4    * $Date: 2004/10/12 15:49:46 $
5    *
6    * DbForms - a Rapid Application Development Framework
7    * Copyright (C) 2001 Joachim Peer <joepeer@excite.com>
8    *
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public
11   * License as published by the Free Software Foundation; either
12   * version 2.1 of the License, or (at your option) any later version.
13   *
14   * This library is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22   */
23  
24  package org.dbforms.util;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  
29  import java.io.BufferedWriter;
30  import java.io.OutputStream;
31  import java.io.OutputStreamWriter;
32  import java.io.PrintWriter;
33  import java.io.StringWriter;
34  import java.io.Writer;
35  
36  import java.lang.reflect.Constructor;
37  import java.lang.reflect.Field;
38  import java.lang.reflect.Method;
39  import java.lang.reflect.Modifier;
40  
41  
42  
43  /***
44   * ReflectionUtil class
45   *
46   * @author Luca Fossato
47   * @created 20 novembre 2002
48   */
49  public class ReflectionUtil {
50     /*** log4j category */
51     private static Log logCat = LogFactory.getLog(ReflectionUtil.class);
52  
53     /***
54      * Invokes the underlying method represented by this Method object, on the
55      * specified object with the specified parameters. <br>
56      * Individual parameters are automatically unwrapped to match primitive
57      * formal parameters, and both primitive and reference parameters are
58      * subject to widening conversions as necessary. <br>
59      * The value returned by the underlying method is automatically wrapped in
60      * an object if it has a primitive type.
61      *
62      * @param className              the object class name
63      * @param methodName   the arguments classes for the object method
64      * @param argsTypes        the arguments values for the object constructor
65      * @param args DOCUMENT ME!
66      *
67      * @return If the method completes normally, the value it returns is
68      *         returned to the caller of invoke; if the value has a primitive
69      *         type, it is first appropriately wrapped in an object. If the
70      *         underlying method return type is void, the invocation returns
71      *         null.
72      *
73      * @exception Exception if any error occurs
74      */
75     public static Object invoke(String   className,
76                                 String   methodName,
77                                 Class[]  argsTypes,
78                                 Object[] args) throws Exception {
79        Class  c = Class.forName(className);
80        Method m = c.getDeclaredMethod(methodName, argsTypes);
81        Object i = c.newInstance();
82        Object r = m.invoke(i, args);
83  
84        return r;
85     }
86  
87  
88     /***
89      * Return the object having the input class name
90      * @param className              the object class name
91      *
92      * @return the instanced object
93      *
94      * @exception Exception if any error occurs
95      */
96     public static Object newInstance(String className) throws Exception {
97        Class myClass = Class.forName(className);
98        return myClass.newInstance();
99     }
100 
101 
102    /***
103     * Return the object having the input class name, instanced with the
104     * constructor having the <code>constructorArgsTypes</code> arguments.
105     *
106     * @param className              the object class name
107     * @param constructorArgsTypes   the object constructor arguments classes
108     * @param constructorArgs        the object constructor arguments values
109     *
110     * @return the instanced object
111     *
112     * @exception Exception if any error occurs
113     */
114    public static Object newInstance(String   className,
115                                     Class[]  constructorArgsTypes,
116                                     Object[] constructorArgs)
117                              throws Exception {
118       Class myClass = Class.forName(className);
119 
120       return newInstance(myClass, constructorArgsTypes, constructorArgs);
121    }
122 
123 
124    /***
125     * Return the object having the input class name, instanced with the
126     * constructor having the <code>constructorArgsTypes</code> arguments.
127     *
128     * @param clazz              the object class name
129     * @param constructorArgsTypes   the object constructor arguments classes
130     * @param constructorArgs        the object constructor arguments values
131     *
132     * @return the instanced object
133     *
134     * @exception Exception if any error occurs
135     */
136    public static Object newInstance(Class    clazz,
137                                     Class[]  constructorArgsTypes,
138                                     Object[] constructorArgs)
139                              throws Exception {
140       Constructor myConstructor = clazz.getConstructor(constructorArgsTypes);
141 
142       return myConstructor.newInstance(constructorArgs);
143    }
144 
145 
146    /***
147     * Reflect the input class state.
148     *
149     * @param name Description of the Parameter
150     * @param os Description of the Parameter
151     */
152    public static void reflectClass(String       name,
153                                    OutputStream os) {
154       Writer w = new BufferedWriter(new OutputStreamWriter(os));
155       reflectClass(name, w);
156    }
157 
158 
159    /***
160     * Reflect the input class state.
161     *
162     * @param name Description of the Parameter
163     * @param w Description of the Parameter
164     */
165    public static void reflectClass(String name,
166                                    Writer w) {
167       Class c = null;
168 
169       try {
170          c = Class.forName(name);
171          reflectClass(c.newInstance(), false, w);
172       } catch (Exception e) {
173          logCat.error("Class " + name + " is not found.");
174 
175          return;
176       }
177    }
178 
179 
180    /***
181     * Reflect the input object state.
182     *
183     * @param o Description of the Parameter
184     * @param os Description of the Parameter
185     */
186    public static void reflectObject(Object       o,
187                                     OutputStream os) {
188       Writer w = new BufferedWriter(new OutputStreamWriter(os));
189       reflectClass(o, true, w);
190    }
191 
192 
193    /***
194     * Reflect the input object state.
195     *
196     * @param o Description of the Parameter
197     * @param w Description of the Parameter
198     */
199    public static void reflectObject(Object o,
200                                     Writer w) {
201       reflectClass(o, true, w);
202    }
203 
204 
205    /***
206     * Get the String representation of the input object
207     *
208     * @param o  the object to introspect
209     *
210     * @return the String representation of the input object
211     */
212    public static String toString(Object o) {
213       StringWriter   sw = new StringWriter();
214       BufferedWriter bw = new BufferedWriter(new PrintWriter(sw));
215       String         s  = null;
216 
217       reflectObject(o, bw);
218       s = sw.getBuffer()
219             .toString();
220 
221       try {
222          sw.close();
223       } catch (Exception e) {
224          logCat.error("::toString - cannot close the writer object", e);
225       }
226 
227       return s;
228    }
229 
230 
231    /***
232     * Get the String representation of the class having the input full
233     * qualified name.
234     *
235     * @param c  the full qualified name of the class to introspect
236     *
237     * @return the String representation of the input object
238     */
239    public static String toString(String c) {
240       StringWriter   sw = new StringWriter();
241       BufferedWriter bw = new BufferedWriter(new PrintWriter(sw));
242       String         s  = null;
243 
244       reflectClass(c, bw);
245       s = sw.getBuffer()
246             .toString();
247 
248       try {
249          sw.close();
250       } catch (Exception e) {
251          logCat.error("::toString - cannot close the writer object", e);
252       }
253 
254       return s;
255    }
256 
257 
258    /***
259     * Gets the typeName attribute of the input class
260     *
261     * @param c Description of the Parameter
262     *
263     * @return The typeName value
264     */
265    private static String getTypeName(Class c) {
266       if (c.isArray()) {
267          try {
268             Class cl         = c;
269             int   dimensions = 0;
270 
271             while (cl.isArray()) {
272                dimensions++;
273                cl = cl.getComponentType();
274             }
275 
276             StringBuffer sb = new StringBuffer();
277 
278             sb.append(cl.getName());
279 
280             for (int i = 0; i < dimensions; i++)
281                sb.append("[]");
282 
283             return sb.toString();
284          } catch (Throwable e) {
285             logCat.error("::getTypeName - cannot get the class type", e);
286          }
287       }
288 
289       return c.getName();
290    }
291 
292 
293    /***
294     * Get the class constructors.
295     *
296     * @param pw Description of the Parameter
297     * @param c Description of the Parameter
298     */
299    private static void listClassConstructors(PrintWriter pw,
300                                              Class       c) {
301       Constructor[] constructors = c.getDeclaredConstructors();
302 
303       for (int i = 0; i < constructors.length; i++) {
304          if (i == 0) {
305             pw.println("  // Constructors");
306          }
307 
308          pw.print("  " + Modifier.toString(constructors[i].getModifiers())
309                   + " " + constructors[i].getName() + "(");
310 
311          listParameters(pw, constructors[i].getParameterTypes());
312          pw.println(");");
313       }
314 
315       if (constructors.length > 0) {
316          pw.println();
317       }
318    }
319 
320 
321    /***
322     * Get the class methods
323     *
324     * @param pw Description of the Parameter
325     * @param c Description of the Parameter
326     */
327    private static void listClassMethods(PrintWriter pw,
328                                         Class       c) {
329       Method[] methods = c.getDeclaredMethods();
330 
331       for (int i = 0; i < methods.length; i++) {
332          if (i == 0) {
333             pw.println("  // Methods");
334          }
335 
336          pw.print("  " + Modifier.toString(methods[i].getModifiers()) + " "
337                   + getTypeName(methods[i].getReturnType()) + " "
338                   + methods[i].getName() + "(");
339 
340          listParameters(pw, methods[i].getParameterTypes());
341          pw.println(");");
342       }
343    }
344 
345 
346    /***
347     * Get the class variables
348     *
349     * @param pw         Description of the Parameter
350     * @param o          Description of the Parameter
351     * @param dumpValues Description of the Parameter
352     *
353     * @throws Exception DOCUMENT ME!
354     */
355    private static void listClassVariables(PrintWriter pw,
356                                           Object      o,
357                                           boolean     dumpValues)
358                                    throws Exception {
359       if (o != null) {
360          Class   c      = o.getClass();
361          Field[] fields = c.getDeclaredFields();
362 
363          for (int i = 0; i < fields.length; i++) {
364             if (i == 0) {
365                pw.println("  // Variables");
366             }
367 
368             // Only take those that belong to this class
369             pw.print("  " + Modifier.toString(fields[i].getModifiers()) + " "
370                      + getTypeName(fields[i].getType()) + " "
371                      + fields[i].getName()); //+ ";");
372 
373             // try to get the field value;
374             if (dumpValues) {
375                Field  f      = fields[i];
376                String fValue = null;
377 
378                if (f.isAccessible()) {
379                   fValue = f.get(o)
380                             .toString();
381                } else {
382                   try {
383                      f.setAccessible(true);
384                      fValue = f.get(o)
385                                .toString();
386                      f.setAccessible(false);
387                   } catch (Exception e) {
388                      fValue = "NOT ACCESSIBLE";
389                   }
390                }
391 
392                pw.print(" = [ " + fValue + " ]");
393             }
394 
395             pw.println(";");
396          }
397 
398          if (fields.length > 0) {
399             pw.println();
400          }
401       }
402    }
403 
404 
405    /***
406     * Get the type of the class parameters
407     *
408     * @param pw Description of the Parameter
409     * @param parameters Description of the Parameter
410     */
411    private static void listParameters(PrintWriter pw,
412                                       Class[]     parameters) {
413       for (int j = 0; j < parameters.length; j++) {
414          pw.print(getTypeName(parameters[j]));
415 
416          if (j < (parameters.length - 1)) {
417             pw.print(", ");
418          }
419       }
420    }
421 
422 
423    /***
424     * PRIVATE methods here
425     *
426     * @param o DOCUMENT ME!
427     * @param dumpValues DOCUMENT ME!
428     * @param w DOCUMENT ME!
429     */
430    /***
431     * Reflect the input class state.
432     *
433     * @param o Description of the Parameter
434     * @param dumpValues DOCUMENT ME!
435     * @param w Description of the Parameter
436     */
437    private static void reflectClass(Object  o,
438                                     boolean dumpValues,
439                                     Writer  w) {
440       PrintWriter pw = new PrintWriter(w);
441       Class       c = o.getClass();
442 
443       // Print Declaration
444       pw.println(Modifier.toString(c.getModifiers()) + " " + c.getName());
445 
446       // Print Superclass
447       if (c.getSuperclass() != null) {
448          pw.print("  extends " + c.getSuperclass().getName());
449       }
450 
451       // Print interfaces
452       Class[] interfaces = c.getInterfaces();
453 
454       for (int i = 0; i < interfaces.length; i++) {
455          if (i == 0) {
456             pw.print(" implements ");
457          } else {
458             pw.print(", ");
459          }
460 
461          pw.print(interfaces[i].getName());
462       }
463 
464       pw.println("\n{");
465 
466       try {
467          listClassVariables(pw, o, dumpValues);
468       } catch (Exception e) {
469          logCat.error("::reflectClass - cannot list the class variables", e);
470       }
471 
472       listClassConstructors(pw, c);
473       listClassMethods(pw, c);
474 
475       pw.println("\n}");
476       pw.flush();
477    }
478 }