Support for Java 8's java.util.Optional at injection points
Issue: SPR-11833
This commit is contained in:
parent
6aa9c40552
commit
7d03daf8cb
|
@ -36,6 +36,7 @@ import java.util.IdentityHashMap;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.inject.Provider;
|
||||
|
@ -108,6 +109,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
|
||||
private static Class<?> javaxInjectProviderClass = null;
|
||||
|
||||
private static Class<?> javaUtilOptionalClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
javaxInjectProviderClass =
|
||||
|
@ -116,6 +119,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - Provider interface simply not supported then.
|
||||
}
|
||||
try {
|
||||
javaUtilOptionalClass =
|
||||
ClassUtils.forName("java.util.Optional", DefaultListableBeanFactory.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Java 8 not available - Optional references simply not supported then.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -854,6 +864,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
else if (descriptor.getDependencyType().equals(javaxInjectProviderClass)) {
|
||||
return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName);
|
||||
}
|
||||
else if (descriptor.getDependencyType().equals(javaUtilOptionalClass)) {
|
||||
return new OptionalDependencyFactory().createOptionalDependency(descriptor, beanName);
|
||||
}
|
||||
else {
|
||||
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, beanName);
|
||||
if (result == null) {
|
||||
|
@ -1319,4 +1332,22 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Separate inner class for avoiding a hard dependency on the {@code javax.inject} API.
|
||||
*/
|
||||
private class OptionalDependencyFactory {
|
||||
|
||||
public Object createOptionalDependency(DependencyDescriptor descriptor, String beanName) {
|
||||
DependencyDescriptor descriptorToUse = new DependencyDescriptor(descriptor) {
|
||||
@Override
|
||||
public boolean isRequired() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
descriptorToUse.increaseNestingLevel();
|
||||
return Optional.ofNullable(doResolveDependency(descriptorToUse, beanName, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,6 +19,7 @@ package org.springframework.beans.factory.annotation;
|
|||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
@ -573,6 +574,62 @@ public class InjectAnnotationBeanPostProcessorTests {
|
|||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalFieldInjectionWithBeanAvailable() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalFieldInjectionBean.class));
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
OptionalFieldInjectionBean bean = (OptionalFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
assertTrue(bean.getTestBean().isPresent());
|
||||
assertSame(bf.getBean("testBean"), bean.getTestBean().get());
|
||||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalFieldInjectionWithBeanNotAvailable() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalFieldInjectionBean.class));
|
||||
|
||||
OptionalFieldInjectionBean bean = (OptionalFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
assertFalse(bean.getTestBean().isPresent());
|
||||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalMethodInjectionWithBeanAvailable() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalMethodInjectionBean.class));
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
OptionalMethodInjectionBean bean = (OptionalMethodInjectionBean) bf.getBean("annotatedBean");
|
||||
assertTrue(bean.getTestBean().isPresent());
|
||||
assertSame(bf.getBean("testBean"), bean.getTestBean().get());
|
||||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalMethodInjectionWithBeanNotAvailable() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(OptionalMethodInjectionBean.class));
|
||||
|
||||
OptionalMethodInjectionBean bean = (OptionalMethodInjectionBean) bf.getBean("annotatedBean");
|
||||
assertFalse(bean.getTestBean().isPresent());
|
||||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
|
||||
public static class ResourceInjectionBean {
|
||||
|
||||
|
@ -1099,4 +1156,30 @@ public class InjectAnnotationBeanPostProcessorTests {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static class OptionalFieldInjectionBean {
|
||||
|
||||
@Inject
|
||||
private Optional<TestBean> testBean;
|
||||
|
||||
public Optional<TestBean> getTestBean() {
|
||||
return this.testBean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class OptionalMethodInjectionBean {
|
||||
|
||||
private Optional<TestBean> testBean;
|
||||
|
||||
@Inject
|
||||
public void setTestBean(Optional<TestBean> testBeanFactory) {
|
||||
this.testBean = testBeanFactory;
|
||||
}
|
||||
|
||||
public Optional<TestBean> getTestBean() {
|
||||
return this.testBean;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue