OSDN Git Service

Removed BeanException class: http://code.google.com/p/xerial/issues/detail?id=26
[xerial/xerial-core.git] / src / main / java / org / xerial / util / bean / TypeInfo.java
1 /*--------------------------------------------------------------------------
2  *  Copyright 2007 Taro L. Saito
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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 //--------------------------------------
17 // XerialJ
18 //
19 // TypeInformation.java
20 // Since: Aug 9, 2007 9:37:40 AM
21 //
22 // $URL$
23 // $Author$
24 //--------------------------------------
25 package org.xerial.util.bean;
26
27 import java.io.File;
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;
38 import java.util.Map;
39 import java.util.Queue;
40 import java.util.Set;
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;
46
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;
53
54 /**
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.
58  * 
59  * @author leo
60  * 
61  */
62 public class TypeInfo
63 {
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 };
67
68     static private HashSet<Class< ? >> basicTypeSet    = new HashSet<Class< ? >>();
69     static {
70         for (Class< ? > c : _parameterClass)
71             basicTypeSet.add(c);
72     }
73
74     /**
75      * non-constructable
76      */
77     private TypeInfo() {}
78
79     /**
80      * @param c
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.
84      */
85     public static boolean isBasicType(Class< ? > c) {
86         if (c.isArray())
87             return basicTypeSet.contains(c.getComponentType());
88         else if (c.isEnum())
89             return true;
90         else
91             return basicTypeSet.contains(c);
92     }
93
94     public static boolean isCollection(Class< ? > c) {
95         return Collection.class.isAssignableFrom(c);
96     }
97
98     public static boolean isSet(Class< ? > c) {
99         return Set.class.isAssignableFrom(c);
100     }
101
102     public static boolean isSortedSet(Class< ? > c) {
103         return SortedSet.class.isAssignableFrom(c);
104     }
105
106     public static boolean isSortedMap(Class< ? > c) {
107         return SortedMap.class.isAssignableFrom(c);
108     }
109
110     public static boolean isMap(Class< ? > c) {
111         return Map.class.isAssignableFrom(c);
112     }
113
114     public static boolean isQueue(Class< ? > c) {
115         return Queue.class.isAssignableFrom(c);
116     }
117
118     public static boolean isEnum(Class< ? > c) {
119         return c.isEnum();
120     }
121
122     public static boolean isArray(Class< ? > c) {
123         return c.isArray();
124     }
125
126     public static boolean isString(Class< ? > c) {
127         return String.class.isAssignableFrom(c);
128     }
129
130     public static boolean isBoolean(Class< ? > c) {
131         return boolean.class.isAssignableFrom(c) || Boolean.class.isAssignableFrom(c);
132     }
133
134     public static boolean isDOMElement(Class< ? > c) {
135         return Element.class.isAssignableFrom(c);
136     }
137
138     public static boolean isPair(Class< ? > c) {
139         return Pair.class.isAssignableFrom(c);
140     }
141
142     public static boolean isTriplet(Class< ? > c) {
143         return Triplet.class.isAssignableFrom(c);
144     }
145
146     public static boolean hasDefaultConstructor(Class< ? > c) {
147         for (Constructor< ? > constructor : c.getConstructors()) {
148             if (constructor.getParameterTypes().length == 0) {
149                 return true;
150             }
151         }
152         return false;
153     }
154
155     public static boolean hasPublicDefaultConstructor(Class< ? > c) {
156         return getPublicDefaultConstructor(c) != null;
157     }
158
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())) {
164                     return constructor;
165                 }
166             }
167         }
168         return null;
169     }
170
171     public static boolean canInstantiate(Class< ? > c) {
172         // do not worry about basic types
173         return (isBasicType(c) || alternateConstractableClassFor(c) != null);
174     }
175
176     /**
177      * @param <T>
178      * @param c
179      * @return
180      */
181     @SuppressWarnings("unchecked")
182     // type cast is tested
183     private static <T> Class<T> alternateConstractableClassFor(Class<T> c) {
184         if (hasPublicDefaultConstructor(c))
185             return c;
186
187         if (isCollection(c)) {
188             if (isSet(c)) {
189                 if (isSortedSet(c))
190                     return (Class<T>) TreeSet.class;
191                 else
192                     return (Class<T>) LinkedHashSet.class;
193             }
194             else if (isQueue(c)) {
195                 return (Class<T>) ArrayDeque.class;
196             }
197             else
198                 return (Class<T>) ArrayList.class;
199         }
200         else if (isMap(c)) {
201             if (isSortedMap(c))
202                 return (Class<T>) TreeMap.class;
203             else
204                 return (Class<T>) LinkedHashMap.class;
205         }
206
207         return null;
208     }
209
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
213                     .getSimpleName()));
214
215         // Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE
216         if (c == int.class)
217             return 0;
218         else if (c == long.class)
219             return 1L;
220         else if (c == double.class)
221             return (double) 0;
222         else if (c == boolean.class)
223             return false;
224         else if (c == float.class)
225             return (float) 0;
226         else if (c == short.class)
227             return (short) 0;
228         else if (c == byte.class)
229             return (byte) 0;
230         else if (c == char.class)
231             return (char) 0;
232         else
233             return null;
234
235     }
236
237     //    public static <T> Object createInstance(Class<T> c) throws XerialException
238     //    {
239     //        if (c.isPrimitive())
240     //            return createPrimitiveTypeInstance(c);
241     //
242     //        try
243     //        {
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");
248     //            
249     //            return constractableClass.newInstance();
250     //        }
251     //        catch (InstantiationException e)
252     //        {
253     //            throw new XerialException(XerialErrorCode.InstantiationFailure, e);
254     //        }
255     //        catch (IllegalAccessException e)
256     //        {
257     //            throw new XerialException(XerialErrorCode.IllegalAccess, e);
258     //        }
259     //    }
260
261     private static ConcurrentHashMap<Class< ? >, Constructor< ? >> constructorTable = new ConcurrentHashMap<Class< ? >, Constructor< ? >>();
262
263     private static <T> Object createInstance(Constructor< ? > cons) throws XerialException {
264         try {
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);
270         }
271         catch (Exception e) {
272             throw new XerialException(XerialErrorCode.InstantiationFailure, e);
273         }
274     }
275
276     @SuppressWarnings("unchecked")
277     public static <T> T createInstance(Class<T> c) throws XerialException {
278         if (c.isPrimitive())
279             return (T) createPrimitiveTypeInstance(c);
280
281         try {
282             Constructor< ? > cons = constructorTable.get(c);
283             if (cons != null) {
284                 return (T) createInstance(cons);
285             }
286
287             assert cons == null;
288
289             Class<T> constractableClass = alternateConstractableClassFor(c);
290             if (constractableClass != null) {
291                 cons = getPublicDefaultConstructor(constractableClass);
292                 assert cons != null;
293                 constructorTable.put(c, cons);
294                 return constractableClass.newInstance();
295             }
296             else {
297                 // search other public constructors
298                 for (Constructor< ? > publicConstructor : c.getConstructors()) {
299                     try {
300                         Object instance = createInstance(publicConstructor);
301                         constructorTable.put(c, publicConstructor);
302                         return (T) instance;
303                     }
304                     catch (Exception e) {
305
306                     }
307                 }
308
309                 // search hidden constructors
310                 for (Constructor< ? > constructor : c.getDeclaredConstructors()) {
311                     try {
312                         constructor.setAccessible(true);
313                         Object instance = createInstance(constructor);
314                         constructorTable.put(c, constructor);
315                         return (T) instance;
316                     }
317                     catch (Exception e) {
318
319                     }
320                 }
321
322                 throw new XerialException(XerialErrorCode.NoPublicConstructor, "No public constructor for the class: "
323                         + c.getName() + " is available");
324
325             }
326         }
327         catch (InstantiationException e) {
328             throw new XerialException(XerialErrorCode.InstantiationFailure, e);
329         }
330         catch (IllegalAccessException e) {
331             throw new XerialException(XerialErrorCode.IllegalAccess, e);
332         }
333     }
334
335     public static Class< ? > getElementTypeOfCollection(Class< ? extends Collection< ? >> collectionType) {
336         //        collectionType.get
337         //        
338         //        ParameterizedType pt = getParentParameterizedType(type, Collection.class);
339         //        if (pt != null)
340         //        {
341         //            Type[] actualType = pt.getActualTypeArguments();
342         //            if (actualType.length > 0)
343         //                return resolveRawType(actualType[0], orig);
344         //        }
345         //        return orig;
346         return null;
347     }
348
349     public static ParameterizedType getParameterizedType(Type t) {
350         if (t == null)
351             return null;
352
353         if (t instanceof ParameterizedType) {
354             ParameterizedType pt = (ParameterizedType) t;
355             return pt;
356         }
357         if (t instanceof Class)
358             return getParameterizedType(((Class< ? >) t).getGenericSuperclass());
359         else
360             return null;
361     }
362
363     @SuppressWarnings("unchecked")
364     public static ParameterizedType getParentParameterizedType(Type t, Class target) {
365         if (t == null)
366             return null;
367
368         if (t instanceof ParameterizedType) {
369             ParameterizedType pt = (ParameterizedType) t;
370             if (target.isAssignableFrom((Class) pt.getRawType())) {
371                 return pt;
372             }
373         }
374
375         if (t instanceof Class) {
376             Class c = (Class) t;
377             return getParentParameterizedType(c.getGenericSuperclass(), target);
378         }
379         else
380             return null;
381     }
382
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);
387         }
388         else if (type instanceof Class)
389             return (Class< ? >) type;
390         else
391             return orig;
392     }
393
394     public static Class< ? > resolveRawType(Type type) {
395         if (type instanceof ParameterizedType) {
396             ParameterizedType pt = (ParameterizedType) type;
397             return resolveRawType(pt.getRawType());
398         }
399         else if (type instanceof Class)
400             return (Class< ? >) type;
401         else
402             return Object.class;
403     }
404
405 }