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

Cannot initialize a map inside @ConfigurationProperties #43352

Open
dsyer opened this issue Dec 2, 2024 · 5 comments
Open

Cannot initialize a map inside @ConfigurationProperties #43352

dsyer opened this issue Dec 2, 2024 · 5 comments
Labels
status: pending-design-work Needs design work before any code can be developed type: enhancement A general enhancement
Milestone

Comments

@dsyer
Copy link
Member

dsyer commented Dec 2, 2024

This fails

@SpringBootTest(properties = { "bar.foos.alice.name=alice", "bar.foos.alice.age=20",
        "bar.foos.bob.age=21" }, classes = PropertiesTests.Bar.class)
public class PropertiesTests {

    @Autowired
    private Bar bar;

    @Test
    public void test() {
        assertThat(bar.getFoos().get("alice").getAge()).isEqualTo(20);
        assertThat(bar.getFoos().get("alice").getName()).isEqualTo("alice");
        assertThat(bar.getFoos().get("bob").getAge()).isEqualTo(21);
        assertThat(bar.getFoos().get("bob").getName()).isEqualTo("bob");
    }

    @TestConfiguration
    @ConfigurationProperties("bar")
    static class Bar {
        private Map<String, Foo> foos = new HashMap<>(Map.of("bob", new Foo("bob")));

        public Map<String, Foo> getFoos() {
            return foos;
        }
    }

    static class Foo {
        private String name;
        private int age;

        Foo() {
        }

        public Foo(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

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

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}

Bob’s name is null.

It means you can't initialize a map if you are going to bind to it as well (there's no point as it will just get overwritten). That seems like a bug to me.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Dec 2, 2024
@philwebb
Copy link
Member

philwebb commented Dec 2, 2024

For a little more background, the MapBinder class currently only creates new elements to put into the map, it doesn't mutate existing elements. I'm pretty sure that was an intentional decision when we designed the new code, but the exact reason escapes me. It might have been to ensure that a put always gets called, or it may be that we were worried that a Map would contain values from multiple places and it's better to fully replace them.

It is inconsistent with the regular JavaBeanBinder where we do allow such patterns.

I think if we fix this, it will have to be in 3.5 because of the risk that we'll break existing code.

@philwebb philwebb added the for: team-meeting An issue we'd like to discuss as a team to make progress label Dec 2, 2024
@quaff

This comment was marked as resolved.

@philwebb philwebb added the status: pending-design-work Needs design work before any code can be developed label Dec 3, 2024
@quaff

This comment has been minimized.

dsyer added a commit to spring-projects-experimental/spring-grpc that referenced this issue Dec 4, 2024
Because of spring-projects/spring-boot#43352
there's no point having a "default" entry in the channels map.
@philwebb
Copy link
Member

philwebb commented Dec 4, 2024

We discussed this today and we'd like to change the behavior, but we're worried that folks might be relying on the existing way things work.

We're specifically concerned that someone may declare a @ConfigurationProperties with a Map containing some defaults and expect that if a user provides any property with the same map key, all the defaults for that key are replaced by the user properties.

We probably need to find a way to support that use-case. Perhaps a new annotation.

@philwebb
Copy link
Member

philwebb commented Dec 4, 2024

#41830 is a similar problem related to merging items.

@philwebb philwebb added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged for: team-meeting An issue we'd like to discuss as a team to make progress labels Dec 4, 2024
@philwebb philwebb added this to the 3.x milestone Dec 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: pending-design-work Needs design work before any code can be developed type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants