Skip to content

Commit

Permalink
Add AOT support for Qualifiers
Browse files Browse the repository at this point in the history
This commit handles AutowiredCandidateQualifier instances, rather than
relying on qualifiers being statically defined and meta-annotated with
`@Qualifier`.

Closes spring-projectsgh-30410
  • Loading branch information
snicoll committed May 3, 2023
1 parent aabd685 commit 2f41ce6
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,11 +19,14 @@
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
Expand All @@ -40,6 +43,7 @@
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.InstanceSupplier;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.javapoet.CodeBlock;
Expand Down Expand Up @@ -119,6 +123,7 @@ CodeBlock generateCode(RootBeanDefinition beanDefinition) {
addConstructorArgumentValues(code, beanDefinition);
addPropertyValues(code, beanDefinition);
addAttributes(code, beanDefinition);
addQualifiers(code, beanDefinition);
return code.build();
}

Expand Down Expand Up @@ -180,6 +185,24 @@ private void addPropertyValues(CodeBlock.Builder code,
}
}

private void addQualifiers(CodeBlock.Builder code,
RootBeanDefinition beanDefinition) {

Set<AutowireCandidateQualifier> qualifiers = beanDefinition.getQualifiers();
if (!qualifiers.isEmpty()) {
for (AutowireCandidateQualifier qualifier : qualifiers) {
Collection<CodeBlock> arguments = new ArrayList<>();
arguments.add(CodeBlock.of("$S", qualifier.getTypeName()));
Object qualifierValue = qualifier.getAttribute(AutowireCandidateQualifier.VALUE_KEY);
if (qualifierValue != null) {
arguments.add(generateValue("value", qualifierValue));
}
code.addStatement("$L.addQualifier(new $T($L))", BEAN_DEFINITION_VARIABLE,
AutowireCandidateQualifier.class, CodeBlock.join(arguments, ", "));
}
}
}

private CodeBlock generateValue(@Nullable String name, @Nullable Object value) {
try {
PropertyNamesStack.push(name);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,10 +16,13 @@

package org.springframework.beans.factory.aot;

import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;

Expand All @@ -36,6 +39,7 @@
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.config.RuntimeBeanNameReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
Expand Down Expand Up @@ -392,6 +396,43 @@ void attributesWhenSomeFiltered() {
});
}

@Test
void qualifiersWhenQualifierHasNoValue() {
this.beanDefinition.addQualifier(new AutowireCandidateQualifier("com.example.Qualifier"));
compile((actual, compiled) -> {
assertThat(actual.getQualifiers()).singleElement().satisfies(isQualifierFor("com.example.Qualifier", null));
assertThat(this.beanDefinition.getQualifiers()).isEqualTo(actual.getQualifiers());
});
}

@Test
void qualifiersWhenQualifierHasStringValue() {
this.beanDefinition.addQualifier(new AutowireCandidateQualifier("com.example.Qualifier", "id"));
compile((actual, compiled) -> {
assertThat(actual.getQualifiers()).singleElement().satisfies(isQualifierFor("com.example.Qualifier", "id"));
assertThat(this.beanDefinition.getQualifiers()).isEqualTo(actual.getQualifiers());
});
}

@Test
void qualifiersWhenMultipleQualifiers() {
this.beanDefinition.addQualifier(new AutowireCandidateQualifier("com.example.Qualifier", "id"));
this.beanDefinition.addQualifier(new AutowireCandidateQualifier("com.example.Another", ChronoUnit.SECONDS));
compile((actual, compiled) -> {
List<AutowireCandidateQualifier> qualifiers = new ArrayList<>(actual.getQualifiers());
assertThat(qualifiers.get(0)).satisfies(isQualifierFor("com.example.Qualifier", "id"));
assertThat(qualifiers.get(1)).satisfies(isQualifierFor("com.example.Another", ChronoUnit.SECONDS));
assertThat(qualifiers).hasSize(2);
});
}

private Consumer<AutowireCandidateQualifier> isQualifierFor(String typeName, Object value) {
return qualifier -> {
assertThat(qualifier.getTypeName()).isEqualTo(typeName);
assertThat(qualifier.getAttribute(AutowireCandidateQualifier.VALUE_KEY)).isEqualTo(value);
};
}

@Test
void multipleItems() {
this.beanDefinition.setPrimary(true);
Expand Down

0 comments on commit 2f41ce6

Please sign in to comment.