Merge branch '6.1.x'

This commit is contained in:
Sam Brannen 2024-08-08 14:20:56 +03:00
commit 3863b77536
6 changed files with 301 additions and 172 deletions

View File

@ -16,4 +16,5 @@ dependencies {
testImplementation(project(":spring-core-test")) testImplementation(project(":spring-core-test"))
testImplementation(testFixtures(project(":spring-core"))) testImplementation(testFixtures(project(":spring-core")))
testImplementation("jakarta.annotation:jakarta.annotation-api") testImplementation("jakarta.annotation:jakarta.annotation-api")
testImplementation("javax.inject:javax.inject")
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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; import org.springframework.lang.Nullable;
/** /**
* {@link RuntimeHintsRegistrar} for Jakarta annotations. * {@link RuntimeHintsRegistrar} for Jakarta annotations and their pre-Jakarta equivalents.
* *
* @author Brian Clozel * @author Brian Clozel
* @author Sam Brannen
*/ */
class JakartaAnnotationsRuntimeHints implements RuntimeHintsRegistrar { class JakartaAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
@Override @Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) { public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
Stream.of("jakarta.inject.Inject", "jakarta.inject.Provider", "jakarta.inject.Qualifier").forEach(typeName -> // javax.inject.Provider is omitted from the list, since we do not currently load
hints.reflection().registerType(TypeReference.of(typeName))); // 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)));
} }
} }

View File

@ -47,11 +47,13 @@ import org.springframework.util.ObjectUtils;
* against {@link Qualifier qualifier annotations} on the field or parameter to be autowired. * 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 suggested expression values through a {@link Value value} annotation.
* *
* <p>Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation, if available. * <p>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 Mark Fisher
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Sam Brannen
* @since 2.5 * @since 2.5
* @see AutowireCandidateQualifier * @see AutowireCandidateQualifier
* @see Qualifier * @see Qualifier
@ -65,9 +67,10 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
/** /**
* Create a new QualifierAnnotationAutowireCandidateResolver * Create a new {@code QualifierAnnotationAutowireCandidateResolver} for Spring's
* for Spring's standard {@link Qualifier} annotation. * standard {@link Qualifier} annotation.
* <p>Also supports JSR-330's {@link jakarta.inject.Qualifier} annotation, if available. * <p>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") @SuppressWarnings("unchecked")
public QualifierAnnotationAutowireCandidateResolver() { public QualifierAnnotationAutowireCandidateResolver() {
@ -76,14 +79,21 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
this.qualifierTypes.add((Class<? extends Annotation>) ClassUtils.forName("jakarta.inject.Qualifier", this.qualifierTypes.add((Class<? extends Annotation>) ClassUtils.forName("jakarta.inject.Qualifier",
QualifierAnnotationAutowireCandidateResolver.class.getClassLoader())); 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) { catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip. // JSR-330 API not available - simply skip.
} }
} }
/** /**
* Create a new QualifierAnnotationAutowireCandidateResolver * Create a new {@code QualifierAnnotationAutowireCandidateResolver} for the given
* for the given qualifier annotation type. * qualifier annotation type.
* @param qualifierType the qualifier annotation to look for * @param qualifierType the qualifier annotation to look for
*/ */
public QualifierAnnotationAutowireCandidateResolver(Class<? extends Annotation> qualifierType) { public QualifierAnnotationAutowireCandidateResolver(Class<? extends Annotation> qualifierType) {
@ -92,8 +102,8 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
} }
/** /**
* Create a new QualifierAnnotationAutowireCandidateResolver * Create a new {@code QualifierAnnotationAutowireCandidateResolver} for the given
* for the given qualifier annotation types. * qualifier annotation types.
* @param qualifierTypes the qualifier annotations to look for * @param qualifierTypes the qualifier annotations to look for
*/ */
public QualifierAnnotationAutowireCandidateResolver(Set<Class<? extends Annotation>> qualifierTypes) { public QualifierAnnotationAutowireCandidateResolver(Set<Class<? extends Annotation>> qualifierTypes) {

View File

@ -129,16 +129,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Nullable @Nullable
private static Class<?> javaxInjectProviderClass; private static Class<?> jakartaInjectProviderClass;
static { static {
try { try {
javaxInjectProviderClass = jakartaInjectProviderClass =
ClassUtils.forName("jakarta.inject.Provider", DefaultListableBeanFactory.class.getClassLoader()); ClassUtils.forName("jakarta.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
} }
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
// JSR-330 API not available - Provider interface simply not supported then. // 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()) { ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName); return new DependencyObjectProvider(descriptor, requestingBeanName);
} }
else if (javaxInjectProviderClass == descriptor.getDependencyType()) { else if (jakartaInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName); return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
} }
else if (descriptor.supportsLazyResolution()) { else if (descriptor.supportsLazyResolution()) {

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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}. * Tests for {@link JakartaAnnotationsRuntimeHints}.
* *
* @author Brian Clozel * @author Brian Clozel
* @author Sam Brannen
*/ */
class JakartaAnnotationsRuntimeHintsTests { class JakartaAnnotationsRuntimeHintsTests {
@ -62,4 +63,14 @@ class JakartaAnnotationsRuntimeHintsTests {
assertThat(RuntimeHintsPredicates.reflection().onType(Qualifier.class)).accepts(this.hints); 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);
}
} }

View File

@ -32,6 +32,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.UnsatisfiedDependencyException; import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.AnnotationConfigUtils; import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericApplicationContext;
@ -39,30 +40,35 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 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 Juergen Hoeller
* @author Sam Brannen
* @since 3.0 * @since 3.0
*/ */
class InjectAnnotationAutowireContextTests { class InjectAnnotationAutowireContextTests {
private static final String PERSON1 = "person1";
private static final String PERSON2 = "person2";
private static final String JUERGEN = "juergen"; private static final String JUERGEN = "juergen";
private static final String MARK = "mark"; private static final String MARK = "mark";
@Test @Test
void testAutowiredFieldWithSingleNonQualifiedCandidate() { void autowiredFieldWithSingleNonQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues(); ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN); cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition(PERSON1, person);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class));
new RootBeanDefinition(QualifiedFieldTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy( assertThatExceptionOfType(BeanCreationException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> { .satisfies(ex -> {
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class); assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
assertThat(ex.getBeanName()).isEqualTo("autowired"); assertThat(ex.getBeanName()).isEqualTo("autowired");
@ -70,17 +76,16 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredMethodParameterWithSingleNonQualifiedCandidate() { void autowiredMethodParameterWithSingleNonQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues(); ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN); cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition(PERSON1, person);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy( assertThatExceptionOfType(BeanCreationException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> { .satisfies(ex -> {
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class); assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
assertThat(ex.getBeanName()).isEqualTo("autowired"); assertThat(ex.getBeanName()).isEqualTo("autowired");
@ -88,28 +93,27 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredConstructorArgumentWithSingleNonQualifiedCandidate() { void autowiredConstructorArgumentWithSingleNonQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues(); ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN); cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition(PERSON1, person);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy( assertThatExceptionOfType(UnsatisfiedDependencyException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired")); .satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
} }
@Test @Test
void testAutowiredFieldWithSingleQualifiedCandidate() { void autowiredFieldWithSingleQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues(); ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN); cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition(PERSON1, person);
context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class)); context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
@ -118,15 +122,14 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredMethodParameterWithSingleQualifiedCandidate() { void autowiredMethodParameterWithSingleQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues(); ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN); cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition(PERSON1, person);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedMethodParameterTestBean bean = QualifiedMethodParameterTestBean bean =
@ -135,15 +138,14 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredMethodParameterWithStaticallyQualifiedCandidate() { void autowiredMethodParameterWithStaticallyQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues(); ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN); cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(QualifiedPerson.class, cavs, null); RootBeanDefinition person = new RootBeanDefinition(QualifiedPerson.class, cavs, null);
context.registerBeanDefinition(JUERGEN, context.registerBeanDefinition(PERSON1,
ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(person, JUERGEN), context, true).getBeanDefinition()); ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(person, JUERGEN), context, true).getBeanDefinition());
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedMethodParameterTestBean bean = QualifiedMethodParameterTestBean bean =
@ -152,18 +154,17 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredMethodParameterWithStaticallyQualifiedCandidateAmongOthers() { void autowiredMethodParameterWithStaticallyQualifiedCandidateAmongOthers() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues(); ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN); cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(QualifiedPerson.class, cavs, null); RootBeanDefinition person1 = new RootBeanDefinition(QualifiedPerson.class, cavs, null);
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedMethodParameterTestBean bean = QualifiedMethodParameterTestBean bean =
@ -172,15 +173,14 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredConstructorArgumentWithSingleQualifiedCandidate() { void autowiredConstructorArgumentWithSingleQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs = new ConstructorArgumentValues(); ConstructorArgumentValues cavs = new ConstructorArgumentValues();
cavs.addGenericArgumentValue(JUERGEN); cavs.addGenericArgumentValue(JUERGEN);
RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null);
person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class)); person.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition(PERSON1, person);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedConstructorArgumentTestBean bean = QualifiedConstructorArgumentTestBean bean =
@ -189,7 +189,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredFieldWithMultipleNonQualifiedCandidates() { void autowiredFieldWithMultipleNonQualifiedCandidates() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -197,13 +197,12 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class));
new RootBeanDefinition(QualifiedFieldTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy( assertThatExceptionOfType(BeanCreationException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> { .satisfies(ex -> {
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class); assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
assertThat(ex.getBeanName()).isEqualTo("autowired"); assertThat(ex.getBeanName()).isEqualTo("autowired");
@ -211,7 +210,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredMethodParameterWithMultipleNonQualifiedCandidates() { void autowiredMethodParameterWithMultipleNonQualifiedCandidates() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -219,13 +218,12 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy( assertThatExceptionOfType(BeanCreationException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> { .satisfies(ex -> {
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class); assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
assertThat(ex.getBeanName()).isEqualTo("autowired"); assertThat(ex.getBeanName()).isEqualTo("autowired");
@ -233,7 +231,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredConstructorArgumentWithMultipleNonQualifiedCandidates() { void autowiredConstructorArgumentWithMultipleNonQualifiedCandidates() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -241,18 +239,17 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy( assertThatExceptionOfType(UnsatisfiedDependencyException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired")); .satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
} }
@Test @Test
void testAutowiredFieldResolvesQualifiedCandidate() { void autowiredFieldResolvesQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -261,10 +258,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldTestBean.class));
new RootBeanDefinition(QualifiedFieldTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedFieldTestBean bean = (QualifiedFieldTestBean) context.getBean("autowired"); QualifiedFieldTestBean bean = (QualifiedFieldTestBean) context.getBean("autowired");
@ -272,7 +268,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredMethodParameterResolvesQualifiedCandidate() { void autowiredMethodParameterResolvesQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -281,10 +277,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedMethodParameterTestBean bean = QualifiedMethodParameterTestBean bean =
@ -293,7 +288,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredConstructorArgumentResolvesQualifiedCandidate() { void autowiredConstructorArgumentResolvesQualifiedCandidate() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -302,10 +297,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedConstructorArgumentTestBean bean = QualifiedConstructorArgumentTestBean bean =
@ -313,8 +307,28 @@ class InjectAnnotationAutowireContextTests {
assertThat(bean.getPerson().getName()).isEqualTo(JUERGEN); assertThat(bean.getPerson().getName()).isEqualTo(JUERGEN);
} }
@Test // gh-33345
void autowiredConstructorArgumentResolvesJakartaNamedCandidate() {
Class<JakartaNamedConstructorArgumentTestBean> 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<JavaxNamedConstructorArgumentTestBean> 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 @Test
void testAutowiredFieldResolvesQualifiedCandidateWithDefaultValueAndNoValueOnBeanDefinition() { void autowiredFieldResolvesQualifiedCandidateWithDefaultValueAndNoValueOnBeanDefinition() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -324,10 +338,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedFieldWithDefaultValueTestBean bean = QualifiedFieldWithDefaultValueTestBean bean =
@ -336,7 +349,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredFieldDoesNotResolveCandidateWithDefaultValueAndConflictingValueOnBeanDefinition() { void autowiredFieldDoesNotResolveCandidateWithDefaultValueAndConflictingValueOnBeanDefinition() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -346,13 +359,12 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy( assertThatExceptionOfType(BeanCreationException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> { .satisfies(ex -> {
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class); assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
assertThat(ex.getBeanName()).isEqualTo("autowired"); assertThat(ex.getBeanName()).isEqualTo("autowired");
@ -360,7 +372,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredFieldResolvesWithDefaultValueAndExplicitDefaultValueOnBeanDefinition() { void autowiredFieldResolvesWithDefaultValueAndExplicitDefaultValueOnBeanDefinition() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -370,10 +382,9 @@ class InjectAnnotationAutowireContextTests {
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue(MARK); cavs2.addGenericArgumentValue(MARK);
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedFieldWithDefaultValueTestBean bean = QualifiedFieldWithDefaultValueTestBean bean =
@ -382,7 +393,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredFieldResolvesWithMultipleQualifierValues() { void autowiredFieldResolvesWithMultipleQualifierValues() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -396,10 +407,9 @@ class InjectAnnotationAutowireContextTests {
AutowireCandidateQualifier qualifier2 = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class); AutowireCandidateQualifier qualifier2 = new AutowireCandidateQualifier(TestQualifierWithMultipleAttributes.class);
qualifier2.setAttribute("number", 123); qualifier2.setAttribute("number", 123);
person2.addQualifier(qualifier2); person2.addQualifier(qualifier2);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedFieldWithMultipleAttributesTestBean bean = QualifiedFieldWithMultipleAttributesTestBean bean =
@ -408,7 +418,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredFieldDoesNotResolveWithMultipleQualifierValuesAndConflictingDefaultValue() { void autowiredFieldDoesNotResolveWithMultipleQualifierValuesAndConflictingDefaultValue() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -423,13 +433,12 @@ class InjectAnnotationAutowireContextTests {
qualifier2.setAttribute("number", 123); qualifier2.setAttribute("number", 123);
qualifier2.setAttribute("value", "not the default"); qualifier2.setAttribute("value", "not the default");
person2.addQualifier(qualifier2); person2.addQualifier(qualifier2);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy( assertThatExceptionOfType(BeanCreationException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> { .satisfies(ex -> {
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class); assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
assertThat(ex.getBeanName()).isEqualTo("autowired"); assertThat(ex.getBeanName()).isEqualTo("autowired");
@ -437,7 +446,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredFieldResolvesWithMultipleQualifierValuesAndExplicitDefaultValue() { void autowiredFieldResolvesWithMultipleQualifierValuesAndExplicitDefaultValue() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -452,10 +461,9 @@ class InjectAnnotationAutowireContextTests {
qualifier2.setAttribute("number", 123); qualifier2.setAttribute("number", 123);
qualifier2.setAttribute("value", "default"); qualifier2.setAttribute("value", "default");
person2.addQualifier(qualifier2); person2.addQualifier(qualifier2);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh(); context.refresh();
QualifiedFieldWithMultipleAttributesTestBean bean = QualifiedFieldWithMultipleAttributesTestBean bean =
@ -464,7 +472,7 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredFieldDoesNotResolveWithMultipleQualifierValuesAndMultipleMatchingCandidates() { void autowiredFieldDoesNotResolveWithMultipleQualifierValuesAndMultipleMatchingCandidates() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue(JUERGEN); cavs1.addGenericArgumentValue(JUERGEN);
@ -479,13 +487,12 @@ class InjectAnnotationAutowireContextTests {
qualifier2.setAttribute("number", 123); qualifier2.setAttribute("number", 123);
qualifier2.setAttribute("value", "default"); qualifier2.setAttribute("value", "default");
person2.addQualifier(qualifier2); person2.addQualifier(qualifier2);
context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(PERSON1, person1);
context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition(PERSON2, person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy( assertThatExceptionOfType(BeanCreationException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> { .satisfies(ex -> {
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class); assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
assertThat(ex.getBeanName()).isEqualTo("autowired"); assertThat(ex.getBeanName()).isEqualTo("autowired");
@ -493,23 +500,23 @@ class InjectAnnotationAutowireContextTests {
} }
@Test @Test
void testAutowiredFieldDoesNotResolveWithBaseQualifierAndNonDefaultValueAndMultipleMatchingCandidates() { void autowiredConstructorArgumentDoesNotResolveWithBaseQualifierAndNonDefaultValueAndMultipleMatchingCandidates() {
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
cavs1.addGenericArgumentValue("the real juergen"); cavs1.addGenericArgumentValue("the real juergen");
RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); 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(); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
cavs2.addGenericArgumentValue("juergen imposter"); cavs2.addGenericArgumentValue("juergen imposter");
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); 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("juergen1", person1);
context.registerBeanDefinition("juergen2", person2); context.registerBeanDefinition("juergen2", person2);
context.registerBeanDefinition("autowired", context.registerBeanDefinition("autowired",
new RootBeanDefinition(QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean.class)); new RootBeanDefinition(QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean.class));
AnnotationConfigUtils.registerAnnotationConfigProcessors(context); AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy( assertThatExceptionOfType(UnsatisfiedDependencyException.class)
context::refresh) .isThrownBy(context::refresh)
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired")); .satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
} }
@ -543,7 +550,7 @@ class InjectAnnotationAutowireContextTests {
private static class QualifiedConstructorArgumentTestBean { private static class QualifiedConstructorArgumentTestBean {
private Person person; private final Person person;
@Inject @Inject
public QualifiedConstructorArgumentTestBean(@TestQualifier Person person) { 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 { public static class QualifiedFieldWithDefaultValueTestBean {
@Inject @Inject
@ -593,13 +646,13 @@ class InjectAnnotationAutowireContextTests {
} }
public static class QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean { static class QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean {
private Person person; private Person person;
@Inject @Inject
public QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean( public QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean(
@Named("juergen") Person person) { @Named(JUERGEN) Person person) {
this.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}) @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Qualifier @Qualifier