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.

Comment From: philwebb

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.

Comment From: quaff

Please edit code to remove links, for example [bar.foos.alice.name](http://bar.foos.alice.name/)=alice should be bar.foos.alice.name=alice.

Comment From: quaff

Please edit code to remove links, for example [bar.foos.alice.name](http://bar.foos.alice.name/)=alice should be bar.foos.alice.name=alice.

@philwebb The confusing parts in @SpringBootTest(properties) is not edited.

Comment From: philwebb

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.

Comment From: philwebb

41830 is a similar problem related to merging items.