@Override public void contextDestroyed(ServletContextEvent event) { CachedIntrospectionResults.clearClassLoader(Thread.currentThread().getContextClassLoader()); Introspector.flushCaches(); }
/** * Retrieve the JavaBeans {@code PropertyDescriptors} for the given property. * @param clazz the Class to retrieve the PropertyDescriptor for * @param propertyName the name of the property * @return the corresponding PropertyDescriptor, or {@code null} if none * @throws BeansException if PropertyDescriptor lookup fails */ @Nullable public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) throws BeansException { CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz); return cr.getPropertyDescriptor(propertyName); }
results = new CachedIntrospectionResults(beanClass); ConcurrentMap<Class<?>, CachedIntrospectionResults> classCacheToUse; isClassLoaderAccepted(beanClass.getClassLoader())) { classCacheToUse = strongClassCache;
/** * Retrieve the JavaBeans {@code PropertyDescriptor}s of a given class. * @param clazz the Class to retrieve the PropertyDescriptors for * @return an array of {@code PropertyDescriptors} for the given class * @throws BeansException if PropertyDescriptor look fails */ public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException { CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz); return cr.getPropertyDescriptors(); }
PropertyDescriptor[] getPropertyDescriptors() { PropertyDescriptor[] pds = new PropertyDescriptor[this.propertyDescriptorCache.size()]; int i = 0; for (PropertyDescriptor pd : this.propertyDescriptorCache.values()) { pds[i] = (pd instanceof GenericTypeAwarePropertyDescriptor ? pd : buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd)); i++; } return pds; }
@Test public void acceptAndClearClassLoader() throws Exception { BeanWrapper bw = new BeanWrapperImpl(TestBean.class); assertTrue(bw.isWritableProperty("name")); assertTrue(bw.isWritableProperty("age")); assertTrue(CachedIntrospectionResults.strongClassCache.containsKey(TestBean.class)); ClassLoader child = new OverridingClassLoader(getClass().getClassLoader()); Class<?> tbClass = child.loadClass("org.springframework.tests.sample.beans.TestBean"); assertFalse(CachedIntrospectionResults.strongClassCache.containsKey(tbClass)); CachedIntrospectionResults.acceptClassLoader(child); bw = new BeanWrapperImpl(tbClass); assertTrue(bw.isWritableProperty("name")); assertTrue(bw.isWritableProperty("age")); assertTrue(CachedIntrospectionResults.strongClassCache.containsKey(tbClass)); CachedIntrospectionResults.clearClassLoader(child); assertFalse(CachedIntrospectionResults.strongClassCache.containsKey(tbClass)); assertTrue(CachedIntrospectionResults.strongClassCache.containsKey(TestBean.class)); }
private void introspectInterfaces(Class<?> beanClass, Class<?> currClass) throws IntrospectionException { for (Class<?> ifc : currClass.getInterfaces()) { if (!ClassUtils.isJavaLanguageInterface(ifc)) { for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) { PropertyDescriptor existingPd = this.propertyDescriptorCache.get(pd.getName()); if (existingPd == null || (existingPd.getReadMethod() == null && pd.getReadMethod() != null)) { // GenericTypeAwarePropertyDescriptor leniently resolves a set* write method // against a declared read method, so we prefer read method descriptors here. pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd); this.propertyDescriptorCache.put(pd.getName(), pd); } } introspectInterfaces(ifc, ifc); } } }
/** * Convert the given value for the specified property to the latter's type. * <p>This method is only intended for optimizations in a BeanFactory. * Use the {@code convertIfNecessary} methods for programmatic conversion. * @param value the value to convert * @param propertyName the target property * (note that nested or indexed properties are not supported here) * @return the new value, possibly the result of type conversion * @throws TypeMismatchException if type conversion failed */ @Nullable public Object convertForProperty(@Nullable Object value, String propertyName) throws TypeMismatchException { CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults(); PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName); if (pd == null) { throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName, "No property '" + propertyName + "' found"); } TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd); if (td == null) { td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd))); } return convertForProperty(propertyName, null, value, td); }
@Override @Nullable protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) { PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName); return (pd != null ? new BeanPropertyHandler(pd) : null); }
@Test public void shouldUseExtendedBeanInfoWhenApplicable() throws NoSuchMethodException, SecurityException { // given a class with a non-void returning setter method @SuppressWarnings("unused") class C { public Object setFoo(String s) { return this; } public String getFoo() { return null; } } // CachedIntrospectionResults should delegate to ExtendedBeanInfo CachedIntrospectionResults results = CachedIntrospectionResults.forClass(C.class); BeanInfo info = results.getBeanInfo(); PropertyDescriptor pd = null; for (PropertyDescriptor candidate : info.getPropertyDescriptors()) { if (candidate.getName().equals("foo")) { pd = candidate; } } // resulting in a property descriptor including the non-standard setFoo method assertThat(pd, notNullValue()); assertThat(pd.getReadMethod(), equalTo(C.class.getMethod("getFoo"))); assertThat( "No write method found for non-void returning 'setFoo' method. " + "Check to see if CachedIntrospectionResults is delegating to " + "ExtendedBeanInfo as expected", pd.getWriteMethod(), equalTo(C.class.getMethod("setFoo", String.class))); }
/** * Obtain a lazily initialized CachedIntrospectionResults instance * for the wrapped object. */ private CachedIntrospectionResults getCachedIntrospectionResults() { if (this.cachedIntrospectionResults == null) { this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(getWrappedClass()); } return this.cachedIntrospectionResults; }
@Override public void contextInitialized(ServletContextEvent event) { CachedIntrospectionResults.acceptClassLoader(Thread.currentThread().getContextClassLoader()); }
/** * Set the class to introspect. * Needs to be called when the target object changes. * @param clazz the class to introspect */ protected void setIntrospectionClass(Class clazz) { if (this.cachedIntrospectionResults == null || !this.cachedIntrospectionResults.getBeanClass().equals(clazz)) { this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(clazz); } }
/** * Set the class to introspect. * Needs to be called when the target object changes. * @param clazz the class to introspect */ protected void setIntrospectionClass(Class<?> clazz) { if (this.cachedIntrospectionResults != null && this.cachedIntrospectionResults.getBeanClass() != clazz) { this.cachedIntrospectionResults = null; } }
beanInfo = beanInfoFactory.getBeanInfo(beanClass); if (beanInfo != null) { break; Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) : Introspector.getBeanInfo(beanClass)); "; editor [" + pd.getPropertyEditorClass().getName() + "]" : "")); pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd); this.propertyDescriptorCache.put(pd.getName(), pd); Class<?>[] ifcs = clazz.getInterfaces(); for (Class<?> ifc : ifcs) { BeanInfo ifcInfo = Introspector.getBeanInfo(ifc, Introspector.IGNORE_ALL_BEANINFO); PropertyDescriptor[] ifcPds = ifcInfo.getPropertyDescriptors(); for (PropertyDescriptor pd : ifcPds) { if (!this.propertyDescriptorCache.containsKey(pd.getName())) { pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd); this.propertyDescriptorCache.put(pd.getName(), pd);
results = new CachedIntrospectionResults(clazz); boolean cacheSafe = isCacheSafe(clazz); if (logger.isDebugEnabled()) { logger.debug("Class [" + clazz.getName() + "] is " + (!cacheSafe ? "not " : "") + "cache-safe");
public PropertyDescriptor[] getPropertyDescriptors() { return this.cachedIntrospectionResults.getBeanInfo().getPropertyDescriptors(); }
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
PropertyDescriptor[] getPropertyDescriptors() { PropertyDescriptor[] pds = new PropertyDescriptor[this.propertyDescriptorCache.size()]; int i = 0; for (PropertyDescriptor pd : this.propertyDescriptorCache.values()) { pds[i] = (pd instanceof GenericTypeAwarePropertyDescriptor ? pd : buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd)); i++; } return pds; }
private void introspectInterfaces(Class<?> beanClass, Class<?> currClass) throws IntrospectionException { for (Class<?> ifc : currClass.getInterfaces()) { if (!ClassUtils.isJavaLanguageInterface(ifc)) { for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) { PropertyDescriptor existingPd = this.propertyDescriptorCache.get(pd.getName()); if (existingPd == null || (existingPd.getReadMethod() == null && pd.getReadMethod() != null)) { // GenericTypeAwarePropertyDescriptor leniently resolves a set* write method // against a declared read method, so we prefer read method descriptors here. pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd); this.propertyDescriptorCache.put(pd.getName(), pd); } } introspectInterfaces(ifc, ifc); } } }