Merge branch '6.0.x'

This commit is contained in:
Juergen Hoeller 2023-07-18 12:57:18 +02:00
commit c504ac5a47
4 changed files with 41 additions and 29 deletions

View File

@ -90,8 +90,7 @@ class BeanDefinitionMethodGenerator {
/** /**
* Generate the method that returns the {@link BeanDefinition} to be * Generate the method that returns the {@link BeanDefinition} to be registered.
* registered.
* @param generationContext the generation context * @param generationContext the generation context
* @param beanRegistrationsCode the bean registrations code * @param beanRegistrationsCode the bean registrations code
* @return a reference to the generated method. * @return a reference to the generated method.
@ -100,8 +99,7 @@ class BeanDefinitionMethodGenerator {
BeanRegistrationsCode beanRegistrationsCode) { BeanRegistrationsCode beanRegistrationsCode) {
registerRuntimeHintsIfNecessary(generationContext.getRuntimeHints()); registerRuntimeHintsIfNecessary(generationContext.getRuntimeHints());
BeanRegistrationCodeFragments codeFragments = getCodeFragments(generationContext, BeanRegistrationCodeFragments codeFragments = getCodeFragments(generationContext, beanRegistrationsCode);
beanRegistrationsCode);
ClassName target = codeFragments.getTarget(this.registeredBean, this.constructorOrFactoryMethod); ClassName target = codeFragments.getTarget(this.registeredBean, this.constructorOrFactoryMethod);
if (isWritablePackageName(target)) { if (isWritablePackageName(target)) {
GeneratedClass generatedClass = lookupGeneratedClass(generationContext, target); GeneratedClass generatedClass = lookupGeneratedClass(generationContext, target);
@ -187,7 +185,7 @@ class BeanDefinitionMethodGenerator {
return generatedMethods.add("getBeanDefinition", method -> { return generatedMethods.add("getBeanDefinition", method -> {
method.addJavadoc("Get the $L definition for '$L'.", method.addJavadoc("Get the $L definition for '$L'.",
(!this.registeredBean.isInnerBean()) ? "bean" : "inner-bean", (this.registeredBean.isInnerBean() ? "inner-bean" : "bean"),
getName()); getName());
method.addModifiers(modifier, Modifier.STATIC); method.addModifiers(modifier, Modifier.STATIC);
method.returns(BeanDefinition.class); method.returns(BeanDefinition.class);
@ -214,9 +212,9 @@ class BeanDefinitionMethodGenerator {
private String getSimpleBeanName(String beanName) { private String getSimpleBeanName(String beanName) {
int lastDot = beanName.lastIndexOf('.'); int lastDot = beanName.lastIndexOf('.');
beanName = (lastDot != -1) ? beanName.substring(lastDot + 1) : beanName; beanName = (lastDot != -1 ? beanName.substring(lastDot + 1) : beanName);
int lastDollar = beanName.lastIndexOf('$'); int lastDollar = beanName.lastIndexOf('$');
beanName = (lastDollar != -1) ? beanName.substring(lastDollar + 1) : beanName; beanName = (lastDollar != -1 ? beanName.substring(lastDollar + 1) : beanName);
return StringUtils.uncapitalize(beanName); return StringUtils.uncapitalize(beanName);
} }

View File

@ -975,19 +975,19 @@ class ConstructorResolver {
Assert.state(isCompatible, () -> String.format( Assert.state(isCompatible, () -> String.format(
"Incompatible target type '%s' for factory bean '%s'", "Incompatible target type '%s' for factory bean '%s'",
resolvableType.toClass().getName(), factoryBeanClass.getName())); resolvableType.toClass().getName(), factoryBeanClass.getName()));
Executable executable = resolveConstructor(beanName, mbd, Constructor<?> constructor = resolveConstructor(beanName, mbd,
() -> ResolvableType.forClass(factoryBeanClass), valueTypes); () -> ResolvableType.forClass(factoryBeanClass), valueTypes);
if (executable != null) { if (constructor != null) {
return executable; return constructor;
} }
throw new IllegalStateException("No suitable FactoryBean constructor found for " + throw new IllegalStateException("No suitable FactoryBean constructor found for " +
mbd + " and argument types " + valueTypes); mbd + " and argument types " + valueTypes);
} }
Executable resolvedConstructor = resolveConstructor(beanName, mbd, beanType, valueTypes); Constructor<?> constructor = resolveConstructor(beanName, mbd, beanType, valueTypes);
if (resolvedConstructor != null) { if (constructor != null) {
return resolvedConstructor; return constructor;
} }
throw new IllegalStateException("No constructor or factory method candidate found for " + throw new IllegalStateException("No constructor or factory method candidate found for " +
@ -1030,7 +1030,7 @@ class ConstructorResolver {
} }
@Nullable @Nullable
private Executable resolveConstructor(String beanName, RootBeanDefinition mbd, private Constructor<?> resolveConstructor(String beanName, RootBeanDefinition mbd,
Supplier<ResolvableType> beanType, List<ResolvableType> valueTypes) { Supplier<ResolvableType> beanType, List<ResolvableType> valueTypes) {
Class<?> type = ClassUtils.getUserClass(beanType.get().toClass()); Class<?> type = ClassUtils.getUserClass(beanType.get().toClass());
@ -1054,14 +1054,14 @@ class ConstructorResolver {
} }
return types; return types;
}; };
List<? extends Executable> matches = Arrays.stream(ctors) List<Constructor<?>> matches = Arrays.stream(ctors)
.filter(executable -> match(parameterTypesFactory.apply(executable), .filter(executable -> match(parameterTypesFactory.apply(executable),
valueTypes, FallbackMode.NONE)) valueTypes, FallbackMode.NONE))
.toList(); .toList();
if (matches.size() == 1) { if (matches.size() == 1) {
return matches.get(0); return matches.get(0);
} }
List<? extends Executable> assignableElementFallbackMatches = Arrays List<Constructor<?>> assignableElementFallbackMatches = Arrays
.stream(ctors) .stream(ctors)
.filter(executable -> match(parameterTypesFactory.apply(executable), .filter(executable -> match(parameterTypesFactory.apply(executable),
valueTypes, FallbackMode.ASSIGNABLE_ELEMENT)) valueTypes, FallbackMode.ASSIGNABLE_ELEMENT))
@ -1069,7 +1069,7 @@ class ConstructorResolver {
if (assignableElementFallbackMatches.size() == 1) { if (assignableElementFallbackMatches.size() == 1) {
return assignableElementFallbackMatches.get(0); return assignableElementFallbackMatches.get(0);
} }
List<? extends Executable> typeConversionFallbackMatches = Arrays List<Constructor<?>> typeConversionFallbackMatches = Arrays
.stream(ctors) .stream(ctors)
.filter(executable -> match(parameterTypesFactory.apply(executable), .filter(executable -> match(parameterTypesFactory.apply(executable),
valueTypes, FallbackMode.TYPE_CONVERSION)) valueTypes, FallbackMode.TYPE_CONVERSION))
@ -1121,7 +1121,7 @@ class ConstructorResolver {
} }
return types; return types;
}; };
result = (Method) resolveFactoryMethod(candidates, parameterTypesFactory, valueTypes); result = resolveFactoryMethod(candidates, parameterTypesFactory, valueTypes);
} }
if (result == null) { if (result == null) {
@ -1138,24 +1138,24 @@ class ConstructorResolver {
} }
@Nullable @Nullable
private Executable resolveFactoryMethod(List<Method> executables, private Method resolveFactoryMethod(List<Method> executables,
Function<Method, List<ResolvableType>> parameterTypesFactory, Function<Method, List<ResolvableType>> parameterTypesFactory,
List<ResolvableType> valueTypes) { List<ResolvableType> valueTypes) {
List<? extends Executable> matches = executables.stream() List<Method> matches = executables.stream()
.filter(executable -> match(parameterTypesFactory.apply(executable), valueTypes, FallbackMode.NONE)) .filter(executable -> match(parameterTypesFactory.apply(executable), valueTypes, FallbackMode.NONE))
.toList(); .toList();
if (matches.size() == 1) { if (matches.size() == 1) {
return matches.get(0); return matches.get(0);
} }
List<? extends Executable> assignableElementFallbackMatches = executables.stream() List<Method> assignableElementFallbackMatches = executables.stream()
.filter(executable -> match(parameterTypesFactory.apply(executable), .filter(executable -> match(parameterTypesFactory.apply(executable),
valueTypes, FallbackMode.ASSIGNABLE_ELEMENT)) valueTypes, FallbackMode.ASSIGNABLE_ELEMENT))
.toList(); .toList();
if (assignableElementFallbackMatches.size() == 1) { if (assignableElementFallbackMatches.size() == 1) {
return assignableElementFallbackMatches.get(0); return assignableElementFallbackMatches.get(0);
} }
List<? extends Executable> typeConversionFallbackMatches = executables.stream() List<Method> typeConversionFallbackMatches = executables.stream()
.filter(executable -> match(parameterTypesFactory.apply(executable), .filter(executable -> match(parameterTypesFactory.apply(executable),
valueTypes, FallbackMode.TYPE_CONVERSION)) valueTypes, FallbackMode.TYPE_CONVERSION))
.toList(); .toList();

View File

@ -517,7 +517,6 @@ class AnnotationDrivenEventListenerTests {
ReplyEventListener replyEventListener = this.context.getBean(ReplyEventListener.class); ReplyEventListener replyEventListener = this.context.getBean(ReplyEventListener.class);
TestEventListener listener = this.context.getBean(TestEventListener.class); TestEventListener listener = this.context.getBean(TestEventListener.class);
this.eventCollector.assertNoEventReceived(listener); this.eventCollector.assertNoEventReceived(listener);
this.eventCollector.assertNoEventReceived(replyEventListener); this.eventCollector.assertNoEventReceived(replyEventListener);
this.context.publishEvent(event); this.context.publishEvent(event);
@ -634,6 +633,17 @@ class AnnotationDrivenEventListenerTests {
assertThat(listener.order).contains("first", "second", "third"); assertThat(listener.order).contains("first", "second", "third");
} }
@Test
void publicSubclassWithInheritedEventListener() {
load(PublicSubclassWithInheritedEventListener.class);
TestEventListener listener = this.context.getBean(PublicSubclassWithInheritedEventListener.class);
this.eventCollector.assertNoEventReceived(listener);
this.context.publishEvent("test");
this.eventCollector.assertEvent(listener, "test");
this.eventCollector.assertTotalEventsCount(1);
}
@Test @Disabled // SPR-15122 @Test @Disabled // SPR-15122
void listenersReceiveEarlyEvents() { void listenersReceiveEarlyEvents() {
load(EventOnPostConstruct.class, OrderedTestListener.class); load(EventOnPostConstruct.class, OrderedTestListener.class);
@ -646,7 +656,7 @@ class AnnotationDrivenEventListenerTests {
void missingListenerBeanIgnored() { void missingListenerBeanIgnored() {
load(MissingEventListener.class); load(MissingEventListener.class);
context.getBean(UseMissingEventListener.class); context.getBean(UseMissingEventListener.class);
context.getBean(ApplicationEventMulticaster.class).multicastEvent(new TestEvent(this)); context.publishEvent(new TestEvent(this));
} }
@ -753,7 +763,6 @@ class AnnotationDrivenEventListenerTests {
public void handleContextEvent(ApplicationContextEvent event) { public void handleContextEvent(ApplicationContextEvent event) {
collectEvent(event); collectEvent(event);
} }
} }
@ -979,7 +988,6 @@ class AnnotationDrivenEventListenerTests {
} }
@EventListener @EventListener
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface ConditionalEvent { public @interface ConditionalEvent {
@ -1031,7 +1039,7 @@ class AnnotationDrivenEventListenerTests {
} }
@Configuration @Component
static class OrderedTestListener extends TestEventListener { static class OrderedTestListener extends TestEventListener {
public final List<String> order = new ArrayList<>(); public final List<String> order = new ArrayList<>();
@ -1055,6 +1063,11 @@ class AnnotationDrivenEventListenerTests {
} }
@Component
public static class PublicSubclassWithInheritedEventListener extends TestEventListener {
}
static class EventOnPostConstruct { static class EventOnPostConstruct {
@Autowired @Autowired

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2023 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.
@ -74,7 +74,8 @@ public final class MethodIntrospector {
T result = metadataLookup.inspect(specificMethod); T result = metadataLookup.inspect(specificMethod);
if (result != null) { if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) { if (bridgedMethod == specificMethod || bridgedMethod == method ||
metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result); methodMap.put(specificMethod, result);
} }
} }