web-dev-qa-db-fra.com

Lombok @builder sur une classe qui étend une autre classe

J'ai deux classes Child extend Parent. Je dois mettre l'annotation @Builder sur les classes de sorte que je n'ai pas besoin de créer le générateur moi-même.

package jerry;// Internal compiler error: Java.lang.NullPointerException

import lombok.AllArgsConstructor;
import lombok.Builder;

@AllArgsConstructor(onConstructor=@__(@Builder))
public class Child extends Parent { 
//Multiple markers at this line
//  - Implicit super constructor Parent() is undefined. Must explicitly invoke another constructor
//  - overrides Java.lang.Object.toString

   private String a;
   private int b;
   private boolean c;

}


@Builder
public class Parent {
    private double d;
    private float e;
}

Je dois être capable de construire une instance enfant telle que 

Child child = Child.builder().a("aVal").b(1000).c(true).d(10.1).e(20.0F).build();

Mais jusqu’à présent, je reçois les erreurs mentionnées dans les commentaires de code. Quelqu'un peut-il m'indiquer la bonne direction pour y parvenir avec Lombok ou toute autre bibliothèque similaire?

Sous-question

Pourquoi @AllArgsConstructor(onConstructor=@__(@Autowired)) compile-t-il, mais pas @AllArgsConstructor(onConstructor=@__(@Builder))?

18
zur

Voir in https://blog.codecentric.de/en/2016/05/reducing-boilerplate-code-project-lombok/ (partie @Builder et héritage

Ajusté à vos cours

@AllArgsConstructor
public class Parent {
  private double d;
  private float e;
}

public class Child extends Parent {
  private String a;
  private int b;
  private boolean c;

  @Builder
  public Child(String a, int b, boolean c, double d, float e) {
    super(d, e);
    this.a = a;
    this.b = b;
    this.c = c;
  }
}

Avec cette configuration

Child child = Child.builder().a("aVal").b(1000).c(true).d(10.1).e(20.0F).build();

fonctionne correctement

23
hammerfest

La dernière version 1.18.2 de Lombok inclut le nouveau @SuperBuilder expérimental . Il supporte les champs des superclasses (aussi abstraits). Avec elle, la solution est aussi simple que cela:

@SuperBuilder
public class Child extends Parent {
   private String a;
   private int b;
   private boolean c;
}

@SuperBuilder
public class Parent {
    private double d;
    private float e;
}

Child instance = Child.builder().b(7).e(6.3).build();

PS: @AllArgsConstructor(onConstructor=@__(@Builder)) ne fonctionne pas car @Builder est une annotation de traitement d’annotation que lombok traduit en code lors de la compilation. Générer puis traduire une nouvelle annotation Lombok nécessiterait plusieurs itérations du traitement des annotations, que lombok ne prend pas en charge. @Autowired, en revanche, est une annotation Java régulière disponible au moment de l'exécution.

17
Jan Rieke

J'ai un cas d'utilisation similaire mais légèrement différent. Dans mon cas, j'ai une chaîne de super classes abstraites qui construisent et exécutent des requêtes. Des requêtes différentes partagent des paramètres communs, mais chaque requête ne prend pas en charge tous les paramètres. Les générateurs de requêtes concrètes doivent uniquement fournir des méthodes permettant de définir les paramètres pris en charge pour une requête donnée. 

J'ai commencé avec les implémentations de constructeur basées sur les constructeurs, mais cela a entraîné trop de code passe-partout, en particulier si vous avez plusieurs champs à configurer. Je propose maintenant les solutions suivantes, qui me paraissent beaucoup plus propres.

Fondamentalement, les sous-classes concrètes définissent les champs réels que le générateur doit prendre en charge, et l'annotation Getter entraîne la substitution des méthodes de superclasse correspondantes. Les getters dans les superclasses abstraites peuvent même être définis comme abstraits, ce qui nécessite des implémentations concrètes pour définir ces champs.

public abstract class AbstractSuperClass1 {
    protected String getParamA() { return "defaultValueA"; }

    public final void doSomething() {
        System.out.println(getParamA());
        doSomeThingElse();
    }

    protected abstract void doSomeThingElse();
}

public abstract class AbstractSuperClass2 extends AbstractSuperClass1 {
    protected String getParamB() { return "defaultValueB"; }

    protected void doSomeThingElse() {
        System.out.println(getParamB());
    }
}

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;

@Getter(AccessLevel.PROTECTED) @Builder
public class ConcreteClass1 extends AbstractSuperClass2 {
    private final String paramA;
    // Not supported by this implementation: private final String paramB;

    public static void main(String[] args) {
        ConcreteClass1.builder()
           .paramA("NonDefaultValueA")
           .build().doSomething();
    }
}

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;

@Getter(AccessLevel.PROTECTED) @Builder
public class ConcreteClass2 extends AbstractSuperClass2 {
    private final String paramA;
    private final String paramB;

    public static void main(String[] args) {
        ConcreteClass2.builder()
            .paramA("NonDefaultValueA").paramB("NonDefaultValueB")
            .build().doSomething();
    }
}
0
rsenden