1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.morph.util;
17
18 import java.math.BigDecimal;
19 import java.math.BigInteger;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.Set;
25
26 import net.sf.composite.util.ObjectUtils;
27 import net.sf.morph.MorphException;
28 import net.sf.morph.reflect.ReflectionException;
29 import net.sf.morph.transform.TransformationException;
30
31 /**
32 * Class manipulation utilities. Note that some code was copied from the
33 * Spring framework. Some other code was copied from Apache Ant.
34 *
35 * @author Matt Sgarlata
36 * @author Keith Donald
37 * @author Rob Harrop
38 * @author Juergen Hoeller
39 * @author Matt Benson
40 * @since Nov 6, 2004
41 */
42 public abstract class ClassUtils extends net.sf.composite.util.ClassUtils {
43
44 /**
45 * All the base array classes. Multidimensional arrays are subclasses of
46 * these fundamental array types.
47 */
48 public static final Class[] ARRAY_TYPES = {
49 Object[].class,
50 long[].class,
51 int[].class,
52 short[].class,
53 char[].class,
54 byte[].class,
55 double[].class,
56 float[].class,
57 boolean[].class
58 };
59
60 private static final Set ALL_CLASSES;
61 private static final Set IMMUTABLE_TYPES;
62 private static final Map PRIMITIVE_TYPE_MAP;
63
64 static {
65
66 Class[] primitives = {
67 Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE,
68 Long.TYPE, Float.TYPE, Double.TYPE };
69 Class[] wrappers = {
70 Boolean.class, Byte.class, Character.class, Short.class, Integer.class,
71 Long.class, Float.class, Double.class };
72 Map ptm = new HashMap(8);
73 for (int i = 0; i < primitives.length; i++) {
74 ptm.put(primitives[i], wrappers[i]);
75 }
76 PRIMITIVE_TYPE_MAP = Collections.unmodifiableMap(ptm);
77
78
79
80 Set immutable = ContainerUtils.createOrderedSet();
81 immutable.addAll(Arrays.asList(primitives));
82 immutable.addAll(Arrays.asList(wrappers));
83 immutable.add(String.class);
84
85
86 immutable.add(BigInteger.class);
87 immutable.add(BigDecimal.class);
88
89 immutable.add(null);
90 immutable.add(Class.class);
91 IMMUTABLE_TYPES = Collections.unmodifiableSet(immutable);
92
93
94 Set allClasses = ContainerUtils.createOrderedSet();
95 allClasses.add(Object.class);
96 allClasses.addAll(Arrays.asList(primitives));
97 allClasses.add(null);
98 ALL_CLASSES = Collections.unmodifiableSet(allClasses);
99 }
100
101 /**
102 * Returns an array version of the given class (for example, converts Long to Long[]).
103 */
104 public static Class getArrayClass(Class componentType) {
105 return createArray(componentType, 0).getClass();
106 }
107
108 /**
109 * Returns a new instance of the class denoted by <code>type</code>. The
110 * type may be expressed as a Class object, a String or a StringBuffer.
111 *
112 * @param type
113 * an object that specifies the class of the new instance
114 * @return an instance of the specified class
115 * @throws ReflectionException
116 * if a new instance of the requested class could not be created
117 * @throws TransformationException
118 * if the class denoted by the given type could not be retrieved
119 * @throws IllegalArgumentException
120 * if the type parameter is null or not a Class, String or
121 * StringBuffer
122 */
123 public static Object newInstance(Object type) {
124 try {
125 return convertToClass(type).newInstance();
126 }
127 catch (MorphException e) {
128 throw e;
129 }
130 catch (IllegalArgumentException e) {
131 throw e;
132 }
133 catch (Exception e) {
134 throw new ReflectionException("Could not create a new instance of "
135 + ObjectUtils.getObjectDescription(type), e);
136 }
137 }
138
139 /**
140 * Converts the given object to a Class object. The conversion will only
141 * succeed if the object is a Class, String or StringBuffer.
142 *
143 * @param type
144 * an object that specifies the class
145 * @return the specified class
146 * @throws TransformationException
147 * if the class could not be retrieved for some reason
148 * @throws IllegalArgumentException
149 * if the type parameter is null or not a Class, String or
150 * StringBuffer
151 */
152 public static Class convertToClass(Object type) {
153 if (type == null) {
154 throw new IllegalArgumentException(
155 "You must specify the class to instantiate");
156 }
157 if (!(type instanceof String || type instanceof StringBuffer || type instanceof Class)) {
158 throw new IllegalArgumentException(
159 "The type to be instantiated must be specified as a Class, String or StringBuffer object");
160 }
161
162 try {
163 return type instanceof Class ? (Class) type : Class.forName(type.toString());
164 }
165 catch (Exception e) {
166 throw new TransformationException(
167 "Could not convert " + ObjectUtils.getObjectDescription(type)
168 + " to a Class object: " + e.getMessage(), e);
169 }
170 }
171
172 /**
173 * Indicates whether the Servlet API is available.
174 *
175 * @return <code>true</code> if the servlet API is available or <br>
176 * <code>false</code> otherwise
177 */
178 public static boolean isServletApiPresent() {
179 return isClassPresent("javax.servlet.http.HttpServletRequest");
180 }
181
182 /**
183 * Indicates whether the JSP API is available.
184 *
185 * @return <code>true</code> if the JSP API is available or <br>
186 * <code>false</code> otherwise
187 */
188 public static boolean isJspApiPresent() {
189 return isClassPresent("javax.servlet.jsp.PageContext");
190 }
191
192 /**
193 * Indicates whether the Apache Commons BeanUtils API is available.
194 *
195 * @return <code>true</code> if the BeanUtils API is available or <br>
196 * <code>false</code> otherwise
197 */
198 public static boolean isBeanUtilsPresent() {
199 return isClassPresent("org.apache.commons.beanutils.DynaBean");
200 }
201
202 /**
203 * Indicates whether Velocity is available.
204 *
205 * @return <code>true</code> if Velocity is available or <br>
206 * <code>false</code> otherwise
207 */
208 public static boolean isVelocityPresent() {
209 return isClassPresent("org.apache.velocity.VelocityContext");
210 }
211
212 /**
213 * Indicates whether Commons Collections 3.x is available on the classpath.
214 *
215 * @return <code>true</code> Commons Collections 3.x is available on the
216 * classpath<br>
217 * <code>false</code> otherwise
218 */
219 public static boolean isCommonsCollections3Present() {
220 return isClassPresent("org.apache.commons.collections.set.ListOrderedSet");
221 }
222
223 /**
224 * Determines if <code>type</code> is equal to or a subtype of any of the
225 * types in <code>typeArray</code>.
226 *
227 * @param type
228 * the type to test
229 * @param typeArray
230 * the array of types
231 * @return <code>true</code>, if <code>type</code> if <code>type</code>
232 * is equal to or a subtype of any of the types in
233 * <code>typeArray</code> or <br>
234 * <code>false</code>, otherwise
235 * @throws IllegalArgumentException
236 * if any of the types in the provided <code>typeArray</code>
237 * are <code>null</code>
238 */
239 public static boolean inheritanceContains(Class[] typeArray, Class type) {
240 if (typeArray == null) {
241 return false;
242 }
243 for (int i = 0; i < typeArray.length; i++) {
244 if (type == null) {
245 if (typeArray[i] == null) {
246 return true;
247 }
248 }
249 else if (typeArray[i] != null &&
250 typeArray[i].isAssignableFrom(type)) {
251 return true;
252 }
253 }
254 return false;
255 }
256
257 /**
258 * Returns the class of the given object.
259 *
260 * @param object
261 * the object
262 * @return <code>null</code>, if <code>type</code> is <code>null</code>
263 * or <br>
264 * the class of the given object, otherwise
265 */
266 public static Class getClass(Object object) {
267 return object == null ? null : object.getClass();
268 }
269
270 /**
271 * Determines whether the given <code>destinationType</code> is one of the
272 * primitive immutable types provided by the JDK (i.e. a Number or a
273 * String). Note that JDK 1.6 adds AtomicLong and AtomicInteger, which
274 * are <em>not</em> immutable.
275 *
276 * @param destinationType
277 * the type to examine
278 * @return <code>true</code> if the <code>destinationType</code> is an immutable
279 * number or a String or <br>
280 * <code>false</code>, otherwise
281 */
282 public static boolean isImmutable(Class destinationType) {
283 return IMMUTABLE_TYPES.contains(destinationType);
284 }
285
286 /**
287 * Determines whether the given object is an immutable object.
288 * @param o
289 * @return
290 */
291 public static boolean isImmutableObject(Object o) {
292 return isImmutable(getClass(o));
293 }
294
295 /**
296 * Get the known immutable types.
297 * @return Class[]
298 */
299 public static Class[] getImmutableTypes() {
300 return (Class[]) IMMUTABLE_TYPES.toArray(new Class[IMMUTABLE_TYPES.size()]);
301 }
302
303 /**
304 * Get the wrapper type for the specified class (if any).
305 * @param c a (presumably primitive) Class.
306 * @return the wrapper class for <code>c</code>, if <code>c</code> is primitive, else null.
307 */
308 public static Class getPrimitiveWrapper(Class c) {
309 return (Class) PRIMITIVE_TYPE_MAP.get(c);
310 }
311
312 /**
313 * Get all the primitive classes.
314 * @return Class[]
315 */
316 public static Class[] getPrimitiveTypes() {
317 return (Class[]) PRIMITIVE_TYPE_MAP.keySet().toArray(new Class[PRIMITIVE_TYPE_MAP.size()]);
318 }
319
320 /**
321 * Get all the primitive wrapper classes.
322 * @return Class[]
323 */
324 public static Class[] getWrapperTypes() {
325 return (Class[]) PRIMITIVE_TYPE_MAP.values().toArray(new Class[PRIMITIVE_TYPE_MAP.size()]);
326 }
327
328 /**
329 * Returns the set of classes for which any class will match.
330 * @return Class[]
331 */
332 public static Class[] getAllClasses() {
333 return (Class[]) ALL_CLASSES.toArray(new Class[ALL_CLASSES.size()]);
334 }
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364 }