DefaultListableBeanFactory checks for pre-converted Optional wrappers
Issue: SPR-17607
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -1594,7 +1594,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dependency descriptor marker for multiple elements.
|
* A dependency descriptor for a multi-element declaration with nested elements.
|
||||||
*/
|
*/
|
||||||
private static class MultiElementDescriptor extends NestedDependencyDescriptor {
|
private static class MultiElementDescriptor extends NestedDependencyDescriptor {
|
||||||
|
|
||||||
@@ -1622,7 +1622,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
super.resolveCandidate(beanName, requiredType, beanFactory));
|
super.resolveCandidate(beanName, requiredType, beanFactory));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return Optional.ofNullable(doResolveDependency(descriptorToUse, beanName, null, null));
|
Object result = doResolveDependency(descriptorToUse, beanName, null, null);
|
||||||
|
return (result instanceof Optional ? (Optional<?>) result : Optional.ofNullable(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -25,6 +25,7 @@ import java.net.URI;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.AccessControlException;
|
import java.security.AccessControlException;
|
||||||
import java.security.Permission;
|
import java.security.Permission;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
@@ -45,7 +46,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
|||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.support.DefaultConversionService;
|
||||||
import org.springframework.core.convert.support.GenericConversionService;
|
import org.springframework.core.convert.support.GenericConversionService;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
@@ -61,6 +62,7 @@ import static org.junit.Assert.*;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
* @author Sam Brannen
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class ApplicationContextExpressionTests {
|
public class ApplicationContextExpressionTests {
|
||||||
@@ -100,6 +102,8 @@ public class ApplicationContextExpressionTests {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ac.getBeanFactory().setConversionService(new DefaultConversionService());
|
||||||
|
|
||||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||||
Properties placeholders = new Properties();
|
Properties placeholders = new Properties();
|
||||||
placeholders.setProperty("code", "123");
|
placeholders.setProperty("code", "123");
|
||||||
@@ -174,6 +178,9 @@ public class ApplicationContextExpressionTests {
|
|||||||
System.getProperties().put("country", "UK");
|
System.getProperties().put("country", "UK");
|
||||||
assertEquals("123 UK", tb3.country);
|
assertEquals("123 UK", tb3.country);
|
||||||
assertEquals("123 UK", tb3.countryFactory.getObject());
|
assertEquals("123 UK", tb3.countryFactory.getObject());
|
||||||
|
assertEquals("123", tb3.optionalValue1.get());
|
||||||
|
assertEquals("123", tb3.optionalValue2.get());
|
||||||
|
assertFalse(tb3.optionalValue3.isPresent());
|
||||||
assertSame(tb0, tb3.tb);
|
assertSame(tb0, tb3.tb);
|
||||||
|
|
||||||
tb3 = (ValueTestBean) SerializationTestUtils.serializeAndDeserialize(tb3);
|
tb3 = (ValueTestBean) SerializationTestUtils.serializeAndDeserialize(tb3);
|
||||||
@@ -207,12 +214,7 @@ public class ApplicationContextExpressionTests {
|
|||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
GenericApplicationContext ac = new GenericApplicationContext();
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
|
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
|
||||||
GenericConversionService cs = new GenericConversionService();
|
GenericConversionService cs = new GenericConversionService();
|
||||||
cs.addConverter(String.class, String.class, new Converter<String, String>() {
|
cs.addConverter(String.class, String.class, String::trim);
|
||||||
@Override
|
|
||||||
public String convert(String source) {
|
|
||||||
return source.trim();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ac.getBeanFactory().registerSingleton(GenericApplicationContext.CONVERSION_SERVICE_BEAN_NAME, cs);
|
ac.getBeanFactory().registerSingleton(GenericApplicationContext.CONVERSION_SERVICE_BEAN_NAME, cs);
|
||||||
RootBeanDefinition rbd = new RootBeanDefinition(PrototypeTestBean.class);
|
RootBeanDefinition rbd = new RootBeanDefinition(PrototypeTestBean.class);
|
||||||
rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||||
@@ -274,8 +276,7 @@ public class ApplicationContextExpressionTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void systemPropertiesSecurityManager() {
|
public void systemPropertiesSecurityManager() {
|
||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
|
|
||||||
|
|
||||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||||
bd.setBeanClass(TestBean.class);
|
bd.setBeanClass(TestBean.class);
|
||||||
@@ -311,8 +312,7 @@ public class ApplicationContextExpressionTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void stringConcatenationWithDebugLogging() {
|
public void stringConcatenationWithDebugLogging() {
|
||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
|
|
||||||
|
|
||||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||||
bd.setBeanClass(String.class);
|
bd.setBeanClass(String.class);
|
||||||
@@ -326,11 +326,10 @@ public class ApplicationContextExpressionTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resourceInjection() throws IOException {
|
public void resourceInjection() throws IOException {
|
||||||
System.setProperty("logfile", "log4j.properties");
|
System.setProperty("logfile", "do_not_delete_me.txt");
|
||||||
try {
|
try (AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ResourceInjectionBean.class)) {
|
||||||
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ResourceInjectionBean.class);
|
|
||||||
ResourceInjectionBean resourceInjectionBean = ac.getBean(ResourceInjectionBean.class);
|
ResourceInjectionBean resourceInjectionBean = ac.getBean(ResourceInjectionBean.class);
|
||||||
Resource resource = new ClassPathResource("log4j.properties");
|
Resource resource = new ClassPathResource("do_not_delete_me.txt");
|
||||||
assertEquals(resource, resourceInjectionBean.resource);
|
assertEquals(resource, resourceInjectionBean.resource);
|
||||||
assertEquals(resource.getURL(), resourceInjectionBean.url);
|
assertEquals(resource.getURL(), resourceInjectionBean.url);
|
||||||
assertEquals(resource.getURI(), resourceInjectionBean.uri);
|
assertEquals(resource.getURI(), resourceInjectionBean.uri);
|
||||||
@@ -364,6 +363,15 @@ public class ApplicationContextExpressionTests {
|
|||||||
@Value("${code} #{systemProperties.country}")
|
@Value("${code} #{systemProperties.country}")
|
||||||
public ObjectFactory<String> countryFactory;
|
public ObjectFactory<String> countryFactory;
|
||||||
|
|
||||||
|
@Value("${code}")
|
||||||
|
private transient Optional<String> optionalValue1;
|
||||||
|
|
||||||
|
@Value("${code:#{null}}")
|
||||||
|
private transient Optional<String> optionalValue2;
|
||||||
|
|
||||||
|
@Value("${codeX:#{null}}")
|
||||||
|
private transient Optional<String> optionalValue3;
|
||||||
|
|
||||||
@Autowired @Qualifier("original")
|
@Autowired @Qualifier("original")
|
||||||
public transient TestBean tb;
|
public transient TestBean tb;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -83,7 +83,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public TypeDescriptor(MethodParameter methodParameter) {
|
public TypeDescriptor(MethodParameter methodParameter) {
|
||||||
this.resolvableType = ResolvableType.forMethodParameter(methodParameter);
|
this.resolvableType = ResolvableType.forMethodParameter(methodParameter);
|
||||||
this.type = this.resolvableType.resolve(methodParameter.getParameterType());
|
this.type = this.resolvableType.resolve(methodParameter.getNestedParameterType());
|
||||||
this.annotatedElement = new AnnotatedElementAdapter(methodParameter.getParameterIndex() == -1 ?
|
this.annotatedElement = new AnnotatedElementAdapter(methodParameter.getParameterIndex() == -1 ?
|
||||||
methodParameter.getMethodAnnotations() : methodParameter.getParameterAnnotations());
|
methodParameter.getMethodAnnotations() : methodParameter.getParameterAnnotations());
|
||||||
}
|
}
|
||||||
@@ -607,7 +607,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a type descriptor for a nested type declared within the method parameter.
|
* Create a type descriptor for a nested type declared within the method parameter.
|
||||||
* <p>For example, if the methodParameter is a {@code List<String>} and the
|
* <p>For example, if the methodParameter is a {@code List<String>} and the
|
||||||
* nesting level is 1, the nested type descriptor will be String.class.
|
* nesting level is 1, the nested type descriptor will be String.class.
|
||||||
* <p>If the methodParameter is a {@code List<List<String>>} and the nesting
|
* <p>If the methodParameter is a {@code List<List<String>>} and the nesting
|
||||||
@@ -637,7 +637,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a type descriptor for a nested type declared within the field.
|
* Create a type descriptor for a nested type declared within the field.
|
||||||
* <p>For example, if the field is a {@code List<String>} and the nesting
|
* <p>For example, if the field is a {@code List<String>} and the nesting
|
||||||
* level is 1, the nested type descriptor will be {@code String.class}.
|
* level is 1, the nested type descriptor will be {@code String.class}.
|
||||||
* <p>If the field is a {@code List<List<String>>} and the nesting level is
|
* <p>If the field is a {@code List<List<String>>} and the nesting level is
|
||||||
@@ -646,8 +646,9 @@ public class TypeDescriptor implements Serializable {
|
|||||||
* is 1, the nested type descriptor will be String, derived from the map value.
|
* is 1, the nested type descriptor will be String, derived from the map value.
|
||||||
* <p>If the field is a {@code List<Map<Integer, String>>} and the nesting
|
* <p>If the field is a {@code List<Map<Integer, String>>} and the nesting
|
||||||
* level is 2, the nested type descriptor will be String, derived from the map value.
|
* level is 2, the nested type descriptor will be String, derived from the map value.
|
||||||
* <p>Returns {@code null} if a nested type cannot be obtained because it was not declared.
|
* <p>Returns {@code null} if a nested type cannot be obtained because it was not
|
||||||
* For example, if the field is a {@code List<?>}, the nested type descriptor returned will be {@code null}.
|
* declared. For example, if the field is a {@code List<?>}, the nested type
|
||||||
|
* descriptor returned will be {@code null}.
|
||||||
* @param field the field
|
* @param field the field
|
||||||
* @param nestingLevel the nesting level of the collection/array element or
|
* @param nestingLevel the nesting level of the collection/array element or
|
||||||
* map key/value declaration within the field
|
* map key/value declaration within the field
|
||||||
@@ -661,7 +662,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a type descriptor for a nested type declared within the property.
|
* Create a type descriptor for a nested type declared within the property.
|
||||||
* <p>For example, if the property is a {@code List<String>} and the nesting
|
* <p>For example, if the property is a {@code List<String>} and the nesting
|
||||||
* level is 1, the nested type descriptor will be {@code String.class}.
|
* level is 1, the nested type descriptor will be {@code String.class}.
|
||||||
* <p>If the property is a {@code List<List<String>>} and the nesting level
|
* <p>If the property is a {@code List<List<String>>} and the nesting level
|
||||||
@@ -670,9 +671,9 @@ public class TypeDescriptor implements Serializable {
|
|||||||
* is 1, the nested type descriptor will be String, derived from the map value.
|
* is 1, the nested type descriptor will be String, derived from the map value.
|
||||||
* <p>If the property is a {@code List<Map<Integer, String>>} and the nesting
|
* <p>If the property is a {@code List<Map<Integer, String>>} and the nesting
|
||||||
* level is 2, the nested type descriptor will be String, derived from the map value.
|
* level is 2, the nested type descriptor will be String, derived from the map value.
|
||||||
* <p>Returns {@code null} if a nested type cannot be obtained because it was not declared.
|
* <p>Returns {@code null} if a nested type cannot be obtained because it was not
|
||||||
* For example, if the property is a {@code List<?>}, the nested type descriptor
|
* declared. For example, if the property is a {@code List<?>}, the nested type
|
||||||
* returned will be {@code null}.
|
* descriptor returned will be {@code null}.
|
||||||
* @param property the property
|
* @param property the property
|
||||||
* @param nestingLevel the nesting level of the collection/array element or
|
* @param nestingLevel the nesting level of the collection/array element or
|
||||||
* map key/value declaration within the property
|
* map key/value declaration within the property
|
||||||
|
|||||||
Reference in New Issue
Block a user