Merge branch '3.2.x' into 3.3.x

Closes gh-42944
This commit is contained in:
Andy Wilkinson 2024-10-30 10:40:50 +00:00
commit 53186655f9
2 changed files with 38 additions and 5 deletions

View File

@ -24,17 +24,20 @@ import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaAnnotation;
import com.tngtech.archunit.core.domain.JavaCall;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClass.Predicates;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.domain.JavaMethod;
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.HasName;
import com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With;
@ -90,7 +93,8 @@ public abstract class ArchitectureCheck extends DefaultTask {
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(),
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding(),
noClassesShouldLoadResourcesUsingResourceUtils(), noClassesShouldCallStringToUpperCaseWithoutLocale(),
noClassesShouldCallStringToLowerCaseWithoutLocale());
noClassesShouldCallStringToLowerCaseWithoutLocale(),
conditionalOnMissingBeanShouldNotSpecifyOnlyATypeThatIsTheSameAsMethodReturnType());
getRules().addAll(getProhibitObjectsRequireNonNull()
.map((prohibit) -> prohibit ? noClassesShouldCallObjectsRequireNonNull() : Collections.emptyList()));
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
@ -263,6 +267,36 @@ public abstract class ArchitectureCheck extends DefaultTask {
.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) {
this.classes = classes;
}

View File

@ -506,7 +506,7 @@ class ConditionalOnMissingBeanTests {
static class ConditionalOnIgnoredSubclass {
@Bean
@ConditionalOnMissingBean(value = ExampleBean.class, ignored = CustomExampleBean.class)
@ConditionalOnMissingBean(ignored = CustomExampleBean.class)
ExampleBean exampleBean() {
return new ExampleBean("test");
}
@ -517,7 +517,7 @@ class ConditionalOnMissingBeanTests {
static class ConditionalOnIgnoredSubclassByName {
@Bean
@ConditionalOnMissingBean(value = ExampleBean.class,
@ConditionalOnMissingBean(
ignoredType = "org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBeanTests$CustomExampleBean")
ExampleBean exampleBean() {
return new ExampleBean("test");
@ -701,8 +701,7 @@ class ConditionalOnMissingBeanTests {
static class ParameterizedConditionWithValueConfig {
@Bean
@ConditionalOnMissingBean(value = CustomExampleBean.class,
parameterizedContainer = TestParameterizedContainer.class)
@ConditionalOnMissingBean(parameterizedContainer = TestParameterizedContainer.class)
CustomExampleBean conditionalCustomExampleBean() {
return new CustomExampleBean();
}