Merge branch '6.0.x'

This commit is contained in:
Stephane Nicoll 2023-05-04 12:23:46 +02:00
commit 69cde11a51
4 changed files with 130 additions and 3 deletions

View File

@ -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.
@ -19,11 +19,14 @@ package org.springframework.beans.factory.aot;
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;
@ -40,6 +43,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
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;
@ -119,6 +123,7 @@ class BeanDefinitionPropertiesCodeGenerator {
addConstructorArgumentValues(code, beanDefinition);
addPropertyValues(code, beanDefinition);
addAttributes(code, beanDefinition);
addQualifiers(code, beanDefinition);
return code.build();
}
@ -180,6 +185,24 @@ class BeanDefinitionPropertiesCodeGenerator {
}
}
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);

View File

@ -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.
@ -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;
@ -36,6 +39,7 @@ import org.springframework.beans.factory.config.BeanReference;
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;
@ -392,6 +396,43 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
});
}
@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);

View File

@ -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.
@ -64,6 +64,7 @@ import org.springframework.context.testfixture.context.annotation.LazyAutowiredM
import org.springframework.context.testfixture.context.annotation.LazyConstructorArgumentComponent;
import org.springframework.context.testfixture.context.annotation.LazyFactoryMethodArgumentComponent;
import org.springframework.context.testfixture.context.annotation.PropertySourceConfiguration;
import org.springframework.context.testfixture.context.annotation.QualifierConfiguration;
import org.springframework.context.testfixture.context.generator.SimpleComponent;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
@ -303,6 +304,17 @@ class ApplicationContextAotGeneratorTests {
});
}
@Test
void processAheadOfTimeWithQualifier() {
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.registerBean(QualifierConfiguration.class);
testCompiledResult(applicationContext, (initializer, compiled) -> {
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
QualifierConfiguration configuration = freshApplicationContext.getBean(QualifierConfiguration.class);
assertThat(configuration).hasFieldOrPropertyWithValue("bean", "one");
});
}
@Nested
@CompileWithForkedClassLoader
class ConfigurationClassCglibProxy {

View File

@ -0,0 +1,51 @@
/*
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.testfixture.context.annotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class QualifierConfiguration {
private String bean;
@Autowired
@Qualifier("1")
public void setBean(String bean) {
this.bean = bean;
}
public static class BeansConfiguration {
@Bean
@Qualifier("1")
public String one() {
return "one";
}
@Bean
@Qualifier("2")
public String two() {
return "one";
}
}
}