diff --git a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java index 47bcd305464..6183e07b6e3 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java @@ -112,7 +112,7 @@ final class ArchitectureRules { rules.add(noClassesShouldCallStringToUpperCaseWithoutLocale()); rules.add(noClassesShouldCallStringToLowerCaseWithoutLocale()); rules.add(conditionalOnMissingBeanShouldNotSpecifyOnlyATypeThatIsTheSameAsMethodReturnType()); - rules.add(enumSourceShouldNotSpecifyOnlyATypeThatIsTheSameAsMethodParameterType()); + rules.add(enumSourceShouldNotHaveValueThatIsTheSameAsTypeOfMethodsFirstParameter()); rules.add(classLevelConfigurationPropertiesShouldNotSpecifyOnlyPrefixAttribute()); rules.add(methodLevelConfigurationPropertiesShouldNotSpecifyOnlyPrefixAttribute()); rules.add(conditionsShouldNotBePublic()); @@ -273,7 +273,7 @@ final class ArchitectureRules { JavaAnnotation conditionalAnnotation = item .getAnnotationOfType("org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean"); Map properties = conditionalAnnotation.getProperties(); - if (!properties.containsKey("type") && !properties.containsKey("name")) { + if (!hasProperty("type", properties) && !hasProperty("name", properties)) { conditionalAnnotation.get("value").ifPresent((value) -> { if (containsOnlySingleType((JavaType[]) value, item.getReturnType())) { addViolation(events, item, conditionalAnnotation.getDescription() @@ -284,16 +284,24 @@ final class ArchitectureRules { }); } - private static ArchRule enumSourceShouldNotSpecifyOnlyATypeThatIsTheSameAsMethodParameterType() { + private static boolean hasProperty(String name, Map properties) { + Object property = properties.get(name); + if (property == null) { + return false; + } + return !property.getClass().isArray() || ((Object[]) property).length > 0; + } + + private static ArchRule enumSourceShouldNotHaveValueThatIsTheSameAsTypeOfMethodsFirstParameter() { return ArchRuleDefinition.methods() .that() .areAnnotatedWith("org.junit.jupiter.params.provider.EnumSource") - .should(notSpecifyOnlyATypeThatIsTheSameAsTheMethodParameterType()) + .should(notHaveValueThatIsTheSameAsTheTypeOfTheMethodsFirstParameter()) .allowEmptyShould(true); } - private static ArchCondition notSpecifyOnlyATypeThatIsTheSameAsTheMethodParameterType() { - return check("not specify only a type that is the same as the method's parameter type", + private static ArchCondition notHaveValueThatIsTheSameAsTheTypeOfTheMethodsFirstParameter() { + return check("not have a value that is the same as the type of the method's first parameter", ArchitectureRules::notSpecifyOnlyATypeThatIsTheSameAsTheMethodParameterType); } @@ -301,15 +309,13 @@ final class ArchitectureRules { ConditionEvents events) { JavaAnnotation enumSourceAnnotation = item .getAnnotationOfType("org.junit.jupiter.params.provider.EnumSource"); - Map properties = enumSourceAnnotation.getProperties(); - if (properties.size() == 1 && item.getParameterTypes().size() == 1) { - enumSourceAnnotation.get("value").ifPresent((value) -> { - if (value.equals(item.getParameterTypes().get(0))) { - addViolation(events, item, enumSourceAnnotation.getDescription() - + " should not specify only a value that is the same as the method's parameter type"); - } - }); - } + enumSourceAnnotation.get("value").ifPresent((value) -> { + JavaType parameterType = item.getParameterTypes().get(0); + if (value.equals(parameterType)) { + addViolation(events, item, enumSourceAnnotation.getDescription() + + " should not specify a value that is the same as the type of the method's first parameter"); + } + }); } private static ArchRule classLevelConfigurationPropertiesShouldNotSpecifyOnlyPrefixAttribute() { diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java index 213cd3f402a..dc7b2f9f09e 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java @@ -57,6 +57,8 @@ class ArchitectureCheckTests { private static final String SPRING_CONTEXT = "org.springframework:spring-context:6.2.9"; + private static final String JUNIT_JUPITER = "org.junit.jupiter:junit-jupiter:5.12.0"; + private static final String SPRING_INTEGRATION_JMX = "org.springframework.integration:spring-integration-jmx:6.5.1"; private GradleBuild gradleBuild; @@ -283,6 +285,29 @@ class ArchitectureCheckTests { build(this.gradleBuild.withNullMarked(true), Task.CHECK_ARCHITECTURE_TEST); } + @Test + void whenEnumSourceValueIsInferredShouldSucceedAndWriteEmptyReport() throws IOException { + prepareTask(Task.CHECK_ARCHITECTURE_TEST, "junit/enumsource/inferredfromparametertype"); + build(this.gradleBuild.withDependencies(JUNIT_JUPITER), Task.CHECK_ARCHITECTURE_TEST); + } + + @Test + void whenEnumSourceValueIsNotTheSameAsTypeOfMethodsFirstParameterShouldSucceedAndWriteEmptyReport() + throws IOException { + prepareTask(Task.CHECK_ARCHITECTURE_TEST, "junit/enumsource/valuenecessary"); + build(this.gradleBuild.withDependencies(JUNIT_JUPITER), Task.CHECK_ARCHITECTURE_TEST); + } + + @Test + void whenEnumSourceValueIsSameAsTypeOfMethodsFirstParameterShouldFailAndWriteReport() throws IOException { + prepareTask(Task.CHECK_ARCHITECTURE_TEST, "junit/enumsource/sameasparametertype"); + buildAndFail(this.gradleBuild.withDependencies(JUNIT_JUPITER), Task.CHECK_ARCHITECTURE_TEST, + "method ", + "should not have a value that is the same as the type of the method's first parameter"); + } + private void prepareTask(Task task, String... sourceDirectories) throws IOException { for (String sourceDirectory : sourceDirectories) { FileSystemUtils.copyRecursively( diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/inferredfromparametertype/EnumSourceInferredFromParameterType.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/inferredfromparametertype/EnumSourceInferredFromParameterType.java new file mode 100644 index 00000000000..c2fd99dfdf6 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/inferredfromparametertype/EnumSourceInferredFromParameterType.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.architecture.junit.enumsource.inferredfromparametertype; + +import org.junit.jupiter.params.provider.EnumSource; + +class EnumSourceInferredFromParameterType { + + @EnumSource + void exampleMethod(Example example) { + + } + + enum Example { + + ONE, TWO, THREE + + } + +} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/sameasparametertype/EnumSourceSameAsParameterType.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/sameasparametertype/EnumSourceSameAsParameterType.java new file mode 100644 index 00000000000..1695833abf9 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/sameasparametertype/EnumSourceSameAsParameterType.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.architecture.junit.enumsource.sameasparametertype; + +import org.junit.jupiter.params.provider.EnumSource; + +class EnumSourceSameAsParameterType { + + @EnumSource(Example.class) + void exampleMethod(Example example) { + + } + + enum Example { + + ONE, TWO, THREE + + } + +} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/valuenecessary/EnumSourceValueNecessary.java b/buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/valuenecessary/EnumSourceValueNecessary.java new file mode 100644 index 00000000000..b92f4d2bdd2 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/valuenecessary/EnumSourceValueNecessary.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.architecture.junit.enumsource.valuenecessary; + +import org.junit.jupiter.params.provider.EnumSource; + +class EnumSourceValueNecessary { + + @EnumSource(Example.class) + void exampleMethod(String thing, Example example) { + + } + + enum Example { + + ONE, TWO, THREE + + } + +} diff --git a/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointWebExtensionTests.java b/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointWebExtensionTests.java index a4534b569d9..ba14483c021 100644 --- a/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointWebExtensionTests.java +++ b/module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointWebExtensionTests.java @@ -112,7 +112,7 @@ class SbomEndpointWebExtensionTests { } @ParameterizedTest - @EnumSource(value = SbomType.class, names = "UNKNOWN", mode = Mode.EXCLUDE) + @EnumSource(names = "UNKNOWN", mode = Mode.EXCLUDE) void shouldAutodetectFormats(SbomType type) throws IOException { String content = getSbomContent(type); assertThat(type.matches(content)).isTrue(); diff --git a/module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchDataSourceScriptDatabaseInitializerTests.java b/module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchDataSourceScriptDatabaseInitializerTests.java index 7cc1ec63716..7485bb53d1a 100644 --- a/module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchDataSourceScriptDatabaseInitializerTests.java +++ b/module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchDataSourceScriptDatabaseInitializerTests.java @@ -62,8 +62,8 @@ class BatchDataSourceScriptDatabaseInitializerTests { } @ParameterizedTest - @EnumSource(value = DatabaseDriver.class, mode = Mode.EXCLUDE, names = { "AWS_WRAPPER", "CLICKHOUSE", "FIREBIRD", - "INFORMIX", "JTDS", "PHOENIX", "REDSHIFT", "TERADATA", "TESTCONTAINERS", "UNKNOWN" }) + @EnumSource(mode = Mode.EXCLUDE, names = { "AWS_WRAPPER", "CLICKHOUSE", "FIREBIRD", "INFORMIX", "JTDS", "PHOENIX", + "REDSHIFT", "TERADATA", "TESTCONTAINERS", "UNKNOWN" }) void batchSchemaCanBeLocated(DatabaseDriver driver) throws SQLException { DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); BatchJdbcProperties properties = new BatchJdbcProperties(); diff --git a/module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonAutoConfiguration.java b/module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonAutoConfiguration.java index 760b1a33167..061ef637dd6 100644 --- a/module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonAutoConfiguration.java +++ b/module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonAutoConfiguration.java @@ -111,7 +111,7 @@ public final class JacksonAutoConfiguration { @Bean @Primary - @ConditionalOnMissingBean(JsonMapper.class) + @ConditionalOnMissingBean JsonMapper jacksonJsonMapper(JsonMapper.Builder builder) { return builder.build(); } diff --git a/module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsClientConfigurations.java b/module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsClientConfigurations.java index 8107f0a70a6..7dfeb4ae21b 100644 --- a/module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsClientConfigurations.java +++ b/module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsClientConfigurations.java @@ -120,7 +120,7 @@ abstract class JmsClientConfigurations { static class JmsClientConfiguration { @Bean - @ConditionalOnMissingBean(JmsClient.class) + @ConditionalOnMissingBean @ConditionalOnSingleCandidate(JmsTemplate.class) JmsClient jmsClient(JmsTemplate jmsTemplate) { return JmsClient.create(jmsTemplate);