diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java index 13bf2898b19..68a06fd7dbf 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java @@ -90,8 +90,7 @@ class BeanDefinitionMethodGenerator { /** - * Generate the method that returns the {@link BeanDefinition} to be - * registered. + * Generate the method that returns the {@link BeanDefinition} to be registered. * @param generationContext the generation context * @param beanRegistrationsCode the bean registrations code * @return a reference to the generated method. @@ -100,8 +99,7 @@ class BeanDefinitionMethodGenerator { BeanRegistrationsCode beanRegistrationsCode) { registerRuntimeHintsIfNecessary(generationContext.getRuntimeHints()); - BeanRegistrationCodeFragments codeFragments = getCodeFragments(generationContext, - beanRegistrationsCode); + BeanRegistrationCodeFragments codeFragments = getCodeFragments(generationContext, beanRegistrationsCode); ClassName target = codeFragments.getTarget(this.registeredBean, this.constructorOrFactoryMethod); if (isWritablePackageName(target)) { GeneratedClass generatedClass = lookupGeneratedClass(generationContext, target); @@ -187,7 +185,7 @@ class BeanDefinitionMethodGenerator { return generatedMethods.add("getBeanDefinition", method -> { method.addJavadoc("Get the $L definition for '$L'.", - (!this.registeredBean.isInnerBean()) ? "bean" : "inner-bean", + (this.registeredBean.isInnerBean() ? "inner-bean" : "bean"), getName()); method.addModifiers(modifier, Modifier.STATIC); method.returns(BeanDefinition.class); @@ -214,9 +212,9 @@ class BeanDefinitionMethodGenerator { private String getSimpleBeanName(String beanName) { int lastDot = beanName.lastIndexOf('.'); - beanName = (lastDot != -1) ? beanName.substring(lastDot + 1) : beanName; + beanName = (lastDot != -1 ? beanName.substring(lastDot + 1) : beanName); int lastDollar = beanName.lastIndexOf('$'); - beanName = (lastDollar != -1) ? beanName.substring(lastDollar + 1) : beanName; + beanName = (lastDollar != -1 ? beanName.substring(lastDollar + 1) : beanName); return StringUtils.uncapitalize(beanName); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java index 36e3e7e78a4..6af615a3204 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java @@ -975,19 +975,19 @@ class ConstructorResolver { Assert.state(isCompatible, () -> String.format( "Incompatible target type '%s' for factory bean '%s'", resolvableType.toClass().getName(), factoryBeanClass.getName())); - Executable executable = resolveConstructor(beanName, mbd, + Constructor constructor = resolveConstructor(beanName, mbd, () -> ResolvableType.forClass(factoryBeanClass), valueTypes); - if (executable != null) { - return executable; + if (constructor != null) { + return constructor; } throw new IllegalStateException("No suitable FactoryBean constructor found for " + mbd + " and argument types " + valueTypes); } - Executable resolvedConstructor = resolveConstructor(beanName, mbd, beanType, valueTypes); - if (resolvedConstructor != null) { - return resolvedConstructor; + Constructor constructor = resolveConstructor(beanName, mbd, beanType, valueTypes); + if (constructor != null) { + return constructor; } throw new IllegalStateException("No constructor or factory method candidate found for " + @@ -1030,7 +1030,7 @@ class ConstructorResolver { } @Nullable - private Executable resolveConstructor(String beanName, RootBeanDefinition mbd, + private Constructor resolveConstructor(String beanName, RootBeanDefinition mbd, Supplier beanType, List valueTypes) { Class type = ClassUtils.getUserClass(beanType.get().toClass()); @@ -1054,14 +1054,14 @@ class ConstructorResolver { } return types; }; - List matches = Arrays.stream(ctors) + List> matches = Arrays.stream(ctors) .filter(executable -> match(parameterTypesFactory.apply(executable), valueTypes, FallbackMode.NONE)) .toList(); if (matches.size() == 1) { return matches.get(0); } - List assignableElementFallbackMatches = Arrays + List> assignableElementFallbackMatches = Arrays .stream(ctors) .filter(executable -> match(parameterTypesFactory.apply(executable), valueTypes, FallbackMode.ASSIGNABLE_ELEMENT)) @@ -1069,7 +1069,7 @@ class ConstructorResolver { if (assignableElementFallbackMatches.size() == 1) { return assignableElementFallbackMatches.get(0); } - List typeConversionFallbackMatches = Arrays + List> typeConversionFallbackMatches = Arrays .stream(ctors) .filter(executable -> match(parameterTypesFactory.apply(executable), valueTypes, FallbackMode.TYPE_CONVERSION)) @@ -1121,7 +1121,7 @@ class ConstructorResolver { } return types; }; - result = (Method) resolveFactoryMethod(candidates, parameterTypesFactory, valueTypes); + result = resolveFactoryMethod(candidates, parameterTypesFactory, valueTypes); } if (result == null) { @@ -1138,24 +1138,24 @@ class ConstructorResolver { } @Nullable - private Executable resolveFactoryMethod(List executables, + private Method resolveFactoryMethod(List executables, Function> parameterTypesFactory, List valueTypes) { - List matches = executables.stream() + List matches = executables.stream() .filter(executable -> match(parameterTypesFactory.apply(executable), valueTypes, FallbackMode.NONE)) .toList(); if (matches.size() == 1) { return matches.get(0); } - List assignableElementFallbackMatches = executables.stream() + List assignableElementFallbackMatches = executables.stream() .filter(executable -> match(parameterTypesFactory.apply(executable), valueTypes, FallbackMode.ASSIGNABLE_ELEMENT)) .toList(); if (assignableElementFallbackMatches.size() == 1) { return assignableElementFallbackMatches.get(0); } - List typeConversionFallbackMatches = executables.stream() + List typeConversionFallbackMatches = executables.stream() .filter(executable -> match(parameterTypesFactory.apply(executable), valueTypes, FallbackMode.TYPE_CONVERSION)) .toList(); diff --git a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java index 1ec92c65882..d263fb1e8ce 100644 --- a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java @@ -517,7 +517,6 @@ class AnnotationDrivenEventListenerTests { ReplyEventListener replyEventListener = this.context.getBean(ReplyEventListener.class); TestEventListener listener = this.context.getBean(TestEventListener.class); - this.eventCollector.assertNoEventReceived(listener); this.eventCollector.assertNoEventReceived(replyEventListener); this.context.publishEvent(event); @@ -634,6 +633,17 @@ class AnnotationDrivenEventListenerTests { 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 void listenersReceiveEarlyEvents() { load(EventOnPostConstruct.class, OrderedTestListener.class); @@ -646,7 +656,7 @@ class AnnotationDrivenEventListenerTests { void missingListenerBeanIgnored() { load(MissingEventListener.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) { collectEvent(event); } - } @@ -979,7 +988,6 @@ class AnnotationDrivenEventListenerTests { } - @EventListener @Retention(RetentionPolicy.RUNTIME) public @interface ConditionalEvent { @@ -1031,7 +1039,7 @@ class AnnotationDrivenEventListenerTests { } - @Configuration + @Component static class OrderedTestListener extends TestEventListener { public final List order = new ArrayList<>(); @@ -1055,6 +1063,11 @@ class AnnotationDrivenEventListenerTests { } + @Component + public static class PublicSubclassWithInheritedEventListener extends TestEventListener { + } + + static class EventOnPostConstruct { @Autowired diff --git a/spring-core/src/main/java/org/springframework/core/MethodIntrospector.java b/spring-core/src/main/java/org/springframework/core/MethodIntrospector.java index 2947945cc48..9f905cbda47 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodIntrospector.java +++ b/spring-core/src/main/java/org/springframework/core/MethodIntrospector.java @@ -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"); * 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); if (result != null) { 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); } }