Order class filter checks and exit early
Update the logic in `OnClassCondition` so that filtering exits on the first missing class. Also refactor the implementation to save unnecessary `Set` creation when there is just a single class to check. The `AutoConfigureAnnotationProcessor` has also been updated to order classes so that any starting `org.springframework` are considered last. The assumption being that other classes are more likely to be missing. Closes gh-12131
This commit is contained in:
@@ -21,6 +21,7 @@ import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -98,7 +99,7 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
|
||||
private void addValueExtractors(Map<String, ValueExtractor> attributes) {
|
||||
attributes.put("Configuration", ValueExtractor.allFrom("value"));
|
||||
attributes.put("ConditionalOnClass", ValueExtractor.allFrom("value", "name"));
|
||||
attributes.put("ConditionalOnClass", new OnClassConditionValueExtractor());
|
||||
attributes.put("ConditionalOnBean", new OnBeanConditionValueExtractor());
|
||||
attributes.put("ConditionalOnSingleCandidate",
|
||||
new OnBeanConditionValueExtractor());
|
||||
@@ -206,22 +207,8 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
|
||||
List<Object> getValues(AnnotationMirror annotation);
|
||||
|
||||
static ValueExtractor allFrom(String... attributes) {
|
||||
Set<String> names = new HashSet<>(Arrays.asList(attributes));
|
||||
return new AbstractValueExtractor() {
|
||||
|
||||
@Override
|
||||
public List<Object> getValues(AnnotationMirror annotation) {
|
||||
List<Object> result = new ArrayList<>();
|
||||
annotation.getElementValues().forEach((key, value) -> {
|
||||
if (names.contains(key.getSimpleName().toString())) {
|
||||
extractValues(value).forEach(result::add);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
static ValueExtractor allFrom(String... names) {
|
||||
return new NamedValuesExtractor(names);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -250,6 +237,27 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
|
||||
}
|
||||
|
||||
private static class NamedValuesExtractor extends AbstractValueExtractor {
|
||||
|
||||
private final Set<String> names;
|
||||
|
||||
NamedValuesExtractor(String... names) {
|
||||
this.names = new HashSet<>(Arrays.asList(names));
|
||||
};
|
||||
|
||||
@Override
|
||||
public List<Object> getValues(AnnotationMirror annotation) {
|
||||
List<Object> result = new ArrayList<>();
|
||||
annotation.getElementValues().forEach((key, value) -> {
|
||||
if (this.names.contains(key.getSimpleName().toString())) {
|
||||
extractValues(value).forEach(result::add);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class OnBeanConditionValueExtractor extends AbstractValueExtractor {
|
||||
|
||||
@Override
|
||||
@@ -268,4 +276,29 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
|
||||
|
||||
}
|
||||
|
||||
private static class OnClassConditionValueExtractor extends NamedValuesExtractor {
|
||||
|
||||
OnClassConditionValueExtractor() {
|
||||
super("value", "name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getValues(AnnotationMirror annotation) {
|
||||
List<Object> values = super.getValues(annotation);
|
||||
Collections.sort(values, this::compare);
|
||||
return values;
|
||||
}
|
||||
|
||||
private int compare(Object o1, Object o2) {
|
||||
return Comparator.comparing(this::isSpringClass)
|
||||
.thenComparing(String.CASE_INSENSITIVE_ORDER)
|
||||
.compare(o1.toString(), o2.toString());
|
||||
}
|
||||
|
||||
private boolean isSpringClass(String type) {
|
||||
return type.startsWith("org.springframework");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class AutoConfigureAnnotationProcessorTests {
|
||||
"org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration.ConditionalOnClass",
|
||||
"java.io.InputStream,org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration$Nested");
|
||||
+ "TestClassConfiguration$Nested,org.springframework.foo");
|
||||
assertThat(properties)
|
||||
.containsKey("org.springframework.boot.autoconfigureprocessor."
|
||||
+ "TestClassConfiguration");
|
||||
|
||||
@@ -24,7 +24,8 @@ import org.springframework.boot.autoconfigureprocessor.TestConditionalOnWebAppli
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@TestConfiguration
|
||||
@TestConditionalOnClass(name = "java.io.InputStream", value = TestClassConfiguration.Nested.class)
|
||||
@TestConditionalOnClass(name = { "org.springframework.foo",
|
||||
"java.io.InputStream" }, value = TestClassConfiguration.Nested.class)
|
||||
@TestConditionalOnBean(type = "java.io.OutputStream")
|
||||
@TestConditionalOnSingleCandidate(type = "java.io.OutputStream")
|
||||
@TestConditionalOnWebApplication(type = Type.SERVLET)
|
||||
|
||||
Reference in New Issue
Block a user