Support for java.util.Optional within ObjectFactory/Provider
Includes support for arbitrary deep nesting levels in DependencyDescriptor's getDependencyType() and MethodParameter's getNestedParameterType(). Issue: SPR-11833
This commit is contained in:
@@ -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.
|
||||
@@ -263,18 +263,20 @@ public class DependencyDescriptor implements Serializable {
|
||||
if (this.field != null) {
|
||||
if (this.nestingLevel > 1) {
|
||||
Type type = this.field.getGenericType();
|
||||
if (type instanceof ParameterizedType) {
|
||||
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
|
||||
Type arg = args[args.length - 1];
|
||||
for (int i = 2; i <= this.nestingLevel; i++) {
|
||||
if (type instanceof ParameterizedType) {
|
||||
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
|
||||
type = args[args.length - 1];
|
||||
}
|
||||
}
|
||||
if (type instanceof Class) {
|
||||
return (Class<?>) type;
|
||||
}
|
||||
else if (type instanceof ParameterizedType) {
|
||||
Type arg = ((ParameterizedType) type).getRawType();
|
||||
if (arg instanceof Class) {
|
||||
return (Class<?>) arg;
|
||||
}
|
||||
else if (arg instanceof ParameterizedType) {
|
||||
arg = ((ParameterizedType) arg).getRawType();
|
||||
if (arg instanceof Class) {
|
||||
return (Class<?>) arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.OrderProviderComparator;
|
||||
import org.springframework.core.annotation.OrderUtils;
|
||||
import org.springframework.lang.UsesJava8;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -107,18 +108,11 @@ import org.springframework.util.StringUtils;
|
||||
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
|
||||
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
|
||||
|
||||
private static Class<?> javaxInjectProviderClass = null;
|
||||
|
||||
private static Class<?> javaUtilOptionalClass = null;
|
||||
|
||||
private static Class<?> javaxInjectProviderClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
javaxInjectProviderClass =
|
||||
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - Provider interface simply not supported then.
|
||||
}
|
||||
try {
|
||||
javaUtilOptionalClass =
|
||||
ClassUtils.forName("java.util.Optional", DefaultListableBeanFactory.class.getClassLoader());
|
||||
@@ -126,6 +120,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Java 8 not available - Optional references simply not supported then.
|
||||
}
|
||||
try {
|
||||
javaxInjectProviderClass =
|
||||
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - Provider interface simply not supported then.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -858,15 +859,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
|
||||
|
||||
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
|
||||
if (descriptor.getDependencyType().equals(ObjectFactory.class)) {
|
||||
if (descriptor.getDependencyType().equals(javaUtilOptionalClass)) {
|
||||
return new OptionalDependencyFactory().createOptionalDependency(descriptor, beanName);
|
||||
}
|
||||
else if (descriptor.getDependencyType().equals(ObjectFactory.class)) {
|
||||
return new DependencyObjectFactory(descriptor, beanName);
|
||||
}
|
||||
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) {
|
||||
@@ -1284,6 +1285,25 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Separate inner class for avoiding a hard dependency on the {@code javax.inject} API.
|
||||
*/
|
||||
@UsesJava8
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializable ObjectFactory for lazy resolution of a dependency.
|
||||
*/
|
||||
@@ -1291,17 +1311,25 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
|
||||
private final DependencyDescriptor descriptor;
|
||||
|
||||
private final boolean optional;
|
||||
|
||||
private final String beanName;
|
||||
|
||||
public DependencyObjectFactory(DependencyDescriptor descriptor, String beanName) {
|
||||
this.descriptor = new DependencyDescriptor(descriptor);
|
||||
this.descriptor.increaseNestingLevel();
|
||||
this.optional = this.descriptor.getDependencyType().equals(javaUtilOptionalClass);
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() throws BeansException {
|
||||
return doResolveDependency(this.descriptor, this.beanName, null, null);
|
||||
if (this.optional) {
|
||||
return new OptionalDependencyFactory().createOptionalDependency(this.descriptor, this.beanName);
|
||||
}
|
||||
else {
|
||||
return doResolveDependency(this.descriptor, this.beanName, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1332,22 +1360,4 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user