1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jxpath;
17
18 import java.util.Date;
19 import java.util.Map;
20 import java.util.HashMap;
21
22 /***
23 * JXPathIntrospector maintains a registry of {@link JXPathBeanInfo
24 * JXPathBeanInfo} objects for Java classes.
25 *
26 * @author Dmitri Plotnikov
27 * @version $Revision: 1.10 $ $Date: 2004/05/08 15:10:05 $
28 */
29 public class JXPathIntrospector {
30
31 private static HashMap byClass = new HashMap();
32 private static HashMap byInterface = new HashMap();
33
34 static {
35 registerAtomicClass(Class.class);
36 registerAtomicClass(Boolean.TYPE);
37 registerAtomicClass(Boolean.class);
38 registerAtomicClass(Byte.TYPE);
39 registerAtomicClass(Byte.class);
40 registerAtomicClass(Character.TYPE);
41 registerAtomicClass(Character.class);
42 registerAtomicClass(Short.TYPE);
43 registerAtomicClass(Short.class);
44 registerAtomicClass(Integer.TYPE);
45 registerAtomicClass(Integer.class);
46 registerAtomicClass(Long.TYPE);
47 registerAtomicClass(Long.class);
48 registerAtomicClass(Float.TYPE);
49 registerAtomicClass(Float.class);
50 registerAtomicClass(Double.TYPE);
51 registerAtomicClass(Double.class);
52 registerAtomicClass(String.class);
53 registerAtomicClass(Date.class);
54 registerAtomicClass(java.sql.Date.class);
55 registerAtomicClass(java.sql.Time.class);
56 registerAtomicClass(java.sql.Timestamp.class);
57
58 registerDynamicClass(Map.class, MapDynamicPropertyHandler.class);
59 }
60
61 /***
62 * Automatically creates and registers a JXPathBeanInfo object
63 * for the specified class. That object returns true to isAtomic().
64 */
65 public static void registerAtomicClass(Class beanClass) {
66 byClass.put(beanClass, new JXPathBasicBeanInfo(beanClass, true));
67 }
68
69 /***
70 * Automatically creates and registers a JXPathBeanInfo object
71 * for the specified class. That object returns true to isDynamic().
72 */
73 public static void registerDynamicClass(
74 Class beanClass,
75 Class dynamicPropertyHandlerClass)
76 {
77 JXPathBasicBeanInfo bi =
78 new JXPathBasicBeanInfo(beanClass, dynamicPropertyHandlerClass);
79 if (beanClass.isInterface()) {
80 byInterface.put(beanClass, bi);
81 }
82 else {
83 byClass.put(beanClass, bi);
84 }
85 }
86
87 /***
88 * Creates and registers a JXPathBeanInfo object for the supplied class. If
89 * the class has already been registered, returns the registered
90 * JXPathBeanInfo object.
91 * <p>
92 * The process of creation of JXPathBeanInfo is as follows:
93 * <ul>
94 * <li>If class named <code><beanClass>XBeanInfo</code> exists,
95 * an instance of that class is allocated.
96 * <li>Otherwise, an instance of {@link JXPathBasicBeanInfo
97 * JXPathBasicBeanInfo} is allocated.
98 * </ul>
99 */
100 public static JXPathBeanInfo getBeanInfo(Class beanClass) {
101 JXPathBeanInfo beanInfo = (JXPathBeanInfo) byClass.get(beanClass);
102 if (beanInfo == null) {
103 beanInfo = findDynamicBeanInfo(beanClass);
104 if (beanInfo == null) {
105 beanInfo = findInformant(beanClass);
106 if (beanInfo == null) {
107 beanInfo = new JXPathBasicBeanInfo(beanClass);
108 }
109 }
110 byClass.put(beanClass, beanInfo);
111 }
112 return beanInfo;
113 }
114
115 /***
116 * Find a dynamic bean info if available for any superclasses or
117 * interfaces.
118 */
119 private static JXPathBeanInfo findDynamicBeanInfo(Class beanClass) {
120 JXPathBeanInfo beanInfo = null;
121 if (beanClass.isInterface()) {
122 beanInfo = (JXPathBeanInfo) byInterface.get(beanClass);
123 if (beanInfo != null && beanInfo.isDynamic()) {
124 return beanInfo;
125 }
126 }
127
128 Class interfaces[] = beanClass.getInterfaces();
129 if (interfaces != null) {
130 for (int i = 0; i < interfaces.length; i++) {
131 beanInfo = findDynamicBeanInfo(interfaces[i]);
132 if (beanInfo != null && beanInfo.isDynamic()) {
133 return beanInfo;
134 }
135 }
136 }
137
138 Class sup = beanClass.getSuperclass();
139 if (sup != null) {
140 beanInfo = (JXPathBeanInfo) byClass.get(sup);
141 if (beanInfo != null && beanInfo.isDynamic()) {
142 return beanInfo;
143 }
144 return findDynamicBeanInfo(sup);
145 }
146 return null;
147 }
148
149 private static synchronized JXPathBeanInfo findInformant(Class beanClass) {
150 String name = beanClass.getName() + "XBeanInfo";
151 try {
152 return (JXPathBeanInfo) instantiate(beanClass, name);
153 }
154 catch (Exception ex) {
155
156 }
157
158
159 try {
160 if (JXPathBeanInfo.class.isAssignableFrom(beanClass)) {
161 return (JXPathBeanInfo) beanClass.newInstance();
162 }
163 }
164 catch (Exception ex) {
165
166 }
167
168 return null;
169 }
170
171 /***
172 * Try to create an instance of a named class.
173 * First try the classloader of "sibling", then try the system
174 * classloader.
175 */
176 private static Object instantiate(Class sibling, String className)
177 throws Exception
178 {
179
180
181 ClassLoader cl = sibling.getClassLoader();
182 if (cl != null) {
183 try {
184 Class cls = cl.loadClass(className);
185 return cls.newInstance();
186 }
187 catch (Exception ex) {
188
189 }
190 }
191
192
193 Class cls = Class.forName(className);
194 return cls.newInstance();
195 }
196 }