web-dev-qa-db-fra.com

Résoudre le problème du sonar dans les méthodes simples pour getter et setter avec Date ou List

J'écris ce getter/setter à la liste à partir du menu source Eclipse:

public Date getDate() {
    return date;
}

public void setDate(Date date) {
    this.date = date;
}

Et Sonar signalant deux problèmes:

Renvoyer une copie de "date" et stocker une copie de "date"

avec l'explication

"Les membres mutables ne doivent pas être stockés ou retournés directement"

et un exemple de code:

public String [] getStrings() {
    return strings.clone();}

public void setStrings(String [] strings) {
    this.strings = strings.clone();}

Je pense que si ma date est nulle, une exception NullPointerException sera lancée. Ensuite, j'ai changé mon code pour:

public Date getDate() {
    if (this.date != null) {
        return new Date(this.date.getTime());
    } else {
        return null;
    }
}

public void setDate(Date date) {
    if (date != null) {
        this.date = new Date(date.getTime());
    } else {
        this.date = null;
    }
}

Et marque maintenant un autre problème:

"Assigner un objet à null est une odeur de code. Envisagez un refactoring".

J'ai cherché sur internet et définir ou renvoyer un nouveau tableau n'est pas une solution pour moi. Je souhaite conserver ma liste à null si le paramètre setter est null pour écraser une liste précédente existante.

J'ai le même problème pour List et je veux renvoyer/preserve null au lieu d'un nouvel ArrayList pour une liste vide. Et dans ce cas, le poseur marque un autre problème:

"Retourne une collection vide au lieu de null.".

Quelle est la solution à ce problème?

6
Javi L

Si vous êtes dans Java 8 et que vous ne souhaitez pas gérer une date vide, l'utilisation de Optional vous aidera peut-être.

Edit: Exemple de votre classe "POJO"

public class Toto {

    public Optional<Date> myDate;

    public Optional<Date> getMyDate() {
        return this.myDate;
    }

    public void setMyDate(final Date myDate) {
        this.myDate = Optional.ofNullable(myDate);
    }

}

Exemple d'utilisation du code:

Toto toto = new Toto();
toto.setMyDate(null);
System.out.println("Value is null ? " + toto.getMyDate().isPresent());
System.out.println("Value: " + toto.getMyDate().orElse(new Date()));

Essayez de changer le toto.setMyDate (...) avec une valeur de date concrète pour voir ce qui se passe.

Si vous ne savez pas ce qui est facultatif ou comment l'utiliser, vous pouvez trouver de nombreux exemples.

BUT: C’est seulement un moyen de résoudre votre problème de violation et je suis tout à fait d’accord avec la remarque de Brad. Facultatif n’est pas destiné à être utilisé comme type, mais plutôt comme un contrat pour des retours potentiels nuls/nuls. En règle générale, vous ne devez pas corriger votre code de manière incorrecte, mais uniquement pour réparer une violation, si celle-ci est incorrecte. Et dans votre cas, je pense que vous devriez simplement ignorer la violation (comme la plupart des cas de Sonar malheureusement)

Si vous voulez vraiment utiliser Java 8 et Optional dans votre code, votre classe POJO ressemblera à ceci (utilisation de Optional comme contrat sur le getter uniquement)

public class Toto {


    public Date myDate;

    public Optional<Date> getMyDate() {
        return Optional.ofNullable(this.myDate);
    }

    public void setMyDate(final Date myDate) {
        this.myDate = myDate;
    }

}

Par ici,

  • Vous devez rester sérialisable (facultatif, ce n'est pas le cas)
  • Vous activez toujours votre code "client" pour avoir le choix sur la manière de se comporter pour vider/null la valeur de votre propriété
  • Configurez votre violation Sonar comme un faux positif car c’est ce que vous voulez au lieu de changer votre code
3
kij

En règle générale, lorsque vous utilisez des outils d'analyse statique pour vérifier que le code est utile, vous ne devez pas résoudre aveuglément tous les avertissements qui s'affichent sur vous. Vous devez analyser le problème qui est déclenché et vérifier s'il s'applique vraiment dans votre contexte.

Maintenant, pour aborder les problèmes que vous mentionnez

Renvoyer une copie de "date" et stocker une copie de "date"

Cela semble être valide. Il est judicieux d’être sur la défensive et de ne pas exposer un état mutable via des accesseurs/régleurs. Il faut donc créer une copie défensive dans le getter/setter. Cela peut être fait comme vous l'avez fait, ou en utilisant la nouvelle API Java Time, qui fournit des objets immuables.

Assigner un objet à null est une odeur de code. Envisager de refactoriser

OMI douteux. Le problème est soulevé par le plug-in PMD (l'outil d'analyse du code, SonarQube affichant le rapport). Cette règle soulève un problème http://pmd.sourceforge.net/pmd-4.3.0/rules/controversial.html#NullAssignment , comme vous pouvez le constater, il s'agit d'une catégorie controversée. Je ne pense pas que votre code soit incorrect, et une action appropriée pourrait consister à ignorer cet avertissement et à marquer le problème comme "ne résoudra pas". Vous pouvez également configurer votre SonarQube pour ne pas utiliser cette règle particulière dans votre paramètre de profil qualité.

Renvoie une collection vide au lieu de null.

Vous n'avez pas fourni le code qui le déclenche, mais cela semble être un conseil valable. Il est généralement préférable de renvoyer des collections vides plutôt que des valeurs nulles.

1
Tibor Blenessy

Vous n'avez pas à définir explicitement null dans votre setter, utilisez simplement la valeur transmise comme ceci ...

public void setDate(Date date) {
    if (date != null) {
        this.date = new Date(date.getTime());
    } else {
        this.date = date;
    }
}

Personnellement, je n’autoriserais jamais des valeurs NULL dans mes objets Value dans la mesure du possible, mais c’est juste mon style de codage.

Je conseille à quiconque de préférer les objets de valeur immuables dans lesquels vous définissez toutes les valeurs du constructeur et n'autorisez pas les valeurs NULL. il peut être utilisé efficacement pour simplifier votre code.

Modifier

Si le code ci-dessus vous avertit toujours et que vous devez disposer de la fonctionnalité "La propriété n'est pas encore définie", une autre approche consiste à définir un "objet null" comme celui-ci.

public static final Date NO_DATE = new Date(Long.MIN_VALUE);

public void setDate(Date date) {
    this.date = (date == null) ? NO_DATE : new Date(date.getTime());
}

Les utilisateurs de cette classe peuvent se référer à l'objet NO_DATE comme celui-ci, ce qui permet tout de même un code lisible.

if(toto.getDate() != NO_DATE) ...

Ou encapsulez ceci dans une autre méthode afin qu'il soit utilisé comme ceci

if(toto.hasDate()) ...

Bien sûr, cela n’apporte pas beaucoup d’avantages par rapport à l’approche Java 8 facultative de @kij, mais cela fonctionne avec n’importe quelle version de Java.

1
Brad

Je recommanderais d'utiliser la bibliothèque Lombok plutôt que de créer manuellement des getters et des setters. Cela évitera automatiquement ces problèmes de sonar.

0
k_b