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 }