Consistent support for Java 8 default methods (in interfaces implemented by user classes)
Covers ReflectionUtils.doWithMethods as well as affected annotation post-processors. Includes an extension of MethodMetadata for the detection of @Bean default methods. Issue: SPR-12822 Issue: SPR-10919
This commit is contained in:
@@ -243,6 +243,26 @@ public class CommonAnnotationBeanPostProcessorTests {
|
||||
assertEquals("testBean4", depBeans[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceInjectionWithDefaultMethod() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(DefaultMethodResourceInjectionBean.class));
|
||||
TestBean tb2 = new TestBean();
|
||||
bf.registerSingleton("testBean2", tb2);
|
||||
NestedTestBean tb7 = new NestedTestBean();
|
||||
bf.registerSingleton("testBean7", tb7);
|
||||
|
||||
DefaultMethodResourceInjectionBean bean = (DefaultMethodResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(tb2, bean.getTestBean2());
|
||||
assertSame(2, bean.counter);
|
||||
|
||||
bf.destroySingletons();
|
||||
assertSame(3, bean.counter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceInjectionWithTwoProcessors() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
@@ -694,6 +714,42 @@ public class CommonAnnotationBeanPostProcessorTests {
|
||||
}
|
||||
|
||||
|
||||
public interface InterfaceWithDefaultMethod {
|
||||
|
||||
@Resource
|
||||
void setTestBean2(TestBean testBean2);
|
||||
|
||||
@Resource
|
||||
default void setTestBean7(INestedTestBean testBean7) {
|
||||
increaseCounter();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
default void initDefault() {
|
||||
increaseCounter();
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
default void destroyDefault() {
|
||||
increaseCounter();
|
||||
}
|
||||
|
||||
void increaseCounter();
|
||||
}
|
||||
|
||||
|
||||
public static class DefaultMethodResourceInjectionBean extends ResourceInjectionBean
|
||||
implements InterfaceWithDefaultMethod {
|
||||
|
||||
public int counter = 0;
|
||||
|
||||
@Override
|
||||
public void increaseCounter() {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ExtendedEjbInjectionBean extends ResourceInjectionBean {
|
||||
|
||||
@EJB(name="testBean4", beanInterface=TestBean.class)
|
||||
|
||||
@@ -470,6 +470,36 @@ public class ConfigurationClassPostProcessorTests {
|
||||
beanFactory.registerBeanDefinition("serviceBeanProvider", new RootBeanDefinition(ServiceBeanProvider.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
beanFactory.getBean(ServiceBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigWithDefaultMethods() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ConcreteConfigWithDefaultMethods.class));
|
||||
beanFactory.registerBeanDefinition("serviceBeanProvider", new RootBeanDefinition(ServiceBeanProvider.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
beanFactory.getBean(ServiceBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigWithDefaultMethodsUsingAsm() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ConcreteConfigWithDefaultMethods.class.getName()));
|
||||
beanFactory.registerBeanDefinition("serviceBeanProvider", new RootBeanDefinition(ServiceBeanProvider.class.getName()));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
beanFactory.getBean(ServiceBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -944,6 +974,37 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
}
|
||||
|
||||
public interface DefaultMethodsConfig {
|
||||
|
||||
@Bean
|
||||
default ServiceBean serviceBean() {
|
||||
return provider().getServiceBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
default ServiceBeanProvider provider() {
|
||||
return new ServiceBeanProvider();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class ConcreteConfigWithDefaultMethods implements DefaultMethodsConfig {
|
||||
|
||||
@Autowired
|
||||
private ServiceBeanProvider provider;
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public ServiceBeanProvider provider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void validate() {
|
||||
Assert.notNull(provider);
|
||||
}
|
||||
}
|
||||
|
||||
@Primary
|
||||
public static class ServiceBeanProvider {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -77,6 +77,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -98,11 +99,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
@Test
|
||||
public void fixedRateTask() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.FixedRateTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRateTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -128,6 +129,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -148,19 +150,29 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
|
||||
@Test
|
||||
public void severalFixedRatesWithRepeatedScheduledAnnotation() {
|
||||
BeanDefinition processorDefinition = new
|
||||
RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean.class);
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean.class);
|
||||
severalFixedRates(context, processorDefinition, targetDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalFixedRatesWithSchedulesContainerAnnotation() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
SeveralFixedRatesWithSchedulesContainerAnnotationTestBean.class);
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(SeveralFixedRatesWithSchedulesContainerAnnotationTestBean.class);
|
||||
severalFixedRates(context, processorDefinition, targetDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalFixedRatesOnBaseClass() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRatesSubBean.class);
|
||||
severalFixedRates(context, processorDefinition, targetDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalFixedRatesOnDefaultMethod() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRatesDefaultBean.class);
|
||||
severalFixedRates(context, processorDefinition, targetDefinition);
|
||||
}
|
||||
|
||||
@@ -170,6 +182,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -201,11 +214,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
Assume.group(TestGroup.LONG_RUNNING);
|
||||
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.CronTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(CronTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -229,11 +242,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
Assume.group(TestGroup.LONG_RUNNING);
|
||||
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.CronWithTimezoneTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(CronWithTimezoneTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -274,8 +287,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
Assume.group(TestGroup.LONG_RUNNING);
|
||||
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.CronWithInvalidTimezoneTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(CronWithInvalidTimezoneTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
@@ -286,8 +298,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
public void cronTaskWithMethodValidation() throws InterruptedException {
|
||||
BeanDefinition validationDefinition = new RootBeanDefinition(MethodValidationPostProcessor.class);
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.CronTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(CronTestBean.class);
|
||||
context.registerBeanDefinition("methodValidation", validationDefinition);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
@@ -301,6 +312,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -321,11 +333,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
@Test
|
||||
public void metaAnnotationWithCronExpression() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.MetaAnnotationCronTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(MetaAnnotationCronTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -356,6 +368,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -386,6 +399,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -417,6 +431,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -443,12 +458,12 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("schedules.businessHours", businessHoursCronExpression);
|
||||
placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.PropertyPlaceholderMetaAnnotationTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderMetaAnnotationTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("placeholder", placeholderDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
@@ -469,8 +484,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void emptyAnnotation() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.EmptyAnnotationTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(EmptyAnnotationTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
@@ -479,8 +493,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void invalidCron() throws Throwable {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.InvalidCronTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(InvalidCronTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
@@ -489,8 +502,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void nonVoidReturnType() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.NonVoidReturnTypeTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(NonVoidReturnTypeTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
@@ -499,8 +511,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void nonEmptyParamList() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.NonEmptyParamListTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(NonEmptyParamListTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
@@ -542,16 +553,39 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||
|
||||
static class SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean {
|
||||
|
||||
// can use Java 8 repeated @Scheduled once we have Eclipse IDE support for it
|
||||
@Schedules({
|
||||
@Scheduled(fixedRate=4000),
|
||||
@Scheduled(fixedRate=4000, initialDelay=2000)
|
||||
})
|
||||
@Scheduled(fixedRate=4000)
|
||||
@Scheduled(fixedRate=4000, initialDelay=2000)
|
||||
public void fixedRate() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class FixedRatesBaseBean {
|
||||
|
||||
@Scheduled(fixedRate=4000)
|
||||
@Scheduled(fixedRate=4000, initialDelay=2000)
|
||||
public void fixedRate() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class FixedRatesSubBean extends FixedRatesBaseBean {
|
||||
}
|
||||
|
||||
|
||||
static interface FixedRatesDefaultMethod {
|
||||
|
||||
@Scheduled(fixedRate=4000)
|
||||
@Scheduled(fixedRate=4000, initialDelay=2000)
|
||||
default void fixedRate() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class FixedRatesDefaultBean implements FixedRatesDefaultMethod {
|
||||
}
|
||||
|
||||
|
||||
@Validated
|
||||
static class CronTestBean {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user