Skip to content

Commit f94b5bc

Browse files
committed
Support @import on interfaces
Closes spring-projectsgh-34805 Signed-off-by: Daeho Kwon <[email protected]>
1 parent 52265a5 commit f94b5bc

File tree

2 files changed

+59
-18
lines changed

2 files changed

+59
-18
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
* @author Phillip Webb
9999
* @author Sam Brannen
100100
* @author Stephane Nicoll
101+
* @author Daeho Kwon
101102
* @since 3.0
102103
* @see ConfigurationClassBeanDefinitionReader
103104
*/
@@ -549,6 +550,9 @@ private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException
549550
* <p>For example, it is common for a {@code @Configuration} class to declare direct
550551
* {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
551552
* annotation.
553+
* <p>In addition, {@code @Import} annotations declared on interfaces implemented by
554+
* the configuration class are also considered. This allows imports to be triggered
555+
* indirectly via marker interfaces or shared base interfaces.
552556
* @param sourceClass the class to search
553557
* @param imports the imports collected so far
554558
* @param visited used to track visited classes to prevent infinite recursion
@@ -565,6 +569,10 @@ private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, S
565569
}
566570
}
567571
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
572+
573+
for (SourceClass ifc : sourceClass.getInterfaces()) {
574+
collectImports(ifc, imports, visited);
575+
}
568576
}
569577
}
570578

spring-context/src/test/java/org/springframework/context/annotation/ImportSelectorTests.java

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
*
6363
* @author Phillip Webb
6464
* @author Stephane Nicoll
65+
* @author Daeho Kwon
6566
*/
6667
@SuppressWarnings("resource")
6768
public class ImportSelectorTests {
@@ -152,7 +153,7 @@ void importSelectorsSeparateWithGroup() {
152153
ordered.verify(beanFactory).registerBeanDefinition(eq("d"), any());
153154
assertThat(TestImportGroup.instancesCount.get()).isEqualTo(1);
154155
assertThat(TestImportGroup.imports.keySet().stream().map(AnnotationMetadata::getClassName))
155-
.containsExactly(GroupedConfig2.class.getName(),GroupedConfig1.class.getName());
156+
.containsExactly(GroupedConfig2.class.getName(), GroupedConfig1.class.getName());
156157
}
157158

158159
@Test
@@ -168,11 +169,11 @@ void importSelectorsWithNestedGroup() {
168169
assertThat(TestImportGroup.instancesCount.get()).isEqualTo(2);
169170
assertThat(TestImportGroup.imports).hasSize(2);
170171
assertThat(TestImportGroup.allImports())
171-
.containsOnlyKeys(ParentConfiguration1.class.getName(), ChildConfiguration1.class.getName());
172+
.containsOnlyKeys(ParentConfiguration1.class.getName(), ChildConfiguration1.class.getName());
172173
assertThat(TestImportGroup.allImports().get(ParentConfiguration1.class.getName()))
173-
.containsExactly(DeferredImportSelector1.class.getName(), ChildConfiguration1.class.getName());
174+
.containsExactly(DeferredImportSelector1.class.getName(), ChildConfiguration1.class.getName());
174175
assertThat(TestImportGroup.allImports().get(ChildConfiguration1.class.getName()))
175-
.containsExactly(DeferredImportedSelector3.class.getName());
176+
.containsExactly(DeferredImportedSelector3.class.getName());
176177
}
177178

178179
@Test
@@ -187,11 +188,11 @@ void importSelectorsWithNestedGroupSameDeferredImport() {
187188
assertThat(TestImportGroup.instancesCount.get()).isEqualTo(2);
188189
assertThat(TestImportGroup.allImports()).hasSize(2);
189190
assertThat(TestImportGroup.allImports())
190-
.containsOnlyKeys(ParentConfiguration2.class.getName(), ChildConfiguration2.class.getName());
191+
.containsOnlyKeys(ParentConfiguration2.class.getName(), ChildConfiguration2.class.getName());
191192
assertThat(TestImportGroup.allImports().get(ParentConfiguration2.class.getName()))
192-
.containsExactly(DeferredImportSelector2.class.getName(), ChildConfiguration2.class.getName());
193+
.containsExactly(DeferredImportSelector2.class.getName(), ChildConfiguration2.class.getName());
193194
assertThat(TestImportGroup.allImports().get(ChildConfiguration2.class.getName()))
194-
.containsExactly(DeferredImportSelector2.class.getName());
195+
.containsExactly(DeferredImportSelector2.class.getName());
195196
}
196197

197198
@Test
@@ -203,6 +204,38 @@ void invokeAwareMethodsInImportGroup() {
203204
assertThat(TestImportGroup.environment).isEqualTo(context.getEnvironment());
204205
}
205206

207+
@Test
208+
void importAnnotationOnImplementedInterfaceIsRespected() {
209+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
210+
context.register(InterfaceBasedConfig.class);
211+
context.refresh();
212+
213+
assertThat(context.getBean(ImportedConfig.class)).isNotNull();
214+
assertThat(context.getBean(ImportedBean.class)).isNotNull();
215+
assertThat(context.getBean(ImportedBean.class).name()).isEqualTo("imported");
216+
}
217+
218+
@Import(ImportedConfig.class)
219+
interface ConfigImportMarker {
220+
}
221+
222+
@Configuration
223+
static class InterfaceBasedConfig implements ConfigImportMarker {
224+
}
225+
226+
static class ImportedBean {
227+
String name() {
228+
return "imported";
229+
}
230+
}
231+
232+
@Configuration
233+
static class ImportedConfig {
234+
@Bean
235+
ImportedBean importedBean() {
236+
return new ImportedBean();
237+
}
238+
}
206239

207240
@Configuration
208241
@Import(SampleImportSelector.class)
@@ -247,7 +280,7 @@ public void setEnvironment(Environment environment) {
247280

248281
@Override
249282
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
250-
return new String[] {};
283+
return new String[]{};
251284
}
252285
}
253286

@@ -271,7 +304,7 @@ public static class ImportSelector1 implements ImportSelector {
271304
@Override
272305
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
273306
ImportSelectorTests.importFrom.put(getClass(), importingClassMetadata.getClassName());
274-
return new String[] { ImportedSelector1.class.getName() };
307+
return new String[]{ImportedSelector1.class.getName()};
275308
}
276309
}
277310

@@ -281,7 +314,7 @@ public static class ImportSelector2 implements ImportSelector {
281314
@Override
282315
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
283316
ImportSelectorTests.importFrom.put(getClass(), importingClassMetadata.getClassName());
284-
return new String[] { ImportedSelector2.class.getName() };
317+
return new String[]{ImportedSelector2.class.getName()};
285318
}
286319
}
287320

@@ -294,7 +327,7 @@ public static class FilteredImportSelector implements ImportSelector {
294327

295328
@Override
296329
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
297-
return new String[] { ImportedSelector1.class.getName(), ImportedSelector2.class.getName(), ImportedSelector3.class.getName() };
330+
return new String[]{ImportedSelector1.class.getName(), ImportedSelector2.class.getName(), ImportedSelector3.class.getName()};
298331
}
299332

300333
@Override
@@ -310,7 +343,7 @@ public static class DeferredImportSelector1 implements DeferredImportSelector, O
310343
@Override
311344
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
312345
ImportSelectorTests.importFrom.put(getClass(), importingClassMetadata.getClassName());
313-
return new String[] { DeferredImportedSelector1.class.getName() };
346+
return new String[]{DeferredImportedSelector1.class.getName()};
314347
}
315348

316349
@Override
@@ -326,7 +359,7 @@ public static class DeferredImportSelector2 implements DeferredImportSelector {
326359
@Override
327360
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
328361
ImportSelectorTests.importFrom.put(getClass(), importingClassMetadata.getClassName());
329-
return new String[] { DeferredImportedSelector2.class.getName() };
362+
return new String[]{DeferredImportedSelector2.class.getName()};
330363
}
331364
}
332365

@@ -399,7 +432,7 @@ public static class IndirectImportSelector implements ImportSelector {
399432

400433
@Override
401434
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
402-
return new String[] {IndirectImport.class.getName()};
435+
return new String[]{IndirectImport.class.getName()};
403436
}
404437

405438
@Override
@@ -465,7 +498,7 @@ public static class ParentDeferredImportSelector1 implements DeferredImportSelec
465498
@Override
466499
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
467500
ImportSelectorTests.importFrom.put(getClass(), importingClassMetadata.getClassName());
468-
return new String[] { DeferredImportSelector1.class.getName(), ChildConfiguration1.class.getName() };
501+
return new String[]{DeferredImportSelector1.class.getName(), ChildConfiguration1.class.getName()};
469502
}
470503

471504
@Override
@@ -485,7 +518,7 @@ public static class ParentDeferredImportSelector2 implements DeferredImportSelec
485518
@Override
486519
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
487520
ImportSelectorTests.importFrom.put(getClass(), importingClassMetadata.getClassName());
488-
return new String[] { DeferredImportSelector2.class.getName(), ChildConfiguration2.class.getName() };
521+
return new String[]{DeferredImportSelector2.class.getName(), ChildConfiguration2.class.getName()};
489522
}
490523

491524
@Override
@@ -507,7 +540,7 @@ public static class ChildDeferredImportSelector1 implements DeferredImportSelect
507540
@Override
508541
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
509542
ImportSelectorTests.importFrom.put(getClass(), importingClassMetadata.getClassName());
510-
return new String[] { DeferredImportedSelector3.class.getName() };
543+
return new String[]{DeferredImportedSelector3.class.getName()};
511544
}
512545

513546
@Override
@@ -528,7 +561,7 @@ public static class ChildDeferredImportSelector2 implements DeferredImportSelect
528561
@Override
529562
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
530563
ImportSelectorTests.importFrom.put(getClass(), importingClassMetadata.getClassName());
531-
return new String[] { DeferredImportSelector2.class.getName() };
564+
return new String[]{DeferredImportSelector2.class.getName()};
532565
}
533566

534567
@Override

0 commit comments

Comments
 (0)