Skip to content

Commit 183f367

Browse files
committed
DefaultListableBeanFactory checks for pre-converted Optional wrappers
Issue: SPR-17607
1 parent 15f255a commit 183f367

File tree

3 files changed

+35
-26
lines changed

3 files changed

+35
-26
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -1549,7 +1549,8 @@ public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFacto
15491549
super.resolveCandidate(beanName, requiredType, beanFactory));
15501550
}
15511551
};
1552-
return Optional.ofNullable(doResolveDependency(descriptorToUse, beanName, null, null));
1552+
Object result = doResolveDependency(descriptorToUse, beanName, null, null);
1553+
return (result instanceof Optional ? (Optional<?>) result : Optional.ofNullable(result));
15531554
}
15541555

15551556

@@ -1630,7 +1631,7 @@ public NestedDependencyDescriptor(DependencyDescriptor original) {
16301631

16311632

16321633
/**
1633-
* A dependency descriptor marker for multiple elements.
1634+
* A dependency descriptor for a multi-element declaration with nested elements.
16341635
*/
16351636
private static class MultiElementDescriptor extends NestedDependencyDescriptor {
16361637

spring-context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,11 +25,11 @@
2525
import java.net.URL;
2626
import java.security.AccessControlException;
2727
import java.security.Permission;
28+
import java.util.Optional;
2829
import java.util.Properties;
2930

3031
import org.apache.commons.logging.Log;
3132
import org.apache.commons.logging.LogFactory;
32-
3333
import org.junit.Test;
3434

3535
import org.springframework.beans.factory.ObjectFactory;
@@ -46,7 +46,7 @@
4646
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
4747
import org.springframework.context.annotation.AnnotationConfigUtils;
4848
import org.springframework.context.support.GenericApplicationContext;
49-
import org.springframework.core.convert.converter.Converter;
49+
import org.springframework.core.convert.support.DefaultConversionService;
5050
import org.springframework.core.convert.support.GenericConversionService;
5151
import org.springframework.core.io.ClassPathResource;
5252
import org.springframework.core.io.Resource;
@@ -102,6 +102,8 @@ public String getConversationId() {
102102
}
103103
});
104104

105+
ac.getBeanFactory().setConversionService(new DefaultConversionService());
106+
105107
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
106108
Properties placeholders = new Properties();
107109
placeholders.setProperty("code", "123");
@@ -176,6 +178,9 @@ public String getConversationId() {
176178
System.getProperties().put("country", "UK");
177179
assertEquals("123 UK", tb3.country);
178180
assertEquals("123 UK", tb3.countryFactory.getObject());
181+
assertEquals("123", tb3.optionalValue1.get());
182+
assertEquals("123", tb3.optionalValue2.get());
183+
assertFalse(tb3.optionalValue3.isPresent());
179184
assertSame(tb0, tb3.tb);
180185

181186
tb3 = (ValueTestBean) SerializationTestUtils.serializeAndDeserialize(tb3);
@@ -209,12 +214,7 @@ public void prototypeCreationReevaluatesExpressions() {
209214
GenericApplicationContext ac = new GenericApplicationContext();
210215
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
211216
GenericConversionService cs = new GenericConversionService();
212-
cs.addConverter(String.class, String.class, new Converter<String, String>() {
213-
@Override
214-
public String convert(String source) {
215-
return source.trim();
216-
}
217-
});
217+
cs.addConverter(String.class, String.class, String::trim);
218218
ac.getBeanFactory().registerSingleton(GenericApplicationContext.CONVERSION_SERVICE_BEAN_NAME, cs);
219219
RootBeanDefinition rbd = new RootBeanDefinition(PrototypeTestBean.class);
220220
rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
@@ -276,8 +276,7 @@ public void prototypeCreationIsFastEnough() {
276276

277277
@Test
278278
public void systemPropertiesSecurityManager() {
279-
GenericApplicationContext ac = new GenericApplicationContext();
280-
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
279+
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
281280

282281
GenericBeanDefinition bd = new GenericBeanDefinition();
283282
bd.setBeanClass(TestBean.class);
@@ -313,8 +312,7 @@ public void checkPermission(Permission perm) {
313312

314313
@Test
315314
public void stringConcatenationWithDebugLogging() {
316-
GenericApplicationContext ac = new GenericApplicationContext();
317-
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
315+
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
318316

319317
GenericBeanDefinition bd = new GenericBeanDefinition();
320318
bd.setBeanClass(String.class);
@@ -365,6 +363,15 @@ public static class ValueTestBean implements Serializable {
365363
@Value("${code} #{systemProperties.country}")
366364
public ObjectFactory<String> countryFactory;
367365

366+
@Value("${code}")
367+
private transient Optional<String> optionalValue1;
368+
369+
@Value("${code:#{null}}")
370+
private transient Optional<String> optionalValue2;
371+
372+
@Value("${codeX:#{null}}")
373+
private transient Optional<String> optionalValue3;
374+
368375
@Autowired @Qualifier("original")
369376
public transient TestBean tb;
370377
}

spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -80,7 +80,7 @@ public class TypeDescriptor implements Serializable {
8080
*/
8181
public TypeDescriptor(MethodParameter methodParameter) {
8282
this.resolvableType = ResolvableType.forMethodParameter(methodParameter);
83-
this.type = this.resolvableType.resolve(methodParameter.getParameterType());
83+
this.type = this.resolvableType.resolve(methodParameter.getNestedParameterType());
8484
this.annotatedElement = new AnnotatedElementAdapter(methodParameter.getParameterIndex() == -1 ?
8585
methodParameter.getMethodAnnotations() : methodParameter.getParameterAnnotations());
8686
}
@@ -616,7 +616,7 @@ public static TypeDescriptor array(@Nullable TypeDescriptor elementTypeDescripto
616616
}
617617

618618
/**
619-
* Creates a type descriptor for a nested type declared within the method parameter.
619+
* Create a type descriptor for a nested type declared within the method parameter.
620620
* <p>For example, if the methodParameter is a {@code List<String>} and the
621621
* nesting level is 1, the nested type descriptor will be String.class.
622622
* <p>If the methodParameter is a {@code List<List<String>>} and the nesting
@@ -647,7 +647,7 @@ public static TypeDescriptor nested(MethodParameter methodParameter, int nesting
647647
}
648648

649649
/**
650-
* Creates a type descriptor for a nested type declared within the field.
650+
* Create a type descriptor for a nested type declared within the field.
651651
* <p>For example, if the field is a {@code List<String>} and the nesting
652652
* level is 1, the nested type descriptor will be {@code String.class}.
653653
* <p>If the field is a {@code List<List<String>>} and the nesting level is
@@ -656,8 +656,9 @@ public static TypeDescriptor nested(MethodParameter methodParameter, int nesting
656656
* is 1, the nested type descriptor will be String, derived from the map value.
657657
* <p>If the field is a {@code List<Map<Integer, String>>} and the nesting
658658
* level is 2, the nested type descriptor will be String, derived from the map value.
659-
* <p>Returns {@code null} if a nested type cannot be obtained because it was not declared.
660-
* For example, if the field is a {@code List<?>}, the nested type descriptor returned will be {@code null}.
659+
* <p>Returns {@code null} if a nested type cannot be obtained because it was not
660+
* declared. For example, if the field is a {@code List<?>}, the nested type
661+
* descriptor returned will be {@code null}.
661662
* @param field the field
662663
* @param nestingLevel the nesting level of the collection/array element or
663664
* map key/value declaration within the field
@@ -672,7 +673,7 @@ public static TypeDescriptor nested(Field field, int nestingLevel) {
672673
}
673674

674675
/**
675-
* Creates a type descriptor for a nested type declared within the property.
676+
* Create a type descriptor for a nested type declared within the property.
676677
* <p>For example, if the property is a {@code List<String>} and the nesting
677678
* level is 1, the nested type descriptor will be {@code String.class}.
678679
* <p>If the property is a {@code List<List<String>>} and the nesting level
@@ -681,9 +682,9 @@ public static TypeDescriptor nested(Field field, int nestingLevel) {
681682
* is 1, the nested type descriptor will be String, derived from the map value.
682683
* <p>If the property is a {@code List<Map<Integer, String>>} and the nesting
683684
* level is 2, the nested type descriptor will be String, derived from the map value.
684-
* <p>Returns {@code null} if a nested type cannot be obtained because it was not declared.
685-
* For example, if the property is a {@code List<?>}, the nested type descriptor
686-
* returned will be {@code null}.
685+
* <p>Returns {@code null} if a nested type cannot be obtained because it was not
686+
* declared. For example, if the property is a {@code List<?>}, the nested type
687+
* descriptor returned will be {@code null}.
687688
* @param property the property
688689
* @param nestingLevel the nesting level of the collection/array element or
689690
* map key/value declaration within the property

0 commit comments

Comments
 (0)