Does Lombok toBuilder() method creates deep copy of fields

Viewed 26444

I am using toBuilder() on an object instance to create a builder instance and then build method to create new instance. The original object has a list, does the new object has reference to same list or a copy of it?

@Getter
@Setter
@AllArgsConstructor
public class Library {

    private List<Book> books;

    @Builder(toBuilder=true)
    public Library(final List<Book> books){
         this.books = books;
    }

}

Library lib2  = lib1.toBuilder().build();

Will lib2 books refer to same list as lib1 books ?

3 Answers

Yes, the @Builder(toBuilder=true) annotation doesn't perform a deep copy of the object and only copies the reference of the field.

List<Book> books = new ArrayList<>();
Library one = new Library(books);
Library two = one.toBuilder().build();
System.out.println(one.getBooks() == two.getBooks()); // true, same reference

You can make a copy of the collection manually with one simple trick:

    List<Book> books = new ArrayList<>();
    Library one = new Library(books);
    Library two = one.toBuilder()
        .books(new ArrayList<>(one.getBooks))
        .build();
    System.out.println(one.getBooks() == two.getBooks()); // false, different refs

Actually what you can do is to use other mapping tools to create a new object from the existing one.

For example com.fasterxml.jackson.databind.ObjectMapper

    @AllArgsConstructor
    public static class Book
    {
        private String title;
    }

    @NoArgsConstructor
    @AllArgsConstructor
    @Getter
    public static class Library
    {
        private List<Book> books;
    }

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

    List<Book> books = new ArrayList<>();
    Library one = new Library( books );

    Library two = objectMapper.convertValue( one, Library.class );
    System.out.println( one.getBooks() == two.getBooks() ); // false, different refs

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

Related