Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to define empty java.util.Optional bean in spring xml [SPR-14121] #18693

Closed
spring-issuemaster opened this issue Apr 5, 2016 · 1 comment
Closed
Assignees
Milestone

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented Apr 5, 2016

Yibo Wang opened SPR-14121 and commented

A bean who refers to an empty java.util.Optional value cannot be created with Spring configuration xml.

In Spring config xml file I have:

<bean id="emptyOptional" class="java.util.Optional" factory-method="empty"/>

Then when the Spring config was loaded, it reported the following error:

 [junit] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'emptyOptional' defined in URL [file:configuration/spring-configuration/components/observers.xml]: Bean instantiation via factory method failed; nested exception is java.lang.IllegalArgumentException: Optional value must be present
[junit]     at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
[junit]     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
[junit]     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
[junit]     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
[junit]     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
[junit]     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
[junit]     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
[junit]     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
[junit]     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
[junit]     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
[junit]     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
[junit]     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
[junit]     at com.amazon.gpi.componentTesting.ComponentTestContext.createContext(ComponentTestContext.java:140)
[junit]     at com.amazon.gpi.componentTesting.ComponentTestContext.<init>(ComponentTestContext.java:117)
[junit]     at com.amazon.gpi.componentTesting.ComponentTestContext.fromProfile(ComponentTestContext.java:59)
[junit]     at com.amazon.gpi.componentTesting.TestProfileRunner.<init>(TestProfileRunner.java:130)
[junit]     at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
[junit]     at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
[junit] Caused by: java.lang.IllegalArgumentException: Optional value must be present
[junit]     at org.springframework.util.Assert.isTrue(Assert.java:68)
[junit]     at org.springframework.beans.AbstractNestablePropertyAccessor$OptionalUnwrapper.unwrap(AbstractNestablePropertyAccessor.java:1049)
[junit]     at org.springframework.beans.AbstractNestablePropertyAccessor.setWrappedInstance(AbstractNestablePropertyAccessor.java:207)
[junit]     at org.springframework.beans.BeanWrapperImpl.setWrappedInstance(BeanWrapperImpl.java:138)
[junit]     at org.springframework.beans.AbstractNestablePropertyAccessor.setWrappedInstance(AbstractNestablePropertyAccessor.java:194)
[junit]     at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:595)

Looks like spring tried to extract the nested value of the Optional class and use that to assign to the bean which was not what I intended. (What I tried to do was to have both empty Optional and present Optional and later conditionally choose to use one of them. So if spring did not extract the nested value, it would just work (like if the Optional is from Guava.))

Thanks


Affects: 4.2.4

Issue Links:

  • #16855 Data binding with java.util.Optional: traversal of nested paths, detection of empty holders
  • #19043 NPE while try to use abstract beans with optional properties

Referenced from: commits 0864834, 5c1d3fc, 157dcab

@spring-issuemaster
Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Apr 7, 2016

Juergen Hoeller commented

I've cleaned this up through avoiding java.util.Optional unwrapping for factory-created beans completely, since that code path was only really meant to be used for data binding and nested properties in particular. It is a little unusual to create top-level beans of type Optional, but if we encounter that, we should just preserve that original bean class and not try to smartly unwrap it in such a container context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.