22
22
import java .beans .PropertyDescriptor ;
23
23
import java .lang .ref .Reference ;
24
24
import java .lang .ref .WeakReference ;
25
- import java .util .Collection ;
26
25
import java .util .Collections ;
27
- import java .util .HashMap ;
28
26
import java .util .HashSet ;
29
27
import java .util .Iterator ;
28
+ import java .util .LinkedHashMap ;
30
29
import java .util .Map ;
31
30
import java .util .Set ;
32
31
import java .util .WeakHashMap ;
@@ -141,19 +140,20 @@ static CachedIntrospectionResults forClass(Class beanClass) throws BeansExceptio
141
140
results = (CachedIntrospectionResults ) value ;
142
141
}
143
142
if (results == null ) {
144
- // can throw BeansException
145
- results = new CachedIntrospectionResults (beanClass );
146
143
// On JDK 1.5 and higher, it is almost always safe to cache the bean class...
147
144
// The sole exception is a custom BeanInfo class being provided in a non-safe ClassLoader.
148
- if (ClassUtils .isCacheSafe (beanClass , CachedIntrospectionResults .class .getClassLoader ()) ||
149
- isClassLoaderAccepted (beanClass .getClassLoader ()) ||
150
- !ClassUtils .isPresent (beanClass .getName () + "BeanInfo" , beanClass .getClassLoader ())) {
145
+ boolean fullyCacheable =
146
+ ClassUtils .isCacheSafe (beanClass , CachedIntrospectionResults .class .getClassLoader ()) ||
147
+ isClassLoaderAccepted (beanClass .getClassLoader ());
148
+ if (fullyCacheable || !ClassUtils .isPresent (beanClass .getName () + "BeanInfo" , beanClass .getClassLoader ())) {
149
+ results = new CachedIntrospectionResults (beanClass , fullyCacheable );
151
150
classCache .put (beanClass , results );
152
151
}
153
152
else {
154
153
if (logger .isDebugEnabled ()) {
155
154
logger .debug ("Not strongly caching class [" + beanClass .getName () + "] because it is not cache-safe" );
156
155
}
156
+ results = new CachedIntrospectionResults (beanClass , true );
157
157
classCache .put (beanClass , new WeakReference <CachedIntrospectionResults >(results ));
158
158
}
159
159
}
@@ -216,7 +216,7 @@ private static boolean isUnderneathClassLoader(ClassLoader candidate, ClassLoade
216
216
* @param beanClass the bean class to analyze
217
217
* @throws BeansException in case of introspection failure
218
218
*/
219
- private CachedIntrospectionResults (Class beanClass ) throws BeansException {
219
+ private CachedIntrospectionResults (Class beanClass , boolean cacheFullMetadata ) throws BeansException {
220
220
try {
221
221
if (logger .isTraceEnabled ()) {
222
222
logger .trace ("Getting BeanInfo for class [" + beanClass .getName () + "]" );
@@ -237,24 +237,29 @@ private CachedIntrospectionResults(Class beanClass) throws BeansException {
237
237
if (logger .isTraceEnabled ()) {
238
238
logger .trace ("Caching PropertyDescriptors for class [" + beanClass .getName () + "]" );
239
239
}
240
- this .propertyDescriptorCache = new HashMap <String , PropertyDescriptor >();
240
+ this .propertyDescriptorCache = new LinkedHashMap <String , PropertyDescriptor >();
241
241
242
242
// This call is slow so we do it once.
243
243
PropertyDescriptor [] pds = this .beanInfo .getPropertyDescriptors ();
244
244
for (PropertyDescriptor pd : pds ) {
245
+ if (Class .class .equals (beanClass ) && "classLoader" .equals (pd .getName ())) {
246
+ // Ignore Class.getClassLoader() method - nobody needs to bind to that
247
+ continue ;
248
+ }
245
249
if (logger .isTraceEnabled ()) {
246
250
logger .trace ("Found bean property '" + pd .getName () + "'" +
247
251
(pd .getPropertyType () != null ? " of type [" + pd .getPropertyType ().getName () + "]" : "" ) +
248
252
(pd .getPropertyEditorClass () != null ?
249
253
"; editor [" + pd .getPropertyEditorClass ().getName () + "]" : "" ));
250
254
}
251
- pd = new GenericTypeAwarePropertyDescriptor (beanClass , pd .getName (), pd .getReadMethod (),
252
- pd .getWriteMethod (), pd .getPropertyEditorClass ());
255
+ if (cacheFullMetadata ) {
256
+ pd = buildGenericTypeAwarePropertyDescriptor (beanClass , pd );
257
+ }
253
258
this .propertyDescriptorCache .put (pd .getName (), pd );
254
259
}
255
260
}
256
261
catch (IntrospectionException ex ) {
257
- throw new FatalBeanException ("Cannot get BeanInfo for object of class [" + beanClass .getName () + "]" , ex );
262
+ throw new FatalBeanException ("Failed to obtain BeanInfo for class [" + beanClass .getName () + "]" , ex );
258
263
}
259
264
}
260
265
@@ -275,12 +280,29 @@ PropertyDescriptor getPropertyDescriptor(String name) {
275
280
pd = this .propertyDescriptorCache .get (name .substring (0 , 1 ).toUpperCase () + name .substring (1 ));
276
281
}
277
282
}
278
- return pd ;
283
+ return (pd == null || pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
284
+ buildGenericTypeAwarePropertyDescriptor (getBeanClass (), pd ));
279
285
}
280
286
281
287
PropertyDescriptor [] getPropertyDescriptors () {
282
- Collection <PropertyDescriptor > descriptorCollection = this .propertyDescriptorCache .values ();
283
- return descriptorCollection .toArray (new PropertyDescriptor [descriptorCollection .size ()]);
288
+ PropertyDescriptor [] pds = new PropertyDescriptor [this .propertyDescriptorCache .size ()];
289
+ int i = 0 ;
290
+ for (PropertyDescriptor pd : this .propertyDescriptorCache .values ()) {
291
+ pds [i ] = (pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
292
+ buildGenericTypeAwarePropertyDescriptor (getBeanClass (), pd ));
293
+ i ++;
294
+ }
295
+ return pds ;
296
+ }
297
+
298
+ private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor (Class beanClass , PropertyDescriptor pd ) {
299
+ try {
300
+ return new GenericTypeAwarePropertyDescriptor (beanClass , pd .getName (), pd .getReadMethod (),
301
+ pd .getWriteMethod (), pd .getPropertyEditorClass ());
302
+ }
303
+ catch (IntrospectionException ex ) {
304
+ throw new FatalBeanException ("Failed to re-introspect class [" + beanClass .getName () + "]" , ex );
305
+ }
284
306
}
285
307
286
308
}
0 commit comments