Skip to content

A lite configuration class's member classes are processed when it's imported but not when it's registered directly [SPR-16839] #21379

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue May 18, 2018 · 6 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented May 18, 2018

Andy Wilkinson opened SPR-16839 and commented

The problem's hopefully illustrated by the following two tests:

package com.example.demo;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

public class ImportVersusDirectRegistrationTests {

	@Test
	public void thingIsAvailableWhenOuterConfigurationIsRegisteredDirectly() {
		try (AnnotationConfigApplicationContext directRegistration = new AnnotationConfigApplicationContext()) {
			directRegistration.register(AccidentalLiteConfiguration.class);
			directRegistration.refresh();
			directRegistration.getBean(Thing.class);
		}
	}

	@Test
	public void thingIsAvailableWhenOuterConfigurationIsImported() {
		try (AnnotationConfigApplicationContext viaImport = new AnnotationConfigApplicationContext()) {
			viaImport.register(Importer.class);
			viaImport.refresh();
			viaImport.getBean(Thing.class);
		}
	}

}

@Import(AccidentalLiteConfiguration.class)
class Importer {

}

class AccidentalLiteConfiguration {

	@Configuration
	class InnerConfiguration {

		@Bean
		public Thing thing() {
			return new Thing();
		}

	}

}

class Thing {

}

thingIsAvailableWhenOuterConfigurationIsImported will pass but thingIsAvailableWhenOuterConfigurationIsRegisteredDirectly will fail. This appears to be because member classes of a lite configuration class are only processed when the lite configuration class has been imported. They are not processed when it's been registered directly with the application context.


Affects: 5.0.6

Reference URL: spring-projects/spring-boot#13129

Issue Links:

Referenced from: commits spring-projects/spring-boot@5cc1a83

0 votes, 5 watchers

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

This is more or less by design but I see that it can be surprising... So I'm willing to address it for 5.0.x at least, considering it as a bug in the refined configuration model there.

The solution involves scanning all nested classes of candidate components which is extra effort in a classpath scanning scenario and technically introduces a third kind of configuration candidate (neither full nor lite since it has no local configuration elements, just containing nested configuration classes). Even just for that reason it's not an ideal backport candidate to 4.3.x.

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

I'm turning this into 5.1 only fix since it is rather involved and may have semantic side effects (even if very unlikely) as well as performance side effects (from reading additional class files via ASM). Fortunately it has an easy work around, simply declaring the containing classes with @Configuration or any other configuration candidate hint.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Sep 12, 2018

Juergen Hoeller commented

Andy Wilkinson, note that I'm effectively undoing this as part of #21564 for 5.1 GA, consistently not searching nested classes in such scenarios unless the containing class is marked as a component type at least.

@spring-projects-issues
Copy link
Collaborator Author

Phil Webb commented

Just a quick note that this change means that configuration base classes also now need to be annotated. If you have MyConfiguration extends MyBaseConfiguration then both MyConfiguration and MyBaseConfiguration will need annotations. We has one of these in Spring Boot but it was pretty easy to fix.

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Hmm we should probably check the stereotype on the concrete class rather than the current base class level; after all, the concrete class is where stereotypes are generally expected. While it doesn't hurt to annotate base classes as well there, this is a backwards compatibility concern indeed.

Giving this a try now, to be committed ASAP.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Sep 17, 2018

Juergen Hoeller commented

Pushed now, along with #21814.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants