Build an object from an existing one using lombok

JavaLombok

Java Problem Overview


Lets say I have a lombok annotated class like

@Builder
class Band {
   String name;
   String type;
}

I know I can do:

Band rollingStones = Band.builder().name("Rolling Stones").type("Rock Band").build();

Is there an easy way to create an object of Foo using the existing object as a template and changing one of it's properties?

Something like:

Band nirvana = Band.builder(rollingStones).name("Nirvana");

I can't find this in the lombok documentation.

Java Solutions


Solution 1 - Java

You can use the toBuilder parameter to give your instances a toBuilder() method.

@Builder(toBuilder=true)
class Foo {
   int x;
   ...
}

Foo f0 = Foo.builder().build();
Foo f1 = f0.toBuilder().x(42).build();

From the documentation:

> If using @Builder to generate builders to produce instances of your own class (this is always the case unless adding @Builder to a method that doesn't return your own type), you can use @Builder(toBuilder = true) to also generate an instance method in your class called toBuilder(); it creates a new builder that starts out with all the values of this instance.

Disclaimer: I am a lombok developer.

Solution 2 - Java

> Is there an easy way to create an object of Foo using the existing object as a template and changing one of it's properties? (emphasis mine)

If you really want to change a single property, then there's a nicer and more efficient way:

@With
class Band {
   String name;
   String type;
}

Band nirvana = rollingStones.withName("Nirvana");

The wither creates no garbage, but it can change just a single field. For changing many fields, you could use

withA(a).withB(b).withC(c)....

and produce tons of garbage (all intermediate results) but than toBuilder is more efficient and more natural.

NOTE: Older versions of lombok have used @Wither annotation. See beginning of documentation.

Solution 3 - Java

You might also want do a copy of the object using com.fasterxml.jackson.databind.ObjectMapper

@AllArgsConstructor
@Setter
class Band {
    String name;
    String type;
}

ObjectMapper objectMapper = new ObjectMapper(); //it's configurable
objectMapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
objectMapper.configure( SerializationFeature.FAIL_ON_EMPTY_BEANS, false );

Band rollingStones = new Band("Rolling Stones", "Rock Band");

Band nirvana = objectMapper.convertValue( rollingStones, Band.class);
nirvana.setName("Nirvana");

it can be easily wrapped in some utility method to be used all over the project like ConvertUtils.clone(rollingStones, Band.class)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMustafaView Question on Stackoverflow
Solution 1 - JavaRoel SpilkerView Answer on Stackoverflow
Solution 2 - JavamaaartinusView Answer on Stackoverflow
Solution 3 - JavaITishaView Answer on Stackoverflow