diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java b/spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java index 2aefdc240d..fe26c29d85 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java @@ -23,17 +23,18 @@ import java.beans.IntrospectionException; * Strategy for creating {@link BeanInfo} instances. * *

BeanInfoFactories are are instantiated by the {@link CachedIntrospectionResults}, - * which looks for {@code META-INF/spring.beanInfoFactories} files on the class path. - * These files contain one or more {@code BeanInfoFactory} class names, each of a single - * line. When a {@link BeanInfo} is to be created, the {@code CachedIntrospectionResults} - * will iterate through the discovered factories, asking each one if it {@linkplain - * #supports(Class) supports} the given bean class. If it does, {@link - * #getBeanInfo(Class)} will be called; if not, the next factory will be queried. If none - * of the factories support the class, an standard {@link BeanInfo} is created as a - * default. + * by using the {@link org.springframework.core.io.support.SpringFactoriesLoader} utility + * class. * - *

Note that the {@link CachedIntrospectionResults} sorts the {@code BeanInfoFactory} - * instances by {@link org.springframework.core.annotation.Order Order}, so that ones with + * When a {@link BeanInfo} is to be created, the {@code CachedIntrospectionResults} + * will iterate through the discovered factories, calling {@link + * #getBeanInfo(Class)} on each one. If {@code null} is returned, the next factory will + * be queried. If none of the factories support the class, an standard {@link BeanInfo} + * is created as a default. + * + *

Note that the {@link org.springframework.core.io.support.SpringFactoriesLoader} + * sorts the {@code BeanInfoFactory} instances by + * {@link org.springframework.core.annotation.Order @Order}, so that ones with * a higher precedence come first. * * @author Arjen Poutsma @@ -42,18 +43,10 @@ import java.beans.IntrospectionException; public interface BeanInfoFactory { /** - * Indicates whether a bean with the given class is supported by this factory. + * Returns the bean info for the given class, if supported. * * @param beanClass the bean class - * @return {@code true} if supported; {@code false} otherwise - */ - boolean supports(Class beanClass); - - /** - * Returns the bean info for the given class. - * - * @param beanClass the bean class - * @return the bean info + * @return the bean info, or {@code null} if not the given class is not supported * @throws IntrospectionException in case of exceptions */ BeanInfo getBeanInfo(Class beanClass) throws IntrospectionException; 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 c0da75ffcc..8da24fc802 100644 --- a/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java +++ b/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java @@ -20,25 +20,21 @@ import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; -import java.io.IOException; import java.lang.ref.Reference; import java.lang.ref.WeakReference; -import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.Set; import java.util.WeakHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; -import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -64,12 +60,6 @@ import org.springframework.util.StringUtils; */ public class CachedIntrospectionResults { - /** - * The location to look for the bean info mapping files. Can be present in multiple JAR files. - */ - public static final String BEAN_INFO_FACTORIES_LOCATION = "META-INF/spring.beanInfoFactories"; - - private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class); /** @@ -242,8 +232,8 @@ public class CachedIntrospectionResults { BeanInfo beanInfo = null; List beanInfoFactories = getBeanInfoFactories(beanClass.getClassLoader()); for (BeanInfoFactory beanInfoFactory : beanInfoFactories) { - if (beanInfoFactory.supports(beanClass)) { - beanInfo = beanInfoFactory.getBeanInfo(beanClass); + beanInfo = beanInfoFactory.getBeanInfo(beanClass); + if (beanInfo != null) { break; } } @@ -339,57 +329,12 @@ public class CachedIntrospectionResults { if (beanInfoFactories == null) { synchronized (beanInfoFactoriesMutex) { if (beanInfoFactories == null) { - try { - Properties properties = - PropertiesLoaderUtils.loadAllProperties( - BEAN_INFO_FACTORIES_LOCATION, classLoader); - - if (logger.isDebugEnabled()) { - logger.debug("Loaded BeanInfoFactories: " + properties.keySet()); - } - - List factories = new ArrayList(properties.size()); - - for (Object key : properties.keySet()) { - if (key instanceof String) { - String className = (String) key; - BeanInfoFactory factory = instantiateBeanInfoFactory(className, classLoader); - factories.add(factory); - } - } - - Collections.sort(factories, new AnnotationAwareOrderComparator()); - - beanInfoFactories = Collections.synchronizedList(factories); - } - catch (IOException ex) { - throw new IllegalStateException( - "Unable to load BeanInfoFactories from location [" + BEAN_INFO_FACTORIES_LOCATION + "]", ex); - } + beanInfoFactories = Collections.synchronizedList(SpringFactoriesLoader + .loadFactories(BeanInfoFactory.class, classLoader)); } } } return beanInfoFactories; } - private static BeanInfoFactory instantiateBeanInfoFactory(String className, - ClassLoader classLoader) { - try { - Class factoryClass = ClassUtils.forName(className, classLoader); - if (!BeanInfoFactory.class.isAssignableFrom(factoryClass)) { - throw new FatalBeanException( - "Class [" + className + "] does not implement the [" + - BeanInfoFactory.class.getName() + "] interface"); - } - return (BeanInfoFactory) BeanUtils.instantiate(factoryClass); - } - catch (ClassNotFoundException ex) { - throw new FatalBeanException( - "BeanInfoFactory class [" + className + "] not found", ex); - } - catch (LinkageError err) { - throw new FatalBeanException("Invalid BeanInfoFactory class [" + className + - "]: problem with handler class file or dependent class", err); - } - } } diff --git a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java index 5f6256621f..2eafdea317 100644 --- a/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java @@ -19,7 +19,6 @@ package org.springframework.beans; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; - import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -37,13 +36,21 @@ import org.springframework.core.Ordered; * @since 3.2 * @see BeanInfoFactory */ -class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory { +public class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory { + + /** + * Return a new {@link ExtendedBeanInfo} for the given bean class. + */ + public BeanInfo getBeanInfo(Class beanClass) throws IntrospectionException { + return supports(beanClass) ? + new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null; + } /** * Return whether the given bean class declares or inherits any non-void returning * JavaBeans or indexed property setter methods. */ - public boolean supports(Class beanClass) { + private boolean supports(Class beanClass) { for (Method method : beanClass.getMethods()) { String methodName = method.getName(); Class[] parameterTypes = method.getParameterTypes(); @@ -59,13 +66,6 @@ class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory { return false; } - /** - * Return a new {@link ExtendedBeanInfo} for the given bean class. - */ - public BeanInfo getBeanInfo(Class beanClass) throws IntrospectionException { - return new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)); - } - public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } diff --git a/spring-beans/src/main/resources/META-INF/spring.beanInfoFactories b/spring-beans/src/main/resources/META-INF/spring.beanInfoFactories deleted file mode 100644 index 7a104edec2..0000000000 --- a/spring-beans/src/main/resources/META-INF/spring.beanInfoFactories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.beans.ExtendedBeanInfoFactory diff --git a/spring-beans/src/main/resources/META-INF/spring.factories b/spring-beans/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..b623047ec2 --- /dev/null +++ b/spring-beans/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory \ No newline at end of file diff --git a/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoFactoryTests.java index d56b672e5b..d2ee119f81 100644 --- a/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoFactoryTests.java @@ -18,11 +18,11 @@ package org.springframework.beans; import java.beans.IntrospectionException; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; import org.junit.Test; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - /** * Unit tests for {@link ExtendedBeanInfoTests}. * @@ -38,7 +38,7 @@ public class ExtendedBeanInfoFactoryTests { class C { public void setFoo(String s) { } } - assertThat(factory.supports(C.class), is(false)); + assertThat(factory.getBeanInfo(C.class), nullValue()); } @Test @@ -47,7 +47,7 @@ public class ExtendedBeanInfoFactoryTests { class C { public C setFoo(String s) { return this; } } - assertThat(factory.supports(C.class), is(true)); + assertThat(factory.getBeanInfo(C.class), notNullValue()); } @Test @@ -56,7 +56,7 @@ public class ExtendedBeanInfoFactoryTests { class C { public C setFoo(int i, String s) { return this; } } - assertThat(factory.supports(C.class), is(true)); + assertThat(factory.getBeanInfo(C.class), notNullValue()); } @Test @@ -65,7 +65,7 @@ public class ExtendedBeanInfoFactoryTests { class C { void setBar(String s) { } } - assertThat(factory.supports(C.class), is(false)); + assertThat(factory.getBeanInfo(C.class), nullValue()); } @Test @@ -74,7 +74,7 @@ public class ExtendedBeanInfoFactoryTests { class C { C setBar() { return this; } } - assertThat(factory.supports(C.class), is(false)); + assertThat(factory.getBeanInfo(C.class), nullValue()); } @Test @@ -83,7 +83,7 @@ public class ExtendedBeanInfoFactoryTests { class C { C set(String s) { return this; } } - assertThat(factory.supports(C.class), is(false)); + assertThat(factory.getBeanInfo(C.class), nullValue()); } }