View Javadoc

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 }