1 /*
2 * $Id: ClassUtil.java 1306435 2012-03-28 15:39:11Z nlebas $
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21 package org.apache.tiles.request.reflect;
22
23 import java.beans.BeanInfo;
24 import java.beans.Introspector;
25 import java.beans.PropertyDescriptor;
26 import java.util.Map;
27
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31
32 /**
33 * Utilities to work with dynamic class loading and instantiation.
34 *
35 * @version $Rev: 1306435 $ $Date: 2012-03-29 02:39:11 +1100 (Thu, 29 Mar 2012) $
36 */
37 public final class ClassUtil {
38
39 /**
40 * Constructor, private to avoid instantiation.
41 */
42 private ClassUtil() {
43 }
44
45 /**
46 * Returns the class and casts it to the correct subclass.<br>
47 * It tries to use the thread's current classloader first and, if it does
48 * not succeed, uses the classloader of ClassUtil.
49 *
50 * @param <T> The subclass to use.
51 * @param className The name of the class to load.
52 * @param baseClass The base class to subclass to.
53 * @return The loaded class.
54 * @throws ClassNotFoundException If the class has not been found.
55 */
56 public static <T> Class<? extends T> getClass(String className,
57 Class<T> baseClass) throws ClassNotFoundException {
58 ClassLoader classLoader = Thread.currentThread()
59 .getContextClassLoader();
60 if (classLoader == null) {
61 classLoader = ClassUtil.class.getClassLoader();
62 }
63 return Class.forName(className, true, classLoader)
64 .asSubclass(baseClass);
65 }
66
67 /**
68 * Returns an instance of the given class name, by calling the default
69 * constructor.
70 *
71 * @param className The class name to load and to instantiate.
72 * @return The new instance of the class name.
73 * @throws CannotInstantiateObjectException If something goes wrong during
74 * instantiation.
75 */
76 public static Object instantiate(String className) {
77 return instantiate(className, false);
78 }
79
80 /**
81 * Returns an instance of the given class name, by calling the default
82 * constructor.
83 *
84 * @param className The class name to load and to instantiate.
85 * @param returnNull If <code>true</code>, if the class is not found it
86 * returns <code>true</code>, otherwise it throws a
87 * <code>TilesException</code>.
88 * @return The new instance of the class name.
89 * @throws CannotInstantiateObjectException If something goes wrong during instantiation.
90 */
91 public static Object instantiate(String className, boolean returnNull) {
92 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
93 if (classLoader == null) {
94 classLoader = ClassUtil.class.getClassLoader();
95 }
96 try {
97 Class<? extends Object> namedClass = getClass(className, Object.class);
98 return namedClass.newInstance();
99 } catch (ClassNotFoundException e) {
100 if (returnNull) {
101 return null;
102 }
103 throw new CannotInstantiateObjectException(
104 "Unable to resolve factory class: '" + className + "'", e);
105 } catch (IllegalAccessException e) {
106 throw new CannotInstantiateObjectException(
107 "Unable to access factory class: '" + className + "'", e);
108 } catch (InstantiationException e) {
109 throw new CannotInstantiateObjectException(
110 "Unable to instantiate factory class: '"
111 + className
112 + "'. Make sure that this class has a default constructor",
113 e);
114 }
115 }
116
117 /**
118 * Collects bean infos from a class and filling a list.
119 *
120 * @param clazz The class to be inspected.
121 * @param name2descriptor The map in the form: name of the property ->
122 * descriptor.
123 */
124 public static void collectBeanInfo(Class<?> clazz,
125 Map<String, PropertyDescriptor> name2descriptor) {
126 Logger log = LoggerFactory.getLogger(ClassUtil.class);
127 BeanInfo info = null;
128 try {
129 info = Introspector.getBeanInfo(clazz);
130 } catch (Exception ex) {
131 if (log.isDebugEnabled()) {
132 log.debug("Cannot inspect class " + clazz, ex);
133 }
134 }
135 if (info == null) {
136 return;
137 }
138 for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
139 pd.setValue("type", pd.getPropertyType());
140 pd.setValue("resolvableAtDesignTime", Boolean.TRUE);
141 name2descriptor.put(pd.getName(), pd);
142 }
143 }
144 }