web-dev-qa-db-fra.com

Valeur par défaut en lombok. Comment initier par défaut avec le constructeur et le constructeur

J'ai un objet

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
    private int id;
    private String nick;
    private boolean isEmailConfirmed = true;
}

Et je l'initialise de deux manières

UserInfo ui = new UserInfo();
UserInfo ui2 = UserInfo.builder().build();

System.out.println("ui: " + ui.isEmailConfirmed());
System.out.println("ui2: " + ui2.isEmailConfirmed());

Voici la sortie

ui: true
ui2: false

Il semble que le constructeur n'obtienne pas de valeur par défaut. J'ajoute l'annotation @Builder.Default à ma propriété et mon objet ressemble maintenant à ceci

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo { 
    private int id;
    private String nick;
    @Builder.Default
    private boolean isEmailConfirmed = true;
}

Voici la sortie de la console

ui: false
ui2: true

Comment puis-je faire les deux être true?

35
Vitalii

J'imagine que ce n'est pas possible (sans avoir supprimé le code). Mais pourquoi ne pas simplement implémenter le constructeur dont vous avez besoin? Lombok est conçu pour vous faciliter la vie, et si quelque chose ne fonctionne pas avec Lombok, il suffit de le faire à l’ancienne.

@Data
@Builder
@AllArgsConstructor
public class UserInfo { 
    private int id;
    private String nick;
    @Builder.Default
    private boolean isEmailConfirmed = true;

    public UserInfo(){
        isEmailConfirmed = true;
    }
}

Sortie de la console:

ui: true
ui2: true
18

Comme @Builder.Default l'annotation est cassée , je ne l'emploierais pas du tout. Vous pouvez toutefois utiliser l'approche suivante:

@Data
@NoArgsConstructor
public class UserInfo {

    private int id;
    private String nick;
    private boolean isEmailConfirmed = true;

    @Builder
    @SuppressWarnings("unused")
    private UserInfo(int id, String nick, Boolean isEmailConfirmed) {
        this.id = id;
        this.nick = nick;
        this.isEmailConfirmed = Optional.ofNullable(isEmailConfirmed).orElse(this.isEmailConfirmed);
    }
}

De cette façon, vous vous assurez:

  • le champ isEmailConfirmed n'est initialisé qu'à un seul endroit, ce qui rend le code moins sujet aux erreurs et plus facile à gérer ultérieurement
  • la classe UserInfo sera initialisée de la même manière que vous utilisiez un générateur ou un constructeur sans argument

En d'autres termes, la condition contient true:

new UserInfo().equals(UserInfo.builder().build())

Dans ce cas, la création d'objet est cohérente quelle que soit la manière dont vous le créez. Cela est particulièrement important lorsque votre classe est utilisée par une infrastructure de mappage ou par un fournisseur JPA lorsque vous ne l'instanciez pas manuellement par un générateur mais qu'un constructeur no-args est appelé dans votre dos pour créer l'instance.

L'approche décrite ci-dessus est très similaire mais présente un inconvénient majeur. Vous devez initialiser le champ à deux endroits, ce qui rend le code sujet aux erreurs car vous devez garder les valeurs cohérentes.

31
Marcin Kłopotek

Vous pouvez également définir votre propre méthode getterannulation la lombok getter:

@Data
@Builder
@AllArgsConstructor
public class UserInfo { 
    private int id;
    private String nick;
    private Boolean isEmailConfirmed;

    public Boolean getIsEmailConfirmed(){
      return Objects.isNull(isEmailConfirmed) ? true : isEmailConfirmed;
    }
}
2
Sahil Chhabra

Voici mon approche:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
public class UserInfo { 
    private int id;
    private String nick;
    private boolean isEmailConfirmed = true;
}

Puis

UserInfo ui = new UserInfo().toBuilder().build();
0
laurent

Les constructeurs personnalisés et @Builder.Default ne fonctionneront probablement jamais ensemble.

Les auteurs de framework veulent éviter les doubles initialisations pour @Builder.

Je réutilise .builder() par public static CLAZZ of(...) méthodes:

@Builder
public class Connection {
    private String user;
    private String pass;

    @Builder.Default
    private long timeout = 10_000;

    @Builder.Default
    private String port = "8080";

    public static Connection of(String user, String pass) {
        return Connection.builder()
            .user(user)
            .pass(pass)
            .build();
    }

    public static Connection of(String user, String pass, String port) {
        return Connection.builder()
            .user(user)
            .pass(pass)
            .port(port)
            .build();
    }

    public static Connection of(String user, String pass, String port, long timeout) {
        return Connection.builder()
            .user(user)
            .pass(pass)
            .port(port)
            .timeout(timeout)
            .build();
    }
}

Vérifiez la discussion correspondante: https://github.com/rzwitserloot/lombok/issues/1347

0
gavenkoa