web-dev-qa-db-fra.com

comment appeler super constructeur à Lombok

J'ai un cours 

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

J'ai une autre classe B

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

lombok génère une erreur en disant qu'il ne peut pas trouver le constructeur A(), appelez-le explicitement ce que je veux que lombok fasse est de donner une annotation à la classe b telle qu'elle génère le code suivant:

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

Avons-nous une annotation pour le faire à Lombok?

61
user2067797

Ce n'est pas possible à Lombok. Bien que ce soit une fonctionnalité vraiment agréable, il faut résoudre le problème pour trouver les constructeurs de la classe supérieure. La super classe n'est nommée que lorsque Lombok est invoqué. L'utilisation des instructions d'importation et du chemin d'accès aux classes pour trouver la classe réelle n'est pas triviale. Et lors de la compilation, vous ne pouvez pas simplement utiliser la réflexion pour obtenir une liste de constructeurs.

Ce n’est pas tout à fait impossible, mais les résultats obtenus avec la résolution dans val et @ExtensionMethod nous ont appris que c’est difficile et susceptible d’erreurs.

Divulgation: Je suis un développeur de Lombok.

91
Roel Spilker

Lombok Issue # 78 référence cette page https://www.donneo.de/2015/09/16/lomboks-builder-annotation-and-inheritance/ avec cette belle explication:

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

En conséquence, vous pouvez ensuite utiliser le générateur généré comme ceci:

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

La documentation officielle explique cela, mais elle ne précise pas que vous pouvez la faciliter de cette manière.

J'ai également constaté que cela fonctionne bien avec Spring Data JPA.

13
JJ Zabkar

Lombok ne prend pas en charge ce qui est également indiqué en faisant toute classe @Value annotée final (comme vous le savez en utilisant @NonFinal).

La seule solution que j'ai trouvée consiste à déclarer tous les membres finaux et à utiliser plutôt l'annotation @Data. Ces sous-classes doivent être annotées par @EqualsAndHashCode et requièrent un constructeur explicite de tous les arguments, car Lombok ne sait pas en créer un en utilisant l'un des arguments de la super classe:

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

En particulier, les constructeurs des sous-classes rendent la solution un peu désordonnée pour les super-classes avec de nombreux membres, désolé.

5
Arne Burmeister

pour les super-classes avec de nombreux membres, je vous suggère d'utiliser @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;
    }
}
2
Kris

Si la classe enfant a plus de membres que de parents, cela pourrait être fait de manière pas très propre, mais de manière courte:

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