2

Given a @Value.Immutable-annotated class that contains a collection of immutable objects, what is the most elegant way to create a new copy, where the child objects are modified?

For example, given a company with employees, if I want to set all employee names to uppercase, is this the correct approach, or is there a simpler one?

Company c1 = ImmutableCompany.builder()
    .name("ACME")
    .addEmployees(
        ImmutableEmployee.builder().name("William Shakespeare").build(),
        ImmutableEmployee.builder().name("T.S. Eliot").build()
    )
    .build();

Company c2 = ImmutableCompany.copyOf(c1).withEmployees(
    c1.employees().stream().map(employee ->
        ImmutableEmployee.copyOf(employee).withName(employee.name().toUpperCase())).collect(Collectors.toList())
);

assertThat(c2.employees().get(0).name(), equalTo("WILLIAM SHAKESPEARE"));
assertThat(c2.employees().get(1).name(), equalTo("T.S. ELIOT"));

This gets fairly unreadable in my real-world scenario, where the property being edited is buried three levels away from the parent node (the company), so I am just trying to make sure I there isn't a simpler approach that I'm missing.

Shteinitz
  • 37
  • 2
  • 5
  • What will `copyOf` return? the builder or the object itself? – Thiyagu Nov 27 '18 at 17:55
  • [`copyOf`](https://immutables.github.io/immutable.html#copy-methods) returns the object itself (`ImmutableCompany` or `ImmutableEmployee`). – Shteinitz Nov 27 '18 at 17:56
  • Will this be better? `ImmutableCompany.builder().name(c1.getName()).addEmployees( c1.employees().stream().map(employee -> ImmutableEmployee.builder().name(employee.name().toUpperCase())).collect(Collectors.toList()) );` – Thiyagu Nov 27 '18 at 17:59
  • It's unfortunately worse, because this way, I have to explicitly copy each property by name from c1 to c2 instead of a single `copyOf` call that copies all of them. In this toy example, there's only a single property to copy, but in real life, there would be way more. – Shteinitz Nov 27 '18 at 18:05

0 Answers0