Skip to content

Commit 82739dd

Browse files
committed
Refactor BeanInfoFactory
This commit refactors the BeanInfoFactory so that: - supports() and getBeanInfo() are folded into one, so that getBeanInfo() returns null if a given class is not supported. - CachedIntrospectionResults now uses SpringFactoriesLoader
1 parent aeff91c commit 82739dd

File tree

6 files changed

+38
-100
lines changed

6 files changed

+38
-100
lines changed

spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,18 @@
2323
* Strategy for creating {@link BeanInfo} instances.
2424
*
2525
* <p>BeanInfoFactories are are instantiated by the {@link CachedIntrospectionResults},
26-
* which looks for {@code META-INF/spring.beanInfoFactories} files on the class path.
27-
* These files contain one or more {@code BeanInfoFactory} class names, each of a single
28-
* line. When a {@link BeanInfo} is to be created, the {@code CachedIntrospectionResults}
29-
* will iterate through the discovered factories, asking each one if it {@linkplain
30-
* #supports(Class) supports} the given bean class. If it does, {@link
31-
* #getBeanInfo(Class)} will be called; if not, the next factory will be queried. If none
32-
* of the factories support the class, an standard {@link BeanInfo} is created as a
33-
* default.
26+
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader} utility
27+
* class.
3428
*
35-
* <p>Note that the {@link CachedIntrospectionResults} sorts the {@code BeanInfoFactory}
36-
* instances by {@link org.springframework.core.annotation.Order Order}, so that ones with
29+
* When a {@link BeanInfo} is to be created, the {@code CachedIntrospectionResults}
30+
* will iterate through the discovered factories, calling {@link
31+
* #getBeanInfo(Class)} on each one. If {@code null} is returned, the next factory will
32+
* be queried. If none of the factories support the class, an standard {@link BeanInfo}
33+
* is created as a default.
34+
*
35+
* <p>Note that the {@link org.springframework.core.io.support.SpringFactoriesLoader}
36+
* sorts the {@code BeanInfoFactory} instances by
37+
* {@link org.springframework.core.annotation.Order @Order}, so that ones with
3738
* a higher precedence come first.
3839
*
3940
* @author Arjen Poutsma
@@ -42,18 +43,10 @@
4243
public interface BeanInfoFactory {
4344

4445
/**
45-
* Indicates whether a bean with the given class is supported by this factory.
46-
*
47-
* @param beanClass the bean class
48-
* @return {@code true} if supported; {@code false} otherwise
49-
*/
50-
boolean supports(Class<?> beanClass);
51-
52-
/**
53-
* Returns the bean info for the given class.
46+
* Returns the bean info for the given class, if supported.
5447
*
5548
* @param beanClass the bean class
56-
* @return the bean info
49+
* @return the bean info, or {@code null} if not the given class is not supported
5750
* @throws IntrospectionException in case of exceptions
5851
*/
5952
BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException;

spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java

Lines changed: 5 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,21 @@
2020
import java.beans.IntrospectionException;
2121
import java.beans.Introspector;
2222
import java.beans.PropertyDescriptor;
23-
import java.io.IOException;
2423
import java.lang.ref.Reference;
2524
import java.lang.ref.WeakReference;
26-
import java.util.ArrayList;
2725
import java.util.Collections;
2826
import java.util.HashSet;
2927
import java.util.Iterator;
3028
import java.util.LinkedHashMap;
3129
import java.util.List;
3230
import java.util.Map;
33-
import java.util.Properties;
3431
import java.util.Set;
3532
import java.util.WeakHashMap;
3633

3734
import org.apache.commons.logging.Log;
3835
import org.apache.commons.logging.LogFactory;
3936

40-
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
41-
import org.springframework.core.io.support.PropertiesLoaderUtils;
37+
import org.springframework.core.io.support.SpringFactoriesLoader;
4238
import org.springframework.util.ClassUtils;
4339
import org.springframework.util.StringUtils;
4440

@@ -64,12 +60,6 @@
6460
*/
6561
public class CachedIntrospectionResults {
6662

67-
/**
68-
* The location to look for the bean info mapping files. Can be present in multiple JAR files.
69-
*/
70-
public static final String BEAN_INFO_FACTORIES_LOCATION = "META-INF/spring.beanInfoFactories";
71-
72-
7363
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
7464

7565
/**
@@ -242,8 +232,8 @@ private CachedIntrospectionResults(Class beanClass, boolean cacheFullMetadata) t
242232
BeanInfo beanInfo = null;
243233
List<BeanInfoFactory> beanInfoFactories = getBeanInfoFactories(beanClass.getClassLoader());
244234
for (BeanInfoFactory beanInfoFactory : beanInfoFactories) {
245-
if (beanInfoFactory.supports(beanClass)) {
246-
beanInfo = beanInfoFactory.getBeanInfo(beanClass);
235+
beanInfo = beanInfoFactory.getBeanInfo(beanClass);
236+
if (beanInfo != null) {
247237
break;
248238
}
249239
}
@@ -339,57 +329,12 @@ private static List<BeanInfoFactory> getBeanInfoFactories(ClassLoader classLoade
339329
if (beanInfoFactories == null) {
340330
synchronized (beanInfoFactoriesMutex) {
341331
if (beanInfoFactories == null) {
342-
try {
343-
Properties properties =
344-
PropertiesLoaderUtils.loadAllProperties(
345-
BEAN_INFO_FACTORIES_LOCATION, classLoader);
346-
347-
if (logger.isDebugEnabled()) {
348-
logger.debug("Loaded BeanInfoFactories: " + properties.keySet());
349-
}
350-
351-
List<BeanInfoFactory> factories = new ArrayList<BeanInfoFactory>(properties.size());
352-
353-
for (Object key : properties.keySet()) {
354-
if (key instanceof String) {
355-
String className = (String) key;
356-
BeanInfoFactory factory = instantiateBeanInfoFactory(className, classLoader);
357-
factories.add(factory);
358-
}
359-
}
360-
361-
Collections.sort(factories, new AnnotationAwareOrderComparator());
362-
363-
beanInfoFactories = Collections.synchronizedList(factories);
364-
}
365-
catch (IOException ex) {
366-
throw new IllegalStateException(
367-
"Unable to load BeanInfoFactories from location [" + BEAN_INFO_FACTORIES_LOCATION + "]", ex);
368-
}
332+
beanInfoFactories = Collections.synchronizedList(SpringFactoriesLoader
333+
.loadFactories(BeanInfoFactory.class, classLoader));
369334
}
370335
}
371336
}
372337
return beanInfoFactories;
373338
}
374339

375-
private static BeanInfoFactory instantiateBeanInfoFactory(String className,
376-
ClassLoader classLoader) {
377-
try {
378-
Class<?> factoryClass = ClassUtils.forName(className, classLoader);
379-
if (!BeanInfoFactory.class.isAssignableFrom(factoryClass)) {
380-
throw new FatalBeanException(
381-
"Class [" + className + "] does not implement the [" +
382-
BeanInfoFactory.class.getName() + "] interface");
383-
}
384-
return (BeanInfoFactory) BeanUtils.instantiate(factoryClass);
385-
}
386-
catch (ClassNotFoundException ex) {
387-
throw new FatalBeanException(
388-
"BeanInfoFactory class [" + className + "] not found", ex);
389-
}
390-
catch (LinkageError err) {
391-
throw new FatalBeanException("Invalid BeanInfoFactory class [" + className +
392-
"]: problem with handler class file or dependent class", err);
393-
}
394-
}
395340
}

spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.beans.BeanInfo;
2020
import java.beans.IntrospectionException;
2121
import java.beans.Introspector;
22-
2322
import java.lang.reflect.Method;
2423
import java.lang.reflect.Modifier;
2524

@@ -37,13 +36,21 @@
3736
* @since 3.2
3837
* @see BeanInfoFactory
3938
*/
40-
class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory {
39+
public class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory {
40+
41+
/**
42+
* Return a new {@link ExtendedBeanInfo} for the given bean class.
43+
*/
44+
public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
45+
return supports(beanClass) ?
46+
new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null;
47+
}
4148

4249
/**
4350
* Return whether the given bean class declares or inherits any non-void returning
4451
* JavaBeans or <em>indexed property</em> setter methods.
4552
*/
46-
public boolean supports(Class<?> beanClass) {
53+
private boolean supports(Class<?> beanClass) {
4754
for (Method method : beanClass.getMethods()) {
4855
String methodName = method.getName();
4956
Class<?>[] parameterTypes = method.getParameterTypes();
@@ -59,13 +66,6 @@ public boolean supports(Class<?> beanClass) {
5966
return false;
6067
}
6168

62-
/**
63-
* Return a new {@link ExtendedBeanInfo} for the given bean class.
64-
*/
65-
public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
66-
return new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass));
67-
}
68-
6969
public int getOrder() {
7070
return Ordered.LOWEST_PRECEDENCE;
7171
}

spring-beans/src/main/resources/META-INF/spring.beanInfoFactories

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory

spring-beans/src/test/java/org/springframework/beans/ExtendedBeanInfoFactoryTests.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818

1919
import java.beans.IntrospectionException;
2020

21+
import static org.hamcrest.CoreMatchers.notNullValue;
22+
import static org.hamcrest.CoreMatchers.nullValue;
23+
import static org.junit.Assert.assertThat;
2124
import org.junit.Test;
2225

23-
import static org.hamcrest.CoreMatchers.*;
24-
import static org.junit.Assert.*;
25-
2626
/**
2727
* Unit tests for {@link ExtendedBeanInfoTests}.
2828
*
@@ -38,7 +38,7 @@ public void shouldNotSupportClassHavingOnlyVoidReturningSetter() throws Introspe
3838
class C {
3939
public void setFoo(String s) { }
4040
}
41-
assertThat(factory.supports(C.class), is(false));
41+
assertThat(factory.getBeanInfo(C.class), nullValue());
4242
}
4343

4444
@Test
@@ -47,7 +47,7 @@ public void shouldSupportClassHavingNonVoidReturningSetter() throws Introspectio
4747
class C {
4848
public C setFoo(String s) { return this; }
4949
}
50-
assertThat(factory.supports(C.class), is(true));
50+
assertThat(factory.getBeanInfo(C.class), notNullValue());
5151
}
5252

5353
@Test
@@ -56,7 +56,7 @@ public void shouldSupportClassHavingNonVoidReturningIndexedSetter() throws Intro
5656
class C {
5757
public C setFoo(int i, String s) { return this; }
5858
}
59-
assertThat(factory.supports(C.class), is(true));
59+
assertThat(factory.getBeanInfo(C.class), notNullValue());
6060
}
6161

6262
@Test
@@ -65,7 +65,7 @@ public void shouldNotSupportClassHavingNonPublicNonVoidReturningIndexedSetter()
6565
class C {
6666
void setBar(String s) { }
6767
}
68-
assertThat(factory.supports(C.class), is(false));
68+
assertThat(factory.getBeanInfo(C.class), nullValue());
6969
}
7070

7171
@Test
@@ -74,7 +74,7 @@ public void shouldNotSupportClassHavingNonVoidReturningParameterlessSetter() thr
7474
class C {
7575
C setBar() { return this; }
7676
}
77-
assertThat(factory.supports(C.class), is(false));
77+
assertThat(factory.getBeanInfo(C.class), nullValue());
7878
}
7979

8080
@Test
@@ -83,7 +83,7 @@ public void shouldNotSupportClassHavingNonVoidReturningMethodNamedSet() throws I
8383
class C {
8484
C set(String s) { return this; }
8585
}
86-
assertThat(factory.supports(C.class), is(false));
86+
assertThat(factory.getBeanInfo(C.class), nullValue());
8787
}
8888

8989
}

0 commit comments

Comments
 (0)