Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build an object when we have inheritance relationship using lombok builder?

In my project, I am using lombok to avoid writing getters and setters for a class. Also, I am using lombok.Builder to build an object instead of writing new Obeject() and then setting all the values.

But when we have inheritance relationship and when we want to construct child object using lombok builder, I am not getting parent's field.

For example:

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class Parent{
  private String nationality;
  .
  .
  // more columns
}

And Child class would be something like this:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Child extends Parent{
   private String firstName;
   private String lastName;
   .
   .
}

In my test class, where I need to build child object

public class Test{

 public void testMethod(){
   Child child = Child.builder()
            .firstName("Rakesh")
            .lastName("SS")
            .nationality("some text")// I am not able to set nationality               
            .build();
 }


}

Please let me know, is there any way to handle this scenario in lombok.

like image 550
Rakesh Avatar asked Oct 07 '15 10:10

Rakesh


People also ask

How do builders use inheritance patterns?

Make a generic builder for each class that will have a subclass builder. This builder will already contain the setter methods for the current class, but we create also a second non generic builder for the class that contains the constructor and build method. The builders will not have any fields.

What is difference between @builder and @SuperBuilder?

The @SuperBuilder annotation produces complex builder APIs for your classes. In contrast to @Builder , @SuperBuilder also works with fields from superclasses. However, it only works for types. Most importantly, it requires that all superclasses also have the @SuperBuilder annotation.

Does @builder require AllArgsConstructor?

Martin GrajcarYour @Builder needs an @AllArgsConstructor (add it; feel free to make it private).

How do you use super builder?

An all new drag-and-drop page builder The Super Builder is a new tool for creating sleek landing pages right in Notion. Simply drag and drop components into place and change the content until you are happy. Then you can save out your page and turn into a live site using Super.


1 Answers

@Builder has no way to determine which fields of Parent you wish to expose.

When @Builder is placed on a class, only fields explicitly declared on that class are added to the *Builder.

When @Builder is placed on a static method or a constructor the resulting *Builder will have a method for each argument.

Also if you are using @Builder then is it safe to assume that at least Child is meant to be immutable?

I supply two examples, one where Parent is mutable and Child is immutable and one where both Parent and Child are immutable.

Immutable Parent and Child

import static org.junit.Assert.*;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.Value;
import lombok.experimental.NonFinal;

import org.junit.Test;

public class So32989562ValueTest {

    @Value
    @NonFinal
    public static class Parent {

        protected final String nationality;

    }

    @Value
    @ToString(callSuper = true)
    @EqualsAndHashCode(callSuper = true)
    public static class Child extends Parent {

        private final String firstName;

        private final String lastName;

        @Builder(toBuilder = true)
        private Child(String nationality, String firstName, String lastName) {
            super(nationality);
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }

    @Test
    public void testChildBuilder() {

        String expectedFirstName = "Jeff";
        String expectedLastName = "Maxwell";
        String expectedNationality = "USA";

        Child result = Child.builder()
            .firstName(expectedFirstName)
            .lastName(expectedLastName)
            .nationality(expectedNationality)
            .build();

        assertEquals(result.toString(), expectedFirstName, result.getFirstName());
        assertEquals(result.toString(), expectedLastName, result.getLastName());
        assertEquals(result.toString(), expectedNationality, result.getNationality());
    }
}

Mutable Parent, Immutable Child:

import static org.junit.Assert.*;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.Value;

import org.junit.Test;

public class So32989562DataTest {

    @Data
    public static class Parent {

        protected String nationality;

    }

    @Value
    @ToString(callSuper = true)
    @EqualsAndHashCode(callSuper = true)
    public static class Child extends Parent {

        private final String firstName;

        private final String lastName;

        @Builder(toBuilder = true)
        private Child(String nationality, String firstName, String lastName) {
            this.setNationality(nationality);
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }

    @Test
    public void testChildBuilder() {

        String expectedFirstName = "Jeff";
        String expectedLastName = "Maxwell";
        String expectedNationality = "USA";

        Child result = Child.builder()
            .firstName(expectedFirstName)
            .lastName(expectedLastName)
            .nationality(expectedNationality)
            .build();

        assertEquals(result.toString(), expectedFirstName, result.getFirstName());
        assertEquals(result.toString(), expectedLastName, result.getLastName());
        assertEquals(result.toString(), expectedNationality, result.getNationality());
    }
}
like image 55
Jeff Avatar answered Sep 17 '22 03:09

Jeff