View Javadoc

1   /*******************************************************************************
2    *  Copyright (c) 2005, 2006, 2007 Imola Informatica.
3    *  All rights reserved. This program and the accompanying materials
4    *  are made available under the terms of the LGPL License v2.1
5    *  which accompanies this distribution, and is available at
6    *  http://www.gnu.org/licenses/lgpl.html
7    *******************************************************************************/
8   package it.imolinfo.jbi4ejb.webservice.generator;
9   
10  import it.imolinfo.jbi4ejb.Logger;
11  import it.imolinfo.jbi4ejb.LoggerFactory;
12  
13  import java.lang.reflect.Field;
14  import java.lang.reflect.Method;
15  import java.util.ArrayList;
16  import java.util.List;
17  import java.util.Set;
18  
19  /**
20   * Provides the methods used to visit a class and collect all the data types
21   * used as field, method parameter, exception and return type.
22   */
23  final class UtilClassCollector {
24  
25      /**
26       * Logger for the class.
27       */
28      private static final Logger LOG = LoggerFactory
29              .getLogger(UtilClassCollector.class);
30      
31      
32      /**
33       * Instantiates a new util class collector.
34       */
35      private UtilClassCollector() {}
36  
37      /**
38       * Provides the methods used to visit a class and collect all the data types
39       * used as field, method parameter, exception and return type.
40       *
41       * @param        result       The container for the class collected.
42       * @param        clazz        The new class to visit.
43       *
44       * @return    The updated class collection.
45       */
46      @SuppressWarnings("unchecked")
47      static Set<Class> visitClassCollector(Set<Class> result, Class clazz) {
48  
49          Set<Class> returnedResult = result;
50          
51          if (skipClassColletor(result, clazz)) {
52  
53              LOG.debug("DON'T Collect[" + clazz + "]");
54  
55          } else {
56  
57              List<Class> types = null;
58  
59              // multi dimensional array ?
60              if (clazz.isArray()) {
61                  LOG.debug("Found an array:" + clazz);
62  
63                  returnedResult = visitClassCollector(result, clazz.getComponentType());
64  
65              } else {
66                  result.add(clazz);
67                  LOG.debug("Collect[" + clazz + "]");
68  
69                  types = extractTypes(clazz);
70  
71                  for (Class currentType : types) {
72                      returnedResult = visitClassCollector(result, currentType);
73                  }
74              }
75  
76          }
77  
78          return returnedResult;
79      }
80  
81      /**
82       * This method decides if a class must be visited or not.
83       *
84       * @param    result    The container for the class collection.
85       * @param    clazz   The class to visit.
86       *
87       * @return    true: if clazz is null
88       *                  or clazz is already visited
89       *                  or clazz is in java.*, javax.*, org.omg.*
90       *                  or clazz is a java primitives data types
91       *                  or an array.
92       */
93      @SuppressWarnings("unchecked")
94      protected static boolean skipClassColletor(Set<Class> result, Class clazz) {
95          if ((clazz == null) 
96                  || (contains(result, clazz))){
97              return true;
98          }
99  
100         String name = clazz.getCanonicalName();
101         // if java, javax, org.omg or primitive
102         if ((name.startsWith("java.") || name.startsWith("javax.") ||
103                 name.startsWith("org.omg.")) 
104                 || (clazz.isPrimitive()) ) {
105             return true;
106         }
107         
108         return false;
109     }
110 
111     /**
112      * Return true if the class is contained in the set.
113      * 
114      * @param result
115      *          The classes set
116      * @param clazz
117      *          The class to search for
118      * 
119      * @return true, if the class is contained in the set.
120      */
121     @SuppressWarnings("unchecked")
122     protected static boolean contains(Set<Class> result, Class clazz) {
123         if (result == null) {
124             return false;
125         }
126         // else
127         String className = null;
128         if (clazz != null) {
129             className = clazz.getCanonicalName();
130         } 
131 
132         for (Class item : result) {
133             String itemClassName = item.getCanonicalName();
134 
135             if (itemClassName.equals(className)) {
136                 return true;
137             }
138         }
139 
140         return false;
141     }
142 
143     /**
144      * This method extracts all the data types used in the class.
145      * (Fields and parameter, Excecption, return for each method).
146      *
147      * @param    clazz    The class inspected.
148      *
149      * @return    The list of class cllected. (never null).
150      */
151     @SuppressWarnings("unchecked")
152     public static List<Class> extractTypes(Class clazz) {
153         List<Class> types = new ArrayList<Class>();
154 
155         //types = exctraxtTypesFromConstructor(clazz, types);
156         types = extractTypesFromMethods(clazz, types);
157         types = extractTypesFromFields(clazz, types);
158 
159         return types;
160     }
161 
162     /**
163      * This method extracts the type of each public field of the class.
164      * (protected and private field are ignored.)
165      *
166      * @param        clazz    The class to visit.
167      * @param        types    The data types already collected.
168      *
169      * @return    The data types collection updated.
170      */
171     @SuppressWarnings("unchecked")
172     private static List<Class> extractTypesFromFields(Class clazz,
173             List<Class> types) {
174 
175         Field[] fields = clazz.getFields();
176         if (fields == null) {
177             return types;
178         }
179         // else
180         for (Field currField : fields) {
181             Class ft = currField.getType();
182             if (!types.contains(ft)) {
183                 types.add(ft);
184             }
185         }
186 
187         return types;
188     }
189 
190     /**
191      * Extract types from methods (parameters, exceptions and return types). 
192      * The types are returned if present in the types list.
193      * 
194      * @param clazz
195      *             The class to inspect
196      * @param types
197      *              The types list 
198      * 
199      * @return the list< class>
200      */
201     @SuppressWarnings("unchecked")
202     private static List<Class> extractTypesFromMethods(Class clazz,
203             List<Class> types) {
204 
205         Method[] methods = clazz.getMethods();
206         if (methods == null) {
207             return types;
208         }
209 
210         // else
211         List<Class> returnedTypes = types;
212         for (Method currentMethod : methods) {
213             // ===== PARAMS
214             Class[] paramTypes = currentMethod.getParameterTypes();
215             returnedTypes = extractFromArray(paramTypes, types);
216 
217             // ===== EXCEPTIONS
218             Class[] exTypes = currentMethod.getExceptionTypes();
219             returnedTypes = extractFromArray(exTypes, types);
220 
221             // ===== RETURNS
222             Class ret = currentMethod.getReturnType();
223             if ((ret != null) && (!types.contains(ret))) {
224                 returnedTypes.add(ret);
225             }
226         }
227 
228         return returnedTypes;
229     }
230 
231     /**
232      * Adds all the classes in the array to the List and returns it.
233      * 
234      * @param array
235      *          The classes array
236      * @param types
237      *          The tpyes array
238      * 
239      * @return the list< class>
240      */
241     @SuppressWarnings("unchecked")
242     private static List<Class> extractFromArray(Class[] array, List<Class> types) {
243 
244         if (array == null) {
245             return types;
246         }
247         // else
248         for (Class currentType : array) {
249             if (!types.contains(currentType)) {
250                 types.add(currentType);
251             }
252         }
253         return types;
254     }
255 
256 }