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:
Juergen Hoeller
2014-06-06 15:29:50 +02:00
parent 7d03daf8cb
commit 5cb3f8eada
4 changed files with 148 additions and 52 deletions

View File

@@ -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;
}

View File

@@ -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));
}
}
}