1 /*--------------------------------------------------------------------------
2 * Copyright 2007 Taro L. Saito
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *--------------------------------------------------------------------------*/
16 //--------------------------------------
19 // TypeInformation.java
20 // Since: Aug 9, 2007 9:37:40 AM
24 //--------------------------------------
25 package org.xerial.util.bean;
28 import java.lang.reflect.Constructor;
29 import java.lang.reflect.Modifier;
30 import java.lang.reflect.ParameterizedType;
31 import java.lang.reflect.Type;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.Date;
35 import java.util.HashSet;
36 import java.util.LinkedHashMap;
37 import java.util.LinkedHashSet;
39 import java.util.Queue;
41 import java.util.SortedMap;
42 import java.util.SortedSet;
43 import java.util.TreeMap;
44 import java.util.TreeSet;
45 import java.util.concurrent.ConcurrentHashMap;
47 import org.w3c.dom.Element;
48 import org.xerial.core.XerialErrorCode;
49 import org.xerial.core.XerialException;
50 import org.xerial.util.ArrayDeque;
51 import org.xerial.util.Pair;
52 import org.xerial.util.Triplet;
55 * TypeInfo holds the information of standard types that can be directly
56 * assignable as Bean parameter values. For example, int/Integer, double/Double,
57 * String, etc. and their arrays are basic types.
64 static private Class< ? >[] _parameterClass = { int.class, double.class, float.class, long.class,
65 boolean.class, char.class, short.class, String.class, Integer.class, Double.class, Float.class, Long.class,
66 Boolean.class, Character.class, Short.class, Date.class, File.class };
68 static private HashSet<Class< ? >> basicTypeSet = new HashSet<Class< ? >>();
70 for (Class< ? > c : _parameterClass)
81 * @return true : if a given class is a single class or array of int,
82 * double, float, boolean, String, Integer, Double, Float or
83 * Boolean. otherwise false.
85 public static boolean isBasicType(Class< ? > c) {
87 return basicTypeSet.contains(c.getComponentType());
91 return basicTypeSet.contains(c);
94 public static boolean isCollection(Class< ? > c) {
95 return Collection.class.isAssignableFrom(c);
98 public static boolean isSet(Class< ? > c) {
99 return Set.class.isAssignableFrom(c);
102 public static boolean isSortedSet(Class< ? > c) {
103 return SortedSet.class.isAssignableFrom(c);
106 public static boolean isSortedMap(Class< ? > c) {
107 return SortedMap.class.isAssignableFrom(c);
110 public static boolean isMap(Class< ? > c) {
111 return Map.class.isAssignableFrom(c);
114 public static boolean isQueue(Class< ? > c) {
115 return Queue.class.isAssignableFrom(c);
118 public static boolean isEnum(Class< ? > c) {
122 public static boolean isArray(Class< ? > c) {
126 public static boolean isString(Class< ? > c) {
127 return String.class.isAssignableFrom(c);
130 public static boolean isBoolean(Class< ? > c) {
131 return boolean.class.isAssignableFrom(c) || Boolean.class.isAssignableFrom(c);
134 public static boolean isDOMElement(Class< ? > c) {
135 return Element.class.isAssignableFrom(c);
138 public static boolean isPair(Class< ? > c) {
139 return Pair.class.isAssignableFrom(c);
142 public static boolean isTriplet(Class< ? > c) {
143 return Triplet.class.isAssignableFrom(c);
146 public static boolean hasDefaultConstructor(Class< ? > c) {
147 for (Constructor< ? > constructor : c.getConstructors()) {
148 if (constructor.getParameterTypes().length == 0) {
155 public static boolean hasPublicDefaultConstructor(Class< ? > c) {
156 return getPublicDefaultConstructor(c) != null;
159 public static Constructor< ? > getPublicDefaultConstructor(Class< ? > c) {
160 for (Constructor< ? > constructor : c.getConstructors()) {
161 if (constructor.getParameterTypes().length == 0) {
162 // the default constructor is public?
163 if (Modifier.isPublic(constructor.getModifiers())) {
171 public static boolean canInstantiate(Class< ? > c) {
172 // do not worry about basic types
173 return (isBasicType(c) || alternateConstractableClassFor(c) != null);
181 @SuppressWarnings("unchecked")
182 // type cast is tested
183 private static <T> Class<T> alternateConstractableClassFor(Class<T> c) {
184 if (hasPublicDefaultConstructor(c))
187 if (isCollection(c)) {
190 return (Class<T>) TreeSet.class;
192 return (Class<T>) LinkedHashSet.class;
194 else if (isQueue(c)) {
195 return (Class<T>) ArrayDeque.class;
198 return (Class<T>) ArrayList.class;
202 return (Class<T>) TreeMap.class;
204 return (Class<T>) LinkedHashMap.class;
210 public static <T> Object createPrimitiveTypeInstance(Class<T> c) throws XerialException {
211 if (!c.isPrimitive())
212 throw new XerialException(XerialErrorCode.InvalidType, String.format("%s is not a primitive", c
215 // Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE
218 else if (c == long.class)
220 else if (c == double.class)
222 else if (c == boolean.class)
224 else if (c == float.class)
226 else if (c == short.class)
228 else if (c == byte.class)
230 else if (c == char.class)
237 // public static <T> Object createInstance(Class<T> c) throws XerialException
239 // if (c.isPrimitive())
240 // return createPrimitiveTypeInstance(c);
244 // Class<T> constractableClass = alternateConstractableClassFor(c);
245 // if (constractableClass == null)
246 // throw new XerialException(XerialErrorCode.NoPublicConstructor, "No public constructor for the class: "
247 // + c.getName() + " is available");
249 // return constractableClass.newInstance();
251 // catch (InstantiationException e)
253 // throw new XerialException(XerialErrorCode.InstantiationFailure, e);
255 // catch (IllegalAccessException e)
257 // throw new XerialException(XerialErrorCode.IllegalAccess, e);
261 private static ConcurrentHashMap<Class< ? >, Constructor< ? >> constructorTable = new ConcurrentHashMap<Class< ? >, Constructor< ? >>();
263 private static <T> Object createInstance(Constructor< ? > cons) throws XerialException {
265 Class< ? >[] argType = cons.getParameterTypes();
266 Object[] args = new Object[argType.length];
267 for (int i = 0; i < argType.length; ++i)
268 args[i] = createInstance(argType[i]);
269 return cons.newInstance(args);
271 catch (Exception e) {
272 throw new XerialException(XerialErrorCode.InstantiationFailure, e);
276 @SuppressWarnings("unchecked")
277 public static <T> T createInstance(Class<T> c) throws XerialException {
279 return (T) createPrimitiveTypeInstance(c);
282 Constructor< ? > cons = constructorTable.get(c);
284 return (T) createInstance(cons);
289 Class<T> constractableClass = alternateConstractableClassFor(c);
290 if (constractableClass != null) {
291 cons = getPublicDefaultConstructor(constractableClass);
293 constructorTable.put(c, cons);
294 return constractableClass.newInstance();
297 // search other public constructors
298 for (Constructor< ? > publicConstructor : c.getConstructors()) {
300 Object instance = createInstance(publicConstructor);
301 constructorTable.put(c, publicConstructor);
304 catch (Exception e) {
309 // search hidden constructors
310 for (Constructor< ? > constructor : c.getDeclaredConstructors()) {
312 constructor.setAccessible(true);
313 Object instance = createInstance(constructor);
314 constructorTable.put(c, constructor);
317 catch (Exception e) {
322 throw new XerialException(XerialErrorCode.NoPublicConstructor, "No public constructor for the class: "
323 + c.getName() + " is available");
327 catch (InstantiationException e) {
328 throw new XerialException(XerialErrorCode.InstantiationFailure, e);
330 catch (IllegalAccessException e) {
331 throw new XerialException(XerialErrorCode.IllegalAccess, e);
335 public static Class< ? > getElementTypeOfCollection(Class< ? extends Collection< ? >> collectionType) {
336 // collectionType.get
338 // ParameterizedType pt = getParentParameterizedType(type, Collection.class);
341 // Type[] actualType = pt.getActualTypeArguments();
342 // if (actualType.length > 0)
343 // return resolveRawType(actualType[0], orig);
349 public static ParameterizedType getParameterizedType(Type t) {
353 if (t instanceof ParameterizedType) {
354 ParameterizedType pt = (ParameterizedType) t;
357 if (t instanceof Class)
358 return getParameterizedType(((Class< ? >) t).getGenericSuperclass());
363 @SuppressWarnings("unchecked")
364 public static ParameterizedType getParentParameterizedType(Type t, Class target) {
368 if (t instanceof ParameterizedType) {
369 ParameterizedType pt = (ParameterizedType) t;
370 if (target.isAssignableFrom((Class) pt.getRawType())) {
375 if (t instanceof Class) {
377 return getParentParameterizedType(c.getGenericSuperclass(), target);
383 public static Class< ? > resolveRawType(Type type, Class< ? > orig) {
384 if (type instanceof ParameterizedType) {
385 ParameterizedType pt = (ParameterizedType) type;
386 return resolveRawType(pt.getRawType(), orig);
388 else if (type instanceof Class)
389 return (Class< ? >) type;
394 public static Class< ? > resolveRawType(Type type) {
395 if (type instanceof ParameterizedType) {
396 ParameterizedType pt = (ParameterizedType) type;
397 return resolveRawType(pt.getRawType());
399 else if (type instanceof Class)
400 return (Class< ? >) type;