Skip to content

ImportSelector#getExclusionFilter does not exclude matching candidates with import selector #27080

@snicoll

Description

@snicoll

ImportSelector#getExclusionFilter is a way to let an import selector apply an exclude to classes that are imported. We use this in Spring Boot to filter out classes that are about to be imported and that have conditions we can run statically eagerly and to avoid loading unnecessary classes.

CacheAutoConfiguration has an import selector that loads the various configuration candidates. That's handled primarily by the following code:

String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);

The candidates for the import selector are as follows:

0 = "org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration"
1 = "org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration"
2 = "org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration"
3 = "org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration"
4 = "org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration"
5 = "org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration"
6 = "org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration"
7 = "org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration"
8 = "org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration"
9 = "org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration"

The exclusion filter is going to match for a number of them. As a result the importSourceClasses collection is the following:

0 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@3426} "org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration"
1 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@2464} "java.lang.Object"
2 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@2464} "java.lang.Object"
3 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@2464} "java.lang.Object"
4 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@2464} "java.lang.Object"
5 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@2464} "java.lang.Object"
6 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@2464} "java.lang.Object"
7 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@2464} "java.lang.Object"
8 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@3427} "org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration"
9 = {org.springframework.context.annotation.ConfigurationClassParser$SourceClass@3428} "org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration"

Those 7 "configuration classes" are then later on processed. It leads ultimately to a java.lang.Object bean to be defined.

The reason for this is because of a shortcut when the exclude filter matches:

if (className == null || filter.test(className)) {
return this.objectSourceClass;
}

Perhaps an improvement would be a way to not contribute the SourceClass at all so that it's not processed?

Metadata

Metadata

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions