question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Changes in bindings cause exception due to unsupported method in collection

See original GitHub issue

Hello everybody,

I just noticed a changed behavior in bindings. The following code works in Spring Boot 1.5.3:

@Component
@ConfigurationProperties(prefix = "foobar")
public class Foobar {

    private Set<String> scope = Collections.emptySet();

    public Set<String> getScope() {
        return scope;
    }

    public void setScope(Collection<String> scope) {
        this.scope = scope == null ? Collections
                .<String>emptySet() : new LinkedHashSet<>(scope);
    }
}

Using properties like

foobar.scope = foo

The code in question is actually not my own, I found it in Spring Security OAuth, inside BaseClientDetails /cc @jgrandja but I wanted to provide a bare example (See oauth-binding-problem.zip)

Prior to Spring Boot 2.0.0.M1 setters seemed to be called and made it work. Now it tries to add to the default collection (which is immutable) and it fails with:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'foobar': Could not bind properties to Foobar (prefix=foobar, ignoreInvalidFields=false, ignoreUnknownFields=true); nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'foobar.scope' to java.util.Collection<java.lang.String>
	at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:340)
	at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:305)
// More...
Caused by: org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'foobar.scope' to java.util.Collection<java.lang.String>
	at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:225)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:200)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$4(Binder.java:298)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:70)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:59)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:51)
	at org.springframework.boot.context.properties.bind.Binder.lambda$null$5(Binder.java:306)
// More...
Caused by: java.lang.UnsupportedOperationException: null
	at java.util.AbstractCollection.add(AbstractCollection.java:262)
	at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
	at org.springframework.boot.context.properties.bind.CollectionBinder.merge(CollectionBinder.java:55)
	at org.springframework.boot.context.properties.bind.CollectionBinder.merge(CollectionBinder.java:31)
	at org.springframework.boot.context.properties.bind.AggregateBinder.bind(AggregateBinder.java:57)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindAggregate$2(Binder.java:273)
	at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:400)
	at org.springframework.boot.context.properties.bind.Binder.bindAggregate(Binder.java:272)
	at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:244)
	at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:196)
	at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$4(Binder.java:298)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:70)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:59)
	at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:51)
	at org.springframework.boot.context.properties.bind.Binder.lambda$null$5(Binder.java:306)

I’m not quite sure what you should do with the info, but I would guess that this can break a lot of projects, as it does with Spring Security OAuth atm.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
philwebbcommented, May 29, 2017

@michael-simons we’ve seen configuration properties like this:

public class Foo {

    public List<Bar> getBar() {
        // ...
    }

}

It’s legitimate to have a no setter so I think that’s why the current code works the way it does. We also don’t know that we can create the appropriate list type (say it’s some funky custom subclass), that’s why we mutate it rather than call the setter. I think we can probably mutate and call the setter if one exists.

1reaction
snicollcommented, May 29, 2017

@mbhave can we please reconsider this fix? Or clearly document the change in behaviour? Regardless of the code, we used to call a setter if present and we don’t anymore which can caught users that were doing some extra stuff in the setter. I am not saying we should support such weird use case but it should be crystal clear that we no longer do that.

If that’s documented already, please ignore me 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Javafx Binding throw exception in application start() method
The implementation of Bindings.bindContent apparently tries to use those unsupported methods when synchronizing the lists. Change this:
Read more >
Troubleshooting Core Data
Problem: You see the error message, " Could not merge changes ." Cause: Two different managed object contexts tried to change the same...
Read more >
Troubleshoot issues when using Azure Functions trigger for ...
This means that the reason that the changes did not arrive at the destination is because that you are failing to process them....
Read more >
UnsupportedOperationException (Java Platform SE 8 )
Constructs a new exception with the specified detail message and cause. Note that the detail message associated with cause is not automatically incorporated...
Read more >
How to Solve Java List UnsupportedOperationException?
The main reason behind the occurrence of this error is the asList method of java.util.Arrays class returns an object of an ArrayList which...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found