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

Constructor binding can fail with non iterable property sources #17098

Closed
kazuki43zoo opened this issue Jun 10, 2019 · 3 comments
Closed

Constructor binding can fail with non iterable property sources #17098

kazuki43zoo opened this issue Jun 10, 2019 · 3 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@kazuki43zoo
Copy link
Contributor

kazuki43zoo commented Jun 10, 2019

The constructor binding feature is very cool. But there are cases that does not work fine when integrating 3rd party configuration class and it deploy to the application server as war file(= When JndiPropertySource is enabled).

Versions

  • 2.2.0.M3 and snapshot version
  • Tomcat 9.0.20

Details

For example, following properties class does not work.

@ConfigurationProperties(prefix = "my")
public class MyProperties {

  private String name;

  @NestedConfigurationProperty
  private ThirdPartyConfiguration configuration; // Third party class

  public void setName(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public void setConfiguration(ThirdPartyConfiguration configuration) {
    this.configuration = configuration;
  }

  public ThirdPartyConfiguration getConfiguration() {
    return configuration;
  }

}
public class ThirdPartyConfiguration {

  private String encoding;

  private boolean enabled;

  private final List<Attribute> attributes = new ArrayList<>();

  public void setEncoding(String encoding) {
    this.encoding = encoding;
  }

  public String getEncoding() {
    return encoding;
  }

  public void setEnabled(boolean enabled) {
    this.enabled = enabled;
  }

  public boolean isEnabled() {
    return enabled;
  }

  public void addAttribute(Attribute attribute) {
    this.attributes.add(attribute);
  }

  public List<Attribute> getAttributes() {
    return attributes;
  }

  public static class Attribute {

    private final String name;
    private final Object value;

    public Attribute(String name, Object value) {
      Objects.requireNonNull(name, "'name' must be not null.");
      Objects.requireNonNull(value, "'value' must be not null.");
      this.name = name;
      this.value = value;
    }

    public String getName() {
      return name;
    }

    public Object getValue() {
      return value;
    }

  }

}
  • application.properties
# empty

Stacktrace

...
Caused by: org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'my.configuration.attributes[0]' to com.example.springbootstartergh350.ThirdPartyConfiguration$Attribute
	at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:243)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:219)
	at org.springframework.boot.context.properties.bind.Binder.lambda$null$0(Binder.java:291)
	at org.springframework.boot.context.properties.bind.Binder$Context.withSource(Binder.java:406)
	at org.springframework.boot.context.properties.bind.Binder$Context.access$1000(Binder.java:373)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindAggregate$1(Binder.java:292)
	at org.springframework.boot.context.properties.bind.IndexedElementsBinder.bindIndexed(IndexedElementsBinder.java:106)
	at org.springframework.boot.context.properties.bind.IndexedElementsBinder.bindIndexed(IndexedElementsBinder.java:86)
	at org.springframework.boot.context.properties.bind.IndexedElementsBinder.bindIndexed(IndexedElementsBinder.java:71)
	at org.springframework.boot.context.properties.bind.CollectionBinder.bindAggregate(CollectionBinder.java:49)
	at org.springframework.boot.context.properties.bind.AggregateBinder.bind(AggregateBinder.java:56)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindAggregate$2(Binder.java:294)
	at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:430)
	at org.springframework.boot.context.properties.bind.Binder$Context.access$200(Binder.java:373)
	at org.springframework.boot.context.properties.bind.Binder.bindAggregate(Binder.java:294)
	at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:255)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:215)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$3(Binder.java:327)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:80)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:70)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:54)
	at org.springframework.boot.context.properties.bind.Binder.lambda$null$4(Binder.java:330)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1359)
	at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
	at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$5(Binder.java:331)
	at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:430)
	at org.springframework.boot.context.properties.bind.Binder$Context.withBean(Binder.java:416)
	at org.springframework.boot.context.properties.bind.Binder$Context.access$500(Binder.java:373)
	at org.springframework.boot.context.properties.bind.Binder.bindBean(Binder.java:329)
	at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:270)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:215)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$3(Binder.java:327)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:80)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:70)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:54)
	at org.springframework.boot.context.properties.bind.Binder.lambda$null$4(Binder.java:330)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1359)
	at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
	at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$5(Binder.java:331)
	at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:430)
	at org.springframework.boot.context.properties.bind.Binder$Context.withBean(Binder.java:416)
	at org.springframework.boot.context.properties.bind.Binder$Context.access$500(Binder.java:373)
	at org.springframework.boot.context.properties.bind.Binder.bindBean(Binder.java:329)
	at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:270)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:215)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:203)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:186)
	at org.springframework.boot.context.properties.ConfigurationPropertiesBinder.bind(ConfigurationPropertiesBinder.java:93)
	at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:115)
	... 66 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.springbootstartergh350.ThirdPartyConfiguration$Attribute]: Constructor threw exception; nested exception is java.lang.NullPointerException: 'name' is not null.
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:213)
	at org.springframework.boot.context.properties.bind.ConstructorParametersBinder.bind(ConstructorParametersBinder.java:60)
	at org.springframework.boot.context.properties.bind.Binder.lambda$null$4(Binder.java:330)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1359)
	at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
	at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$5(Binder.java:331)
	at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:430)
[2019-06-11 03:48:48,181] Artifact spring-boot-starter-gh-350:war: Error during artifact deployment. See server log for details.
	at org.springframework.boot.context.properties.bind.Binder$Context.withBean(Binder.java:416)
	at org.springframework.boot.context.properties.bind.Binder$Context.access$500(Binder.java:373)
	at org.springframework.boot.context.properties.bind.Binder.bindBean(Binder.java:329)
	at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:270)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:215)
	... 127 more
Caused by: java.lang.NullPointerException: 'name' must be not null.
	at java.util.Objects.requireNonNull(Objects.java:228)
	at com.example.springbootstartergh350.ThirdPartyConfiguration$Attribute.<init>(ThirdPartyConfiguration.java:47)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:200)
	... 145 more

Repro project

spring-boot-gh-17098-master.zip

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 10, 2019
@kazuki43zoo
Copy link
Contributor Author

I've added repro project. This issue can reproduce using cargo plugin as follow:

$ ./mvnw package cargo:run

@mbhave mbhave added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 10, 2019
@mbhave mbhave added this to the 2.2.x milestone Jun 10, 2019
@mbhave mbhave self-assigned this Jun 10, 2019
@mbhave mbhave changed the title There is case that fail constructor binding on war deploy Constructor binding can fail with non iterable property sources Jun 13, 2019
@philwebb philwebb modified the milestones: 2.2.x, 2.2.0.M4 Jun 15, 2019
@philwebb philwebb self-assigned this Jun 15, 2019
@kazuki43zoo
Copy link
Contributor Author

@philwebb Thanks for fix! I've confirmed to fix this issue on 2.2.0M4.

@philwebb
Copy link
Member

@kazuki43zoo Actually @mbhave fixed it, I just did the merge. Thanks for testing M4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants