From 984ab07cd08a8e67490ca2b4e85d040e976204c0 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 22 Dec 2017 11:37:12 -0800 Subject: [PATCH] Use BeanInfoFactory when introspecting interfaces Update `CachedIntrospectionResults` to use `BeanInfoFactory` implementations when introspecting interfaces. Also add a couple of optimizations to save introspection of `Object` and `Serializable`. Issue: SPR-16322 --- .../beans/CachedIntrospectionResults.java | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java b/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java index 37ade58ce8c8..ff4d2c0db249 100644 --- a/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java +++ b/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java @@ -20,7 +20,10 @@ import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; +import java.io.Serializable; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -38,6 +41,7 @@ import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentReferenceHashMap; +import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; /** @@ -93,6 +97,8 @@ public class CachedIntrospectionResults { */ public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore"; + private static final Set> IGNORED_INTERFACES = Collections.unmodifiableSet( + new HashSet<>(Arrays.asList(Serializable.class))); private static final boolean shouldIntrospectorIgnoreBeaninfoClasses = SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME); @@ -266,13 +272,7 @@ private CachedIntrospectionResults(Class beanClass) throws BeansException { logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]"); } - BeanInfo beanInfo = null; - for (BeanInfoFactory beanInfoFactory : beanInfoFactories) { - beanInfo = beanInfoFactory.getBeanInfo(beanClass); - if (beanInfo != null) { - break; - } - } + BeanInfo beanInfo = getBeanInfoFromFactories(beanClass); if (beanInfo == null) { // If none of the factories supported the class, fall back to the default beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ? @@ -307,15 +307,20 @@ private CachedIntrospectionResults(Class beanClass) throws BeansException { // Explicitly check implemented interfaces for setter/getter methods as well, // in particular for Java 8 default methods... Class clazz = beanClass; - while (clazz != null) { + while (clazz != null && !Object.class.equals(clazz)) { 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); + if (! IGNORED_INTERFACES.contains(ifc)) { + BeanInfo ifcInfo = getBeanInfoFromFactories(ifc); + if (ifcInfo == null) { + 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); + } } } } @@ -329,6 +334,17 @@ private CachedIntrospectionResults(Class beanClass) throws BeansException { } } + private BeanInfo getBeanInfoFromFactories(Class beanClass) + throws IntrospectionException { + for (BeanInfoFactory beanInfoFactory : beanInfoFactories) { + BeanInfo beanInfo = beanInfoFactory.getBeanInfo(beanClass); + if (beanInfo != null) { + return beanInfo; + } + } + return null; + } + BeanInfo getBeanInfo() { return this.beanInfo; }