diff --git a/spring-test/spring-test.gradle b/spring-test/spring-test.gradle index 01edf88137..8e57b80ed9 100644 --- a/spring-test/spring-test.gradle +++ b/spring-test/spring-test.gradle @@ -70,6 +70,7 @@ dependencies { testImplementation("jakarta.mail:jakarta.mail-api") testImplementation("jakarta.validation:jakarta.validation-api") testImplementation("javax.cache:cache-api") + testImplementation("javax.inject:javax.inject:1") testImplementation("org.apache.httpcomponents:httpclient") { exclude group: "commons-logging", module: "commons-logging" } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/TestConstructorUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/TestConstructorUtils.java index 963c826c6d..981f0d9688 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/TestConstructorUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/TestConstructorUtils.java @@ -16,8 +16,11 @@ package org.springframework.test.context.support; +import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; +import java.util.LinkedHashSet; +import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.SpringProperties; @@ -26,6 +29,7 @@ import org.springframework.lang.Nullable; import org.springframework.test.context.TestConstructor; import org.springframework.test.context.TestConstructor.AutowireMode; import org.springframework.test.context.TestContextAnnotationUtils; +import org.springframework.util.ClassUtils; /** * Utility methods for working with {@link TestConstructor @TestConstructor}. @@ -33,6 +37,7 @@ import org.springframework.test.context.TestContextAnnotationUtils; *

Primarily intended for use within the framework. * * @author Sam Brannen + * @author Florian Lehmann * @since 5.2 * @see TestConstructor */ @@ -99,6 +104,7 @@ public abstract class TestConstructorUtils { * *

    *
  1. The constructor is annotated with {@link Autowired @Autowired}.
  2. + *
  3. The constructor is annotated with {@link jakarta.inject.Inject} or {@code javax.inject.Inject}.
  4. *
  5. {@link TestConstructor @TestConstructor} is present or * meta-present on the test class with * {@link TestConstructor#autowireMode() autowireMode} set to @@ -119,8 +125,8 @@ public abstract class TestConstructorUtils { public static boolean isAutowirableConstructor(Constructor constructor, Class testClass, @Nullable PropertyProvider fallbackPropertyProvider) { - // Is the constructor annotated with @Autowired? - if (AnnotatedElementUtils.hasAnnotation(constructor, Autowired.class)) { + // Is the constructor annotated with @Autowired/@Inject? + if (isAnnotatedWithAutowiredOrInject(constructor)) { return true; } @@ -146,4 +152,30 @@ public abstract class TestConstructorUtils { return (autowireMode == AutowireMode.ALL); } + @SuppressWarnings("unchecked") + private static boolean isAnnotatedWithAutowiredOrInject(Constructor constructor) { + Set> autowiredAnnotationTypes = new LinkedHashSet<>(); + + autowiredAnnotationTypes.add(Autowired.class); + + try { + autowiredAnnotationTypes.add((Class) + ClassUtils.forName("jakarta.inject.Inject", TestConstructorUtils.class.getClassLoader())); + } + catch (ClassNotFoundException ex) { + // jakarta.inject API not available - simply skip. + } + + try { + autowiredAnnotationTypes.add((Class) + ClassUtils.forName("javax.inject.Inject", TestConstructorUtils.class.getClassLoader())); + } + catch (ClassNotFoundException ex) { + // javax.inject API not available - simply skip. + } + + return autowiredAnnotationTypes.stream() + .anyMatch(autowiredAnnotationType -> AnnotatedElementUtils.hasAnnotation(constructor, autowiredAnnotationType)); + } + } diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/InjectAnnotationIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/InjectAnnotationIntegrationTests.java new file mode 100644 index 0000000000..8e71198be6 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/InjectAnnotationIntegrationTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-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 org.springframework.test.context.junit.jupiter; + +import org.junit.jupiter.api.Test; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Common test implementation for integration tests in order to verify support + * for {@link jakarta.inject.Inject} and {@link javax.inject.Inject}. + * + * @author Florian Lehmann + * @since 6.0.5 + */ +@SpringJUnitConfig +public abstract class InjectAnnotationIntegrationTests { + + private final String foo; + + public InjectAnnotationIntegrationTests(String foo) { + this.foo = foo; + } + + @Test + public void beanInjected() { + assertThat(this.foo).isEqualTo("foo"); + } + + @Configuration + static class Config { + + @Bean + String foo() { + return "foo"; + } + + } +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/JakartaInjectAnnotationIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/JakartaInjectAnnotationIntegrationTests.java new file mode 100644 index 0000000000..048cfa50ad --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/JakartaInjectAnnotationIntegrationTests.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-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 org.springframework.test.context.junit.jupiter; + +import jakarta.inject.Inject; + +/** + * Integration tests which verify support for {@link jakarta.inject.Inject}. + * + * @author Florian Lehmann + * @since 6.0.5 + */ +@SpringJUnitConfig +public class JakartaInjectAnnotationIntegrationTests extends InjectAnnotationIntegrationTests { + + @Inject + public JakartaInjectAnnotationIntegrationTests(String foo) { + super(foo); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/JavaxInjectAnnotationIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/JavaxInjectAnnotationIntegrationTests.java new file mode 100644 index 0000000000..1f6432eecd --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/JavaxInjectAnnotationIntegrationTests.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-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 org.springframework.test.context.junit.jupiter; + +import javax.inject.Inject; + +/** + * Integration tests which verify support for {@link javax.inject.Inject}. + * + * @author Florian Lehmann + * @since 6.0.5 + */ +@SpringJUnitConfig +public class JavaxInjectAnnotationIntegrationTests extends InjectAnnotationIntegrationTests { + + @Inject + public JavaxInjectAnnotationIntegrationTests(String foo) { + super(foo); + } + +}