From 03affa02dbb3d629d12228b1622a1d2c8cd37931 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 27 May 2016 22:34:09 +0200 Subject: [PATCH] ConfigurationClassParser detects @Bean methods in interface hierarchies as well Issue: SPR-14288 --- .../annotation/ConfigurationClassParser.java | 28 +++++++++++-------- .../ConfigurationClassPostProcessorTests.java | 20 +++++++++---- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index 2e00f9a3e0..ffed74571f 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -303,15 +303,7 @@ class ConfigurationClassParser { } // Process default methods on interfaces - for (SourceClass ifc : sourceClass.getInterfaces()) { - beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName()); - for (MethodMetadata methodMetadata : beanMethods) { - if (!methodMetadata.isAbstract()) { - // A default method or other concrete method on a Java 8+ interface... - configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); - } - } - } + processInterfaces(configClass, sourceClass); // Process superclass, if any if (sourceClass.getMetadata().hasSuperClass()) { @@ -329,8 +321,6 @@ class ConfigurationClassParser { /** * Register member (nested) classes that happen to be configuration classes themselves. - * @param sourceClass the source class to process - * @throws IOException if there is any problem reading metadata from a member class */ private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { for (SourceClass memberClass : sourceClass.getMemberClasses()) { @@ -352,6 +342,22 @@ class ConfigurationClassParser { } } + /** + * Register default methods on interfaces implemented by the configuration class. + */ + private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { + for (SourceClass ifc : sourceClass.getInterfaces()) { + Set beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName()); + for (MethodMetadata methodMetadata : beanMethods) { + if (!methodMetadata.isAbstract()) { + // A default method or other concrete method on a Java 8+ interface... + configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); + } + } + processInterfaces(configClass, ifc); + } + } + /** * Process the given @PropertySource annotation metadata. * @param propertySource metadata for the @PropertySource annotation found diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java index a1feb216c7..5bebb953b6 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java @@ -1063,17 +1063,27 @@ public class ConfigurationClassPostProcessorTests { } } - public interface DefaultMethodsConfig { + public interface BaseInterface { - @Bean - default ServiceBean serviceBean() { - return provider().getServiceBean(); - } + ServiceBean serviceBean(); + } + + public interface BaseDefaultMethods extends BaseInterface { @Bean default ServiceBeanProvider provider() { return new ServiceBeanProvider(); } + + @Bean + @Override + default ServiceBean serviceBean() { + return provider().getServiceBean(); + } + } + + public interface DefaultMethodsConfig extends BaseDefaultMethods { + } @Configuration