web-dev-qa-db-fra.com

Comment construire un objet lorsque nous avons une relation d'héritage en utilisant lombok builder?

Dans mon projet, j'utilise lombok pour éviter d'écrire des getters et setters pour une classe. En outre, j'utilise lombok.Builder pour construire un objet au lieu d'écrire un nouveau Obeject () puis de définir toutes les valeurs.

Mais lorsque nous avons une relation d'héritage et que nous voulons construire un objet enfant à l'aide du générateur lombok, je n'obtiens pas le champ parent.

Par exemple:

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

Et la classe enfant serait quelque chose comme ceci:

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

Dans ma classe de test, où j'ai besoin de construire un objet enfant

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();
 }


}

Veuillez me le faire savoir, existe-t-il un moyen de gérer ce scénario à lombok.

14
Rakesh

@Builder n'a aucun moyen de déterminer quels champs de Parent vous souhaitez exposer.

Quand @Builder est placé sur une classe, seuls les champs explicitement déclarés sur cette classe sont ajoutés au *Builder.

Quand @Builder est placé sur une méthode statique ou un constructeur le *Builder aura une méthode pour chaque argument.

De plus, si vous utilisez @Builder alors est-il sûr de supposer qu'au moins Child est censé être immuable?

Je fournis deux exemples, un où Parent est modifiable et Child est immuable et un où Parent et Child sont immuables.

Parent et enfant immuables

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());
    }
}

Parent mutable, enfant immuable:

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());
    }
}
19
Jeff

La solution ci-dessus fonctionne, mais cela nécessite trop de solution. De plus, tout changement dans la classe enfant et parent nécessite de changer partout les arguments du constructeur.

Lombok a introduit des fonctionnalités expérimentales avec la version: 1.18.2 pour les problèmes d'héritage rencontrés avec l'annotation Builder, et peut être résolu avec l'annotation @SuperBuilder comme ci-dessous.

@SuperBuilder
public class ParentClass {
    private final String a;
    private final String b;
}

@SuperBuilder
public class ChildClass extends ParentClass{
    private final String c;
}

Maintenant, on peut utiliser la classe Builder comme ci-dessous (ce n'était pas possible avec l'annotation @Builder)

ChildClass.builder().a("testA").b("testB").c("testC").build();
9
Amit Kaneria