diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java index 0c62e7f30..42832974c 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java @@ -589,10 +589,12 @@ private static Classes filterSpringBeans(JavaPackage source) { Classes repositories = source.that(isSpringDataRepository()); Classes coreComponents = source.that(not(INTERFACES).and(isComponent())); Classes configurationProperties = source.that(isConfigurationProperties()); + Classes jsr303Validator = source.that(isJsr303Validator()); return coreComponents // .and(repositories) // .and(configurationProperties) // + .and(jsr303Validator) // .and(collect.getOrDefault(true, Collections.emptyList())) // .and(collect.getOrDefault(false, Collections.emptyList())); } diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/Types.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Types.java index f6b18c93e..2b76e94dc 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/Types.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Types.java @@ -119,6 +119,10 @@ static DescribedPredicate isConfigurationProperties() { return isAnnotatedWith(AT_CONFIGURATION_PROPERTIES); } + static DescribedPredicate isJsr303Validator() { + return implement("jakarta.validation.ConstraintValidator"); + } + static boolean isAtBeanMethod(JavaMethod method) { return isAnnotatedWith(SpringTypes.AT_BEAN).test(method); } diff --git a/spring-modulith-integration-test/pom.xml b/spring-modulith-integration-test/pom.xml index 7fbc37272..237ff3a68 100644 --- a/spring-modulith-integration-test/pom.xml +++ b/spring-modulith-integration-test/pom.xml @@ -52,6 +52,11 @@ spring-tx + + jakarta.validation + jakarta.validation-api + + diff --git a/spring-modulith-integration-test/src/main/java/com/acme/myproject/validator/SampleValidator.java b/spring-modulith-integration-test/src/main/java/com/acme/myproject/validator/SampleValidator.java new file mode 100644 index 000000000..5eab68fe0 --- /dev/null +++ b/spring-modulith-integration-test/src/main/java/com/acme/myproject/validator/SampleValidator.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 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 com.acme.myproject.validator; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +import com.acme.myproject.moduleA.ServiceComponentA; + +public class SampleValidator implements ConstraintValidator { + + public SampleValidator(ServiceComponentA dependency) {} + + @Override + public boolean isValid(Object value, ConstraintValidatorContext context) { + return false; + } +} diff --git a/spring-modulith-integration-test/src/test/java/org/springframework/modulith/core/ApplicationModulesIntegrationTest.java b/spring-modulith-integration-test/src/test/java/org/springframework/modulith/core/ApplicationModulesIntegrationTest.java index 7c64aa942..dafa1bc73 100644 --- a/spring-modulith-integration-test/src/test/java/org/springframework/modulith/core/ApplicationModulesIntegrationTest.java +++ b/spring-modulith-integration-test/src/test/java/org/springframework/modulith/core/ApplicationModulesIntegrationTest.java @@ -37,6 +37,7 @@ import com.acme.myproject.moduleA.ServiceComponentA; import com.acme.myproject.moduleA.SomeConfigurationA.SomeAtBeanComponentA; import com.acme.myproject.moduleB.ServiceComponentB; +import com.acme.myproject.validator.SampleValidator; /** * @author Oliver Drotbohm @@ -196,6 +197,20 @@ void excludesSpringAOTGeneratedTypes() { }); } + @Test // GH-418 + void detectsDependencyInducedByValidatorImplementation() { + + assertThat(modules.getModuleByName("validator")).hasValueSatisfying(it -> { + + assertThat(it.getSpringBeans()) + .extracting(SpringBean::getFullyQualifiedTypeName) + .containsExactly(SampleValidator.class.getName()); + + assertThat(it.getBootstrapDependencies(modules).map(ApplicationModule::getName)) + .containsExactly("moduleA"); + }); + } + private static void verifyNamedInterfaces(NamedInterfaces interfaces, String name, Class... types) { Stream.of(types).forEach(type -> {