diff --git a/spring-beans/spring-beans.gradle b/spring-beans/spring-beans.gradle
index b407bf0ed24..c4fb10eb320 100644
--- a/spring-beans/spring-beans.gradle
+++ b/spring-beans/spring-beans.gradle
@@ -16,4 +16,5 @@ dependencies {
testImplementation(project(":spring-core-test"))
testImplementation(testFixtures(project(":spring-core")))
testImplementation("jakarta.annotation:jakarta.annotation-api")
+ testImplementation("javax.inject:javax.inject")
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java
index c4e46f8ecd8..439b1fb30e4 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2023 the original author or authors.
+ * Copyright 2002-2024 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.
@@ -24,16 +24,24 @@ import org.springframework.aot.hint.TypeReference;
import org.springframework.lang.Nullable;
/**
- * {@link RuntimeHintsRegistrar} for Jakarta annotations.
+ * {@link RuntimeHintsRegistrar} for Jakarta annotations and their pre-Jakarta equivalents.
*
* @author Brian Clozel
+ * @author Sam Brannen
*/
class JakartaAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
- Stream.of("jakarta.inject.Inject", "jakarta.inject.Provider", "jakarta.inject.Qualifier").forEach(typeName ->
- hints.reflection().registerType(TypeReference.of(typeName)));
+ // javax.inject.Provider is omitted from the list, since we do not currently load
+ // it via reflection.
+ Stream.of(
+ "jakarta.inject.Inject",
+ "jakarta.inject.Provider",
+ "jakarta.inject.Qualifier",
+ "javax.inject.Inject",
+ "javax.inject.Qualifier"
+ ).forEach(typeName -> hints.reflection().registerType(TypeReference.of(typeName)));
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
index dda7d8da513..a2345893100 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
@@ -47,11 +47,13 @@ import org.springframework.util.ObjectUtils;
* against {@link Qualifier qualifier annotations} on the field or parameter to be autowired.
* Also supports suggested expression values through a {@link Value value} annotation.
*
- *
Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation, if available.
+ *
Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation (as well as its
+ * pre-Jakarta {@code javax.inject.Qualifier} equivalent), if available.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Stephane Nicoll
+ * @author Sam Brannen
* @since 2.5
* @see AutowireCandidateQualifier
* @see Qualifier
@@ -65,9 +67,10 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
/**
- * Create a new QualifierAnnotationAutowireCandidateResolver
- * for Spring's standard {@link Qualifier} annotation.
- *
Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation, if available.
+ * Create a new {@code QualifierAnnotationAutowireCandidateResolver} for Spring's
+ * standard {@link Qualifier} annotation.
+ *
Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation (as well as
+ * its pre-Jakarta {@code javax.inject.Qualifier} equivalent), if available.
*/
@SuppressWarnings("unchecked")
public QualifierAnnotationAutowireCandidateResolver() {
@@ -76,14 +79,21 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
this.qualifierTypes.add((Class extends Annotation>) ClassUtils.forName("jakarta.inject.Qualifier",
QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
}
+ catch (ClassNotFoundException ex) {
+ // JSR-330 API (as included in Jakarta EE) not available - simply skip.
+ }
+ try {
+ this.qualifierTypes.add((Class extends Annotation>) ClassUtils.forName("javax.inject.Qualifier",
+ QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
+ }
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
/**
- * Create a new QualifierAnnotationAutowireCandidateResolver
- * for the given qualifier annotation type.
+ * Create a new {@code QualifierAnnotationAutowireCandidateResolver} for the given
+ * qualifier annotation type.
* @param qualifierType the qualifier annotation to look for
*/
public QualifierAnnotationAutowireCandidateResolver(Class extends Annotation> qualifierType) {
@@ -92,8 +102,8 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
}
/**
- * Create a new QualifierAnnotationAutowireCandidateResolver
- * for the given qualifier annotation types.
+ * Create a new {@code QualifierAnnotationAutowireCandidateResolver} for the given
+ * qualifier annotation types.
* @param qualifierTypes the qualifier annotations to look for
*/
public QualifierAnnotationAutowireCandidateResolver(Set> qualifierTypes) {
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
index 6d8c27708bf..433e42b1527 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
@@ -129,16 +129,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Nullable
- private static Class> javaxInjectProviderClass;
+ private static Class> jakartaInjectProviderClass;
static {
try {
- javaxInjectProviderClass =
+ jakartaInjectProviderClass =
ClassUtils.forName("jakarta.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - Provider interface simply not supported then.
- javaxInjectProviderClass = null;
+ jakartaInjectProviderClass = null;
}
}
@@ -1494,7 +1494,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
- else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
+ else if (jakartaInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else if (descriptor.supportsLazyResolution()) {
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java
index 9dae6cf67cb..ef2e236fb68 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2023 the original author or authors.
+ * Copyright 2002-2024 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.
@@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link JakartaAnnotationsRuntimeHints}.
*
* @author Brian Clozel
+ * @author Sam Brannen
*/
class JakartaAnnotationsRuntimeHintsTests {
@@ -62,4 +63,14 @@ class JakartaAnnotationsRuntimeHintsTests {
assertThat(RuntimeHintsPredicates.reflection().onType(Qualifier.class)).accepts(this.hints);
}
+ @Test // gh-33345
+ void javaxInjectAnnotationHasHints() {
+ assertThat(RuntimeHintsPredicates.reflection().onType(javax.inject.Inject.class)).accepts(this.hints);
+ }
+
+ @Test // gh-33345
+ void javaxQualifierAnnotationHasHints() {
+ assertThat(RuntimeHintsPredicates.reflection().onType(javax.inject.Qualifier.class)).accepts(this.hints);
+ }
+
}
diff --git a/spring-context/src/test/java/org/springframework/beans/factory/support/InjectAnnotationAutowireContextTests.java b/spring-context/src/test/java/org/springframework/beans/factory/support/InjectAnnotationAutowireContextTests.java
index 54dc5370f2d..48d19fbf7e8 100644
--- a/spring-context/src/test/java/org/springframework/beans/factory/support/InjectAnnotationAutowireContextTests.java
+++ b/spring-context/src/test/java/org/springframework/beans/factory/support/InjectAnnotationAutowireContextTests.java
@@ -32,6 +32,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.support.GenericApplicationContext;
@@ -39,77 +40,80 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
- * Integration tests for handling JSR-303 {@link jakarta.inject.Qualifier} annotations.
+ * Integration tests for handling JSR-330 {@link jakarta.inject.Qualifier} and
+ * {@link javax.inject.Qualifier} annotations.
*
* @author Juergen Hoeller
+ * @author Sam Brannen
* @since 3.0
*/
class InjectAnnotationAutowireContextTests {
+ private static final String PERSON1 = "person1";
+
+ private static final String PERSON2 = "person2";
+
private static final String JUERGEN = "juergen";
private static final String MARK = "mark";
@Test
- void testAutowiredFieldWithSingleNonQualifiedCandidate() {
+ void autowiredFieldWithSingleNonQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
- context.registerBeanDefinition(JUERGEN, person);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldTestBean.class));
+ context.registerBeanDefinition(PERSON1, person);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> {
- assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
- assertThat(ex.getBeanName()).isEqualTo("autowired");
- });
+ assertThatExceptionOfType(BeanCreationException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> {
+ assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
+ assertThat(ex.getBeanName()).isEqualTo("autowired");
+ });
}
@Test
- void testAutowiredMethodParameterWithSingleNonQualifiedCandidate() {
+ void autowiredMethodParameterWithSingleNonQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
- context.registerBeanDefinition(JUERGEN, person);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
+ context.registerBeanDefinition(PERSON1, person);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> {
- assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
- assertThat(ex.getBeanName()).isEqualTo("autowired");
- });
+ assertThatExceptionOfType(BeanCreationException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> {
+ assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
+ assertThat(ex.getBeanName()).isEqualTo("autowired");
+ });
}
@Test
- void testAutowiredConstructorArgumentWithSingleNonQualifiedCandidate() {
+ void autowiredConstructorArgumentWithSingleNonQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
- context.registerBeanDefinition(JUERGEN, person);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
+ context.registerBeanDefinition(PERSON1, person);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
+ assertThatExceptionOfType(UnsatisfiedDependencyException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
}
@Test
- void testAutowiredFieldWithSingleQualifiedCandidate() {
+ void autowiredFieldWithSingleQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
- context.registerBeanDefinition(JUERGEN, person);
+ context.registerBeanDefinition(PERSON1, person);
context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
@@ -118,15 +122,14 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredMethodParameterWithSingleQualifiedCandidate() {
+ void autowiredMethodParameterWithSingleQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
- context.registerBeanDefinition(JUERGEN, person);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
+ context.registerBeanDefinition(PERSON1, person);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedMethodParameterTestBean bean =
@@ -135,15 +138,14 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredMethodParameterWithStaticallyQualifiedCandidate() {
+ void autowiredMethodParameterWithStaticallyQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(QualifiedPerson.class, cavs, null);
- context.registerBeanDefinition(JUERGEN,
+ context.registerBeanDefinition(PERSON1,
ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(person, JUERGEN), context, true).getBeanDefinition());
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedMethodParameterTestBean bean =
@@ -152,18 +154,17 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredMethodParameterWithStaticallyQualifiedCandidateAmongOthers() {
+ void autowiredMethodParameterWithStaticallyQualifiedCandidateAmongOthers() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
- RootBeanDefinition person = new RootBeanDefinition(QualifiedPerson.class, cavs, null);
+ RootBeanDefinition person1 = new RootBeanDefinition(QualifiedPerson.class, cavs, null);
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedMethodParameterTestBean bean =
@@ -172,15 +173,14 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredConstructorArgumentWithSingleQualifiedCandidate() {
+ void autowiredConstructorArgumentWithSingleQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
- context.registerBeanDefinition(JUERGEN, person);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
+ context.registerBeanDefinition(PERSON1, person);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedConstructorArgumentTestBean bean =
@@ -189,7 +189,7 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredFieldWithMultipleNonQualifiedCandidates() {
+ void autowiredFieldWithMultipleNonQualifiedCandidates() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -197,21 +197,20 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> {
- assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
- assertThat(ex.getBeanName()).isEqualTo("autowired");
- });
+ assertThatExceptionOfType(BeanCreationException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> {
+ assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
+ assertThat(ex.getBeanName()).isEqualTo("autowired");
+ });
}
@Test
- void testAutowiredMethodParameterWithMultipleNonQualifiedCandidates() {
+ void autowiredMethodParameterWithMultipleNonQualifiedCandidates() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -219,21 +218,20 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> {
- assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
- assertThat(ex.getBeanName()).isEqualTo("autowired");
- });
+ assertThatExceptionOfType(BeanCreationException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> {
+ assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
+ assertThat(ex.getBeanName()).isEqualTo("autowired");
+ });
}
@Test
- void testAutowiredConstructorArgumentWithMultipleNonQualifiedCandidates() {
+ void autowiredConstructorArgumentWithMultipleNonQualifiedCandidates() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -241,18 +239,17 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
+ assertThatExceptionOfType(UnsatisfiedDependencyException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
}
@Test
- void testAutowiredFieldResolvesQualifiedCandidate() {
+ void autowiredFieldResolvesQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -261,10 +258,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedFieldTestBean bean = (QualifiedFieldTestBean) context.getBean("autowired");
@@ -272,7 +268,7 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredMethodParameterResolvesQualifiedCandidate() {
+ void autowiredMethodParameterResolvesQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -281,10 +277,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedMethodParameterTestBean bean =
@@ -293,7 +288,7 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredConstructorArgumentResolvesQualifiedCandidate() {
+ void autowiredConstructorArgumentResolvesQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -302,10 +297,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedConstructorArgumentTestBean bean =
@@ -313,8 +307,28 @@ class InjectAnnotationAutowireContextTests {
assertThat(bean.getPerson().getName()).isEqualTo(JUERGEN);
}
+ @Test // gh-33345
+ void autowiredConstructorArgumentResolvesJakartaNamedCandidate() {
+ Class testBeanClass = JakartaNamedConstructorArgumentTestBean.class;
+ AnnotationConfigApplicationContext context =
+ new AnnotationConfigApplicationContext(testBeanClass, JakartaCat.class, JakartaDog.class);
+ JakartaNamedConstructorArgumentTestBean bean = context.getBean(testBeanClass);
+ assertThat(bean.getAnimal1().getName()).isEqualTo("Jakarta Tiger");
+ assertThat(bean.getAnimal2().getName()).isEqualTo("Jakarta Fido");
+ }
+
+ @Test // gh-33345
+ void autowiredConstructorArgumentResolvesJavaxNamedCandidate() {
+ Class testBeanClass = JavaxNamedConstructorArgumentTestBean.class;
+ AnnotationConfigApplicationContext context =
+ new AnnotationConfigApplicationContext(testBeanClass, JavaxCat.class, JavaxDog.class);
+ JavaxNamedConstructorArgumentTestBean bean = context.getBean(testBeanClass);
+ assertThat(bean.getAnimal1().getName()).isEqualTo("Javax Tiger");
+ assertThat(bean.getAnimal2().getName()).isEqualTo("Javax Fido");
+ }
+
@Test
- void testAutowiredFieldResolvesQualifiedCandidateWithDefaultValueAndNoValueOnBeanDefinition() {
+ void autowiredFieldResolvesQualifiedCandidateWithDefaultValueAndNoValueOnBeanDefinition() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -324,10 +338,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedFieldWithDefaultValueTestBean bean =
@@ -336,7 +349,7 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredFieldDoesNotResolveCandidateWithDefaultValueAndConflictingValueOnBeanDefinition() {
+ void autowiredFieldDoesNotResolveCandidateWithDefaultValueAndConflictingValueOnBeanDefinition() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -346,21 +359,20 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> {
- assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
- assertThat(ex.getBeanName()).isEqualTo("autowired");
- });
+ assertThatExceptionOfType(BeanCreationException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> {
+ assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
+ assertThat(ex.getBeanName()).isEqualTo("autowired");
+ });
}
@Test
- void testAutowiredFieldResolvesWithDefaultValueAndExplicitDefaultValueOnBeanDefinition() {
+ void autowiredFieldResolvesWithDefaultValueAndExplicitDefaultValueOnBeanDefinition() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -370,10 +382,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedFieldWithDefaultValueTestBean bean =
@@ -382,7 +393,7 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredFieldResolvesWithMultipleQualifierValues() {
+ void autowiredFieldResolvesWithMultipleQualifierValues() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -396,10 +407,9 @@ class InjectAnnotationAutowireContextTests {
AutowireCandidateQualifier qualifier2 = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class);
qualifier2.setAttribute("number", 123);
person2.addQualifier(qualifier2);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedFieldWithMultipleAttributesTestBean bean =
@@ -408,7 +418,7 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredFieldDoesNotResolveWithMultipleQualifierValuesAndConflictingDefaultValue() {
+ void autowiredFieldDoesNotResolveWithMultipleQualifierValuesAndConflictingDefaultValue() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -423,21 +433,20 @@ class InjectAnnotationAutowireContextTests {
qualifier2.setAttribute("number", 123);
qualifier2.setAttribute("value", "not the default");
person2.addQualifier(qualifier2);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> {
- assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
- assertThat(ex.getBeanName()).isEqualTo("autowired");
- });
+ assertThatExceptionOfType(BeanCreationException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> {
+ assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
+ assertThat(ex.getBeanName()).isEqualTo("autowired");
+ });
}
@Test
- void testAutowiredFieldResolvesWithMultipleQualifierValuesAndExplicitDefaultValue() {
+ void autowiredFieldResolvesWithMultipleQualifierValuesAndExplicitDefaultValue() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -452,10 +461,9 @@ class InjectAnnotationAutowireContextTests {
qualifier2.setAttribute("number", 123);
qualifier2.setAttribute("value", "default");
person2.addQualifier(qualifier2);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
QualifiedFieldWithMultipleAttributesTestBean bean =
@@ -464,7 +472,7 @@ class InjectAnnotationAutowireContextTests {
}
@Test
- void testAutowiredFieldDoesNotResolveWithMultipleQualifierValuesAndMultipleMatchingCandidates() {
+ void autowiredFieldDoesNotResolveWithMultipleQualifierValuesAndMultipleMatchingCandidates() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN);
@@ -479,38 +487,37 @@ class InjectAnnotationAutowireContextTests {
qualifier2.setAttribute("number", 123);
qualifier2.setAttribute("value", "default");
person2.addQualifier(qualifier2);
- context.registerBeanDefinition(JUERGEN, person1);
- context.registerBeanDefinition(MARK, person2);
- context.registerBeanDefinition("autowired",
- new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
+ context.registerBeanDefinition(PERSON1, person1);
+ context.registerBeanDefinition(PERSON2, person2);
+ context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> {
- assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
- assertThat(ex.getBeanName()).isEqualTo("autowired");
- });
+ assertThatExceptionOfType(BeanCreationException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> {
+ assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
+ assertThat(ex.getBeanName()).isEqualTo("autowired");
+ });
}
@Test
- void testAutowiredFieldDoesNotResolveWithBaseQualifierAndNonDefaultValueAndMultipleMatchingCandidates() {
+ void autowiredConstructorArgumentDoesNotResolveWithBaseQualifierAndNonDefaultValueAndMultipleMatchingCandidates() {
GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue("the real juergen");
RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null);
- person1.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "juergen"));
+ person1.addQualifier(new AutowireCandidateQualifier(Qualifier.class, JUERGEN));
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue("juergen imposter");
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
- person2.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "juergen"));
+ person2.addQualifier(new AutowireCandidateQualifier(Qualifier.class, JUERGEN));
context.registerBeanDefinition("juergen1", person1);
context.registerBeanDefinition("juergen2", person2);
context.registerBeanDefinition("autowired",
new RootBeanDefinition(QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
- context::refresh)
- .satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
+ assertThatExceptionOfType(UnsatisfiedDependencyException.class)
+ .isThrownBy(context::refresh)
+ .satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
}
@@ -543,7 +550,7 @@ class InjectAnnotationAutowireContextTests {
private static class QualifiedConstructorArgumentTestBean {
- private Person person;
+ private final Person person;
@Inject
public QualifiedConstructorArgumentTestBean(@TestQualifier Person person) {
@@ -557,6 +564,52 @@ class InjectAnnotationAutowireContextTests {
}
+ static class JakartaNamedConstructorArgumentTestBean {
+
+ private final Animal animal1;
+ private final Animal animal2;
+
+ @jakarta.inject.Inject
+ public JakartaNamedConstructorArgumentTestBean(@jakarta.inject.Named("Cat") Animal animal1,
+ @jakarta.inject.Named("Dog") Animal animal2) {
+
+ this.animal1 = animal1;
+ this.animal2 = animal2;
+ }
+
+ public Animal getAnimal1() {
+ return this.animal1;
+ }
+
+ public Animal getAnimal2() {
+ return this.animal2;
+ }
+ }
+
+
+ static class JavaxNamedConstructorArgumentTestBean {
+
+ private final Animal animal1;
+ private final Animal animal2;
+
+ @javax.inject.Inject
+ public JavaxNamedConstructorArgumentTestBean(@javax.inject.Named("Cat") Animal animal1,
+ @javax.inject.Named("Dog") Animal animal2) {
+
+ this.animal1 = animal1;
+ this.animal2 = animal2;
+ }
+
+ public Animal getAnimal1() {
+ return this.animal1;
+ }
+
+ public Animal getAnimal2() {
+ return this.animal2;
+ }
+ }
+
+
public static class QualifiedFieldWithDefaultValueTestBean {
@Inject
@@ -593,13 +646,13 @@ class InjectAnnotationAutowireContextTests {
}
- public static class QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean {
+ static class QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean {
private Person person;
@Inject
public QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean(
- @Named("juergen") Person person) {
+ @Named(JUERGEN) Person person) {
this.person = person;
}
@@ -636,6 +689,52 @@ class InjectAnnotationAutowireContextTests {
}
+ interface Animal {
+
+ String getName();
+ }
+
+
+ @jakarta.inject.Named("Cat")
+ static class JakartaCat implements Animal {
+
+ @Override
+ public String getName() {
+ return "Jakarta Tiger";
+ }
+ }
+
+
+ @javax.inject.Named("Cat")
+ static class JavaxCat implements Animal {
+
+ @Override
+ public String getName() {
+ return "Javax Tiger";
+ }
+ }
+
+
+ @jakarta.inject.Named("Dog")
+ static class JakartaDog implements Animal {
+
+ @Override
+ public String getName() {
+ return "Jakarta Fido";
+ }
+ }
+
+
+ @javax.inject.Named("Dog")
+ static class JavaxDog implements Animal {
+
+ @Override
+ public String getName() {
+ return "Javax Fido";
+ }
+ }
+
+
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier