wie man Super Konstruktor in Lombok aufruft


116

ich habe ein klasse

@Value
@NonFinal
public class A {
    int x;
    int y;
}

Ich habe eine andere Klasse B.

@Value
public class B extends A {
    int z;
}

lombok gibt einen Fehler aus, der besagt, dass es keinen A () -Konstruktor finden kann. Nenne es explizit. Ich möchte, dass lombok der Klasse b eine Anmerkung gibt, so dass der folgende Code generiert wird:

public class B extends A {
    int z;
    public B( int x, int y, int z) {
        super( x , y );
        this.z = z;
    }
}

Haben wir eine Anmerkung dazu in Lombok?

Antworten:


168

Dies ist in Lombok nicht möglich. Obwohl es eine wirklich nette Funktion wäre, erfordert es eine Auflösung, um die Konstruktoren der Superklasse zu finden. Die Superklasse ist nur in dem Moment namentlich bekannt, in dem Lombok aufgerufen wird. Die Verwendung der Importanweisungen und des Klassenpfads zum Auffinden der tatsächlichen Klasse ist nicht trivial. Und während der Kompilierung können Sie nicht einfach Reflection verwenden, um eine Liste der Konstruktoren zu erhalten.

Es ist nicht ganz unmöglich, aber die Ergebnisse mit Auflösung in valund @ExtensionMethodhaben uns gelehrt, dass es schwer und fehleranfällig ist.

Offenlegung: Ich bin ein Lombok-Entwickler.


@ roel-spilker Wir verstehen die Komplexität dahinter. Aber kann Lombok eine inConstructorMethode für Konstruktoranmerkungen bereitstellen, bei der wir angeben können, welcher Konstruktor von superLombok in den generierten Konstruktor injiziert werden soll?
Manu Manjunath

1
afterConstructor wäre auch nett, um eine automatische Initialisierung durchzuführen
Pawel

@ Manu / @ Pawel: siehe Lombok-Verbesserungsanforderung: github.com/peichhorn/lombok-pg/issues/78 (derzeit geöffnet)
JJ Zabkar

Da @Builder in der offiziellen Version ist, siehe: github.com/rzwitserloot/lombok/issues/853
Sebastian

4
Immer noch nicht möglich?
FearX

21

Die Lombok-Ausgabe Nr. 78 verweist auf diese Seite https://www.donneo.de/2015/09/16/lomboks-builder-annotation-and-inheritance/ mit dieser schönen Erklärung:

@AllArgsConstructor 
public class Parent {   
     private String a; 
}

public class Child extends Parent {
  private String b;

  @Builder
  public Child(String a, String b){
    super(a);
    this.b = b;   
  } 
} 

Als Ergebnis können Sie den generierten Builder dann wie folgt verwenden:

Child.builder().a("testA").b("testB").build(); 

In der offiziellen Dokumentation wird dies erläutert, es wird jedoch nicht ausdrücklich darauf hingewiesen, dass Sie dies auf diese Weise vereinfachen können.

Ich fand auch, dass dies gut mit Spring Data JPA funktioniert.


Können Sie ein Beispiel dafür geben, wie es mit Spring Data JPA verwendet wird?
Marc Zampetti

28
Dies beantwortet die Frage überhaupt nicht. Stattdessen erledigt es die Arbeit von Hand, während die Frage war, wie man sie erzeugt. Gleichzeitig wird das Ganze durch Ziehen von @Builder verwirrender, was nichts mit der Frage zu tun hat.
Jasper

8
Tatsächlich ist dies sehr nützlich für diejenigen, die nur eine Vererbungsstruktur erstellen und dann den Builder verwenden möchten. Dies ist zu 99% der Grund, warum ich sowieso #lombok benutze. Manchmal müssen wir nur Sachen von Hand herstellen, damit es so funktioniert, wie wir es uns wünschen. Also danke @ jj-zabkar
Babajide Prince

aber dann; Codieren Sie einfach den Konstruktor self + parent arg. Keine Notwendigkeit, einen Builder zu verwenden
Juh_

Es funktioniert in STS & Eclipse, aber wenn Sie eine JAR-Datei Ihrer Anwendung generieren, schlägt dies höchstwahrscheinlich fehl. Ich habe Both SuperBuilder, Builder für die Vererbung ausprobiert. Beide sind gescheitert. Achtung !!
P Satish Patro

6

Lombok unterstützt dies nicht, indem Sie eine @Valuekommentierte Klasse erstellen final(wie Sie wissen, indem Sie verwenden @NonFinal).

Die einzige Problemumgehung, die ich gefunden habe, besteht darin, alle Mitglieder für endgültig zu erklären und @Datastattdessen die Anmerkung zu verwenden. Diese Unterklassen müssen mit @EqualsAndHashCodeeinem expliziten Konstruktor für alle Argumente kommentiert werden und benötigen einen expliziten Konstruktor für alle Argumente, da Lombok nicht weiß, wie man eine mit allen Argumenten der Superklasse erstellt:

@Data
public class A {
    private final int x;
    private final int y;
}

@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A {
    private final int z;

    public B(int x, int y, int z) {
        super(x, y);
        this.z = z;
    }
}

Besonders die Konstruktoren der Unterklassen machen die Lösung für Superklassen mit vielen Mitgliedern etwas unordentlich, sorry.


1
Können Sie etwas näher erläutern, warum "Unterklassen mit Anmerkungen versehen werden müssen @EqualsAndHashCode"? Ist diese Anmerkung nicht enthalten von @Data? Thx :)
Gerard Bosch

1
@GerardB @Dataerstellt auch equals () und hashCode (), kümmert sich jedoch nicht um Vererbung. Um sicherzustellen, dass die Superklasse gleich () und hashCode () verwendet wird, benötigen Sie die explizite Generierung mit callSuper
Arne Burmeister

5

Für Superklassen mit vielen Mitgliedern würde ich empfehlen, @Delegate zu verwenden

@Data
public class A {
    @Delegate public class AInner{
        private final int x;
        private final int y;
    }
}

@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A {
    private final int z;

    public B(A.AInner a, int z) {
        super(a);
        this.z = z;
    }
}

Dies ist ein interessanter Ansatz, wie es!
Arne Burmeister

@Delegateist @Target({ElementType.FIELD, ElementType.METHOD}). AInner sollte Feld in sein A.
Boriselec

3

Wenn die Kinderklasse mehr Mitglieder als die Eltern hat, kann dies nicht sehr sauber, sondern auf kurze Weise durchgeführt werden:

@Data
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class User extends BaseEntity {
    private @NonNull String fullName;
    private @NonNull String email;
    ... 

    public User(Integer id, String fullName, String email, ....) {
        this(fullName, email, ....);
        this.id = id;
    }
}

@Data
@AllArgsConstructor
abstract public class BaseEntity {
   protected Integer id;

   public boolean isNew() {
      return id == null;
   }
}

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.