Skip to content

Commit d890a38

Browse files
committed
Support registration of non-public BeanDefinitionReader via @⁠ImportResource
Prior to this commit, a BeanDefinitionReader registered via @⁠ImportResource was required to be public and have a public constructor that accepts a single BeanDefinitionRegistry. However, the public visibility requirements are not necessary, and the requirements for the constructor's formal parameter list is not documented. To address those issues, this commit removes the public visibility restrictions and documents that a BeanDefinitionReader registered via @⁠ImportResource must declare a constructor that accepts a single BeanDefinitionRegistry. In addition, this commit includes the cause of the instantiation failure in case the registered BeanDefinitionReader cannot be instantiated. Closes gh-34928
1 parent 98cef50 commit d890a38

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.context.annotation;
1818

19+
import java.lang.reflect.Constructor;
1920
import java.lang.reflect.Method;
2021
import java.util.ArrayList;
2122
import java.util.Arrays;
@@ -27,6 +28,7 @@
2728
import org.apache.commons.logging.Log;
2829
import org.apache.commons.logging.LogFactory;
2930

31+
import org.springframework.beans.BeanUtils;
3032
import org.springframework.beans.factory.BeanDefinitionStoreException;
3133
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
3234
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
@@ -371,9 +373,11 @@ private void loadBeanDefinitionsFromImportedResources(
371373
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
372374
if (reader == null) {
373375
try {
376+
Constructor<? extends BeanDefinitionReader> constructor =
377+
readerClass.getDeclaredConstructor(BeanDefinitionRegistry.class);
374378
// Instantiate the specified BeanDefinitionReader
375-
reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
376-
// Delegate the current ResourceLoader to it if possible
379+
reader = BeanUtils.instantiateClass(constructor, this.registry);
380+
// Delegate the current ResourceLoader and Environment to it if possible
377381
if (reader instanceof AbstractBeanDefinitionReader abdr) {
378382
abdr.setResourceLoader(this.resourceLoader);
379383
abdr.setEnvironment(this.environment);
@@ -382,7 +386,7 @@ private void loadBeanDefinitionsFromImportedResources(
382386
}
383387
catch (Throwable ex) {
384388
throw new IllegalStateException(
385-
"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
389+
"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]", ex);
386390
}
387391
}
388392
reader.loadBeanDefinitions(resource);

spring-context/src/main/java/org/springframework/context/annotation/ImportResource.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@
8080
* {@link BeanDefinitionReader} implementation to use when processing
8181
* resources specified via the {@link #locations() locations} or
8282
* {@link #value() value} attribute.
83+
* <p>The configured {@code BeanDefinitionReader} type must declare a
84+
* constructor that accepts a single
85+
* {@link org.springframework.beans.factory.support.BeanDefinitionRegistry
86+
* BeanDefinitionRegistry} argument.
8387
* <p>By default, the reader will be adapted to the resource path specified:
8488
* {@code ".groovy"} files will be processed with a
8589
* {@link org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader

spring-context/src/test/java/org/springframework/context/annotation/configuration/ImportResourceTests.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.aop.support.AopUtils;
2424
import org.springframework.beans.factory.annotation.Autowired;
2525
import org.springframework.beans.factory.annotation.Value;
26+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2627
import org.springframework.beans.testfixture.beans.TestBean;
2728
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
2829
import org.springframework.context.annotation.Bean;
@@ -109,6 +110,13 @@ void importNonXmlResource() {
109110
}
110111
}
111112

113+
@Test
114+
void importResourceWithPrivateReader() {
115+
try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ImportWithPrivateReaderConfig.class)) {
116+
assertThat(ctx.containsBean("propertiesDeclaredBean")).isTrue();
117+
}
118+
}
119+
112120

113121
@Configuration
114122
@ImportResource("classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml")
@@ -173,4 +181,20 @@ public String xmlBeanName() {
173181
static class ImportNonXmlResourceConfig {
174182
}
175183

184+
@SuppressWarnings("deprecation")
185+
@Configuration
186+
@ImportResource(locations = "org/springframework/context/annotation/configuration/ImportNonXmlResourceConfig.properties",
187+
reader = PrivatePropertiesBeanDefinitionReader.class)
188+
static class ImportWithPrivateReaderConfig {
189+
}
190+
191+
@SuppressWarnings("deprecation")
192+
private static class PrivatePropertiesBeanDefinitionReader
193+
extends org.springframework.beans.factory.support.PropertiesBeanDefinitionReader {
194+
195+
PrivatePropertiesBeanDefinitionReader(BeanDefinitionRegistry registry) {
196+
super(registry);
197+
}
198+
}
199+
176200
}

0 commit comments

Comments
 (0)