Prohibit unnecessary values on @ConditionalOnMissingBean
Closes gh-42941
This commit is contained in:
parent
1f7d8ddc3c
commit
1c61e59099
|
|
@ -24,16 +24,19 @@ import java.nio.file.Files;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.tngtech.archunit.base.DescribedPredicate;
|
import com.tngtech.archunit.base.DescribedPredicate;
|
||||||
|
import com.tngtech.archunit.core.domain.JavaAnnotation;
|
||||||
import com.tngtech.archunit.core.domain.JavaClass;
|
import com.tngtech.archunit.core.domain.JavaClass;
|
||||||
import com.tngtech.archunit.core.domain.JavaClass.Predicates;
|
import com.tngtech.archunit.core.domain.JavaClass.Predicates;
|
||||||
import com.tngtech.archunit.core.domain.JavaClasses;
|
import com.tngtech.archunit.core.domain.JavaClasses;
|
||||||
import com.tngtech.archunit.core.domain.JavaMethod;
|
import com.tngtech.archunit.core.domain.JavaMethod;
|
||||||
import com.tngtech.archunit.core.domain.JavaParameter;
|
import com.tngtech.archunit.core.domain.JavaParameter;
|
||||||
|
import com.tngtech.archunit.core.domain.JavaType;
|
||||||
import com.tngtech.archunit.core.domain.properties.CanBeAnnotated;
|
import com.tngtech.archunit.core.domain.properties.CanBeAnnotated;
|
||||||
import com.tngtech.archunit.core.importer.ClassFileImporter;
|
import com.tngtech.archunit.core.importer.ClassFileImporter;
|
||||||
import com.tngtech.archunit.lang.ArchCondition;
|
import com.tngtech.archunit.lang.ArchCondition;
|
||||||
|
|
@ -83,7 +86,8 @@ public abstract class ArchitectureCheck extends DefaultTask {
|
||||||
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(),
|
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(),
|
||||||
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(),
|
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(),
|
||||||
noClassesShouldCallStringToUpperCaseWithoutLocale(),
|
noClassesShouldCallStringToUpperCaseWithoutLocale(),
|
||||||
noClassesShouldCallStringToLowerCaseWithoutLocale());
|
noClassesShouldCallStringToLowerCaseWithoutLocale(),
|
||||||
|
conditionalOnMissingBeanShouldNotSpecifyOnlyATypeThatIsTheSameAsMethodReturnType());
|
||||||
getRules().addAll(getProhibitObjectsRequireNonNull()
|
getRules().addAll(getProhibitObjectsRequireNonNull()
|
||||||
.map((prohibit) -> prohibit ? noClassesShouldCallObjectsRequireNonNull() : Collections.emptyList()));
|
.map((prohibit) -> prohibit ? noClassesShouldCallObjectsRequireNonNull() : Collections.emptyList()));
|
||||||
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
|
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
|
||||||
|
|
@ -244,6 +248,36 @@ public abstract class ArchitectureCheck extends DefaultTask {
|
||||||
.because("org.springframework.utils.Assert.notNull(Object, Supplier) should be used instead"));
|
.because("org.springframework.utils.Assert.notNull(Object, Supplier) should be used instead"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ArchRule conditionalOnMissingBeanShouldNotSpecifyOnlyATypeThatIsTheSameAsMethodReturnType() {
|
||||||
|
return ArchRuleDefinition.methods()
|
||||||
|
.that()
|
||||||
|
.areAnnotatedWith("org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean")
|
||||||
|
.should(notSpecifyOnlyATypeThatIsTheSameAsTheMethodReturnType())
|
||||||
|
.allowEmptyShould(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArchCondition<? super JavaMethod> notSpecifyOnlyATypeThatIsTheSameAsTheMethodReturnType() {
|
||||||
|
return new ArchCondition<>("not specify only a type that is the same as the method's return type") {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void check(JavaMethod item, ConditionEvents events) {
|
||||||
|
JavaAnnotation<JavaMethod> conditional = item
|
||||||
|
.getAnnotationOfType("org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean");
|
||||||
|
Map<String, Object> properties = conditional.getProperties();
|
||||||
|
if (!properties.containsKey("type") && !properties.containsKey("name")) {
|
||||||
|
conditional.get("value").ifPresent((value) -> {
|
||||||
|
JavaType[] types = (JavaType[]) value;
|
||||||
|
if (types.length == 1 && item.getReturnType().equals(types[0])) {
|
||||||
|
events.add(SimpleConditionEvent.violated(item, conditional.getDescription()
|
||||||
|
+ " should not specify only a value that is the same as the method's return type"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public void setClasses(FileCollection classes) {
|
public void setClasses(FileCollection classes) {
|
||||||
this.classes = classes;
|
this.classes = classes;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -506,7 +506,7 @@ class ConditionalOnMissingBeanTests {
|
||||||
static class ConditionalOnIgnoredSubclass {
|
static class ConditionalOnIgnoredSubclass {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(value = ExampleBean.class, ignored = CustomExampleBean.class)
|
@ConditionalOnMissingBean(ignored = CustomExampleBean.class)
|
||||||
ExampleBean exampleBean() {
|
ExampleBean exampleBean() {
|
||||||
return new ExampleBean("test");
|
return new ExampleBean("test");
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +517,7 @@ class ConditionalOnMissingBeanTests {
|
||||||
static class ConditionalOnIgnoredSubclassByName {
|
static class ConditionalOnIgnoredSubclassByName {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(value = ExampleBean.class,
|
@ConditionalOnMissingBean(
|
||||||
ignoredType = "org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBeanTests$CustomExampleBean")
|
ignoredType = "org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBeanTests$CustomExampleBean")
|
||||||
ExampleBean exampleBean() {
|
ExampleBean exampleBean() {
|
||||||
return new ExampleBean("test");
|
return new ExampleBean("test");
|
||||||
|
|
@ -701,8 +701,7 @@ class ConditionalOnMissingBeanTests {
|
||||||
static class ParameterizedConditionWithValueConfig {
|
static class ParameterizedConditionWithValueConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(value = CustomExampleBean.class,
|
@ConditionalOnMissingBean(parameterizedContainer = TestParameterizedContainer.class)
|
||||||
parameterizedContainer = TestParameterizedContainer.class)
|
|
||||||
CustomExampleBean conditionalCustomExampleBean() {
|
CustomExampleBean conditionalCustomExampleBean() {
|
||||||
return new CustomExampleBean();
|
return new CustomExampleBean();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue