2015-04-20 11 views
35

Ho una classeCome chiamare costruttore eccellente a Lombok

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

Ho un'altra classe B

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

Lombok sta gettando errore dicendo che cant trovare un costruttore(), chiamare esplicitamente cosa voglio Lombok da fare è dare l'annotazione di classe B in modo tale che esso genera il seguente codice:

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

facciamo hai un'annotazione per farlo a Lombok?

risposta

51

Questo non è possibile in Lombok. Anche se sarebbe una caratteristica davvero carina, richiede una risoluzione per trovare i costruttori della super classe. La super classe è conosciuta solo per nome nel momento in cui Lombok viene richiamato. Utilizzare le istruzioni di importazione e il classpath per trovare la classe effettiva non è banale. E durante la compilazione non puoi usare la reflection per ottenere una lista di costruttori.

Non è del tutto impossibile ma i risultati che utilizzano la risoluzione in val e @ExtensionMethod ci hanno insegnato che è difficile e soggetto a errori.

Disclosure: Sono uno sviluppatore di Lombok.

+0

@ roel-spilker Comprendiamo la complessità dietro di esso.Ma Lombok può fornire un metodo 'inConstructor' per le annotazioni del costruttore in cui possiamo specificare quale costruttore di' super' deve iniettare Lombok nel costruttore generato? –

+0

afterConstructor sarebbe bello anche per fare un'inizializzazione automatica – Pawel

+0

@ Manu/@ Pawel: vedere la richiesta di potenziamento lombok: https://github.com/peichhorn/lombok-pg/issues/78 (attualmente aperto) –

8

Lombok Issue #78 riferimenti questa pagina https://www.donneo.de/2015/09/16/lomboks-builder-annotation-and-inheritance/ con questa bella spiegazione:

@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; 
    } 
} 

Come risultato si può quindi utilizzare il costruttore generato in questo modo:

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

Il official documentation spiega questo, ma non indica esplicitamente che puoi facilitarla in questo modo.

Ho anche trovato che funziona bene con Spring Data JPA.

+0

Puoi fornire un esempio di questo utilizzo con Spring Data JPA? –

+7

Questo non risponde affatto alla domanda. Invece, fa il lavoro a mano, mentre la domanda era come generarlo. Allo stesso tempo, rende tutto più confuso trascinando @Builder, che non ha nulla a che fare con la domanda. – Jasper

+0

In realtà questo è molto utile per coloro che vogliono solo creare una struttura di ereditarietà e quindi utilizzare il builder. Questo è il 99% dei motivi per cui uso #lombok comunque. A volte dobbiamo solo fabbricare oggetti per farlo funzionare nel modo che desideriamo. Grazie, @ jj-zabkar –

3

Lombok non supporta quello indicato anche facendo una qualsiasi classe annotata @Valuefinal (come sapete usando @NonFinal).

L'unica soluzione che ho trovato è dichiarare tutti i membri finali da soli e utilizzare invece l'annotazione @Data. Quei sottoclassi devono essere annotata da @EqualsAndHashCode e hanno bisogno di un esplicito tutto args costruttore come Lombok non sa come crearne uno usando i tutti args uno della classe super:

@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; 
    } 
} 

Soprattutto i costruttori delle sottoclassi rendono il soluzione un po 'disordinata per le superclassi con molti membri, mi dispiace.

+0

Puoi spiegare un po 'di più perché "le sottoclassi devono essere annotate da' @ EqualsAndHashCode' "? Questa annotazione non è inclusa da '@ Data'? Thx :) –

+0

@GerardB '@ Data' crea anche equals() e hashCode() ma non importa di alcuna ereditarietà. Per assicurarsi che la superclasse equals() e hashCode() sia usata, hai bisogno della generazione esplicita con callSuper –

1

per superclassi con molti membri vorrei suggerire di utilizzare @Delegate

@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; 
    } 
} 
+0

Questo è un approccio interessante, come questo! –

0

Se la classe bambino ha più membri, di genitore, potrebbe essere fatto non molto pulita, ma così breve:

@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; 
    } 
} 
Problemi correlati