web-dev-qa-db-fra.com

Est-il possible en Java de vérifier si les champs d'objets sont nuls et d'ajouter une valeur par défaut à tous ces attributs?

Je dois m'assurer qu'aucun attribut d'objet n'est nul et ajouter une valeur par défaut au cas où il serait nul. Y a-t-il un moyen facile de faire cela, ou dois-je le faire manuellement en vérifiant chaque attribut par ses accesseurs et ses régleurs?

23
newbie

Vous pouvez utiliser la réflexion pour parcourir le champ de l'objet et les définir. Vous aurez évidemment besoin d'une sorte de mappage entre types ou même de noms de champs et de valeurs par défaut requises, mais cela peut être fait assez facilement dans une boucle. Par exemple:

for (Field f : obj.getClass().getFields()) {
  f.setAccessible(true);
  if (f.get(obj) == null) {
     f.set(obj, getDefaultValueForType(f.getType()));
  }
}

[Mettre à jour]

Avec Java moderne, vous pouvez utiliser des annotations pour définir les valeurs par défaut des champs par classe. Une implémentation complète pourrait ressembler à ceci:

// DefaultString.Java:
import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultString {
    String value();
}

// DefaultInteger.Java:
import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultInteger {
    int value();
}

// DefaultPojo.Java:
import Java.lang.annotation.Annotation;
import Java.lang.reflect.Field;

public class DefaultPojo {

    public void setDefaults() {
        for (Field f : getClass().getFields()) {
            f.setAccessible(true);
            try {
                if (f.get(this) == null) {
                    f.set(this, getDefaultValueFromAnnotation(f.getAnnotations()));
                }
            } catch (IllegalAccessException e) { // shouldn't happen because I used setAccessible
            }
        }
    }

    private Object getDefaultValueFromAnnotation(Annotation[] annotations) {
        for (Annotation a : annotations) {
            if (a instanceof DefaultString)
                return ((DefaultString)a).value();
            if (a instanceof DefaultInteger)
                return ((DefaultInteger)a).value();
        }
        return null;
    }

}

// Test Pojo
public class TestPojo extends DefaultPojo {
    @DefaultString("Hello world!")
    public String stringValue;
    @DefaultInteger(42);
    public int integerValue;
}

Alors les valeurs par défaut pour une TestPojo peuvent être définies simplement en exécutant test.setDetaults()

38
Guss

Vous devez filtrer manuellement les entrées des constructeurs et des setters. Eh bien ... vous pouvez utiliser la réflexion mais je ne le conseillerais pas. Une partie du travail des constructeurs et des installateurs consiste à valider les entrées. Cela peut inclure des choses comme:

public void setPrice(double price) {
  if (price < 0.0d) {
    throw new IllegalArgumentException("price cannot be negative " + price);
  }
  this.price = price;
}

et

public void setName(String name) {
  if (name == null) {
    throw new NullPointerException("name cannot be null");
  }
  this.name = name;
}

Vous pouvez utiliser des fonctions d'encapsidation pour la vérification réelle et le lancement de l'exception.

9
cletus

Peut-être vérifier Hibernate Validator 4.0 , l’implémentation de référence de la JSR 303: Validation de beans

Voici un exemple de classe annotée:

public class Address {

    @NotNull 
    private String line1;
    private String line2;
    private String Zip;
    private String state;

    @Length(max = 20)
    @NotNull
    private String country;

    @Range(min = -2, max = 50, message = "Floor out of range")
    public int floor;

        ...
}

Pour une introduction, voir Prise en main de JSR 303 (Validation de bean) - Partie 1 et Partie 2 ou la section "Mise en route" du guide de référence faisant partie de la distribution Hibernate Validator.

5
Pascal Thivent

Une solution non réfléchissante pour Java 8, sans utiliser une série de if, consisterait à diffuser tous les champs et à vérifier la validité:

return Stream.of(id, name).allMatch(Objects::isNull);

Cela reste assez facile à maintenir tout en évitant le marteau à réflexion ..__ Ceci retournera vrai pour les attributs nuls.

3
Amar Magar

J'ai essayé ceci et cela fonctionne sans problème pour valider si le champ est vide . J'ai répondu à votre question partiellement car je n'ai pas personnellement essayé d'ajouter des valeurs par défaut aux attributs

if(field.getText()!= null && !field.getText().isEmpty())

J'espère que ça aide

0
Mickey

Il ne s'agit pas de rechercher la valeur null, cela sera utile pour convertir un objet existant en un objet vide (objet récent). Je ne sais pas si cela est pertinent ou non, mais j'avais une telle exigence.

@SuppressWarnings({ "unchecked" })
static void emptyObject(Object obj) 
{
    Class c1 = obj.getClass();
    Field[] fields = c1.getDeclaredFields();

    for(Field field : fields)
    {
        try
        {
            if(field.getType().getCanonicalName() == "boolean")
            {
                field.set(obj, false);
            }
            else if(field.getType().getCanonicalName() == "char")
            {
                field.set(obj, '\u0000');
            }
            else if((field.getType().isPrimitive()))
            {
                field.set(obj, 0);
            }
            else
            {
                field.set(obj, null);
            }
        }
        catch(Exception ex)
        {

        }
    }
}
0
user6161504

Vous pouvez créer une fonction qui renvoie une valeur booléenne et vérifie chaque attribut. Vous pouvez appeler cette fonction pour faire le travail à votre place.

Vous pouvez également initialiser l'objet avec les valeurs par défaut. De cette façon, vous n'avez pas besoin de vérifier.

0
Lucas T

Je n'ai pas assez de contexte pour vous donner une réponse correcte, mais je vais vous suggérer de vous coder immuable autant que possible. Utilisez les champs public final. Pas plus getters ou setters: chaque champ doit être défini par la constructor. Votre code est plus court, plus lisible et vous empêche d’écrire du code avec des effets secondaires. 

Cela ne vous empêche pas de passer des arguments nuls à votre constructeur cependant ... Vous pouvez toujours vérifier chaque argument comme suggéré par @cletus, mais je vous suggère de lancer IllegalArgumentException au lieu de NullPointerException sans donner de nouvel indice sur ce que tu as fait.

Quoi qu'il en soit, c'est ce que je fais le plus possible et cela a considérablement amélioré mon code (lisibilité, stabilité). Tous les membres de mon équipe le font et nous en sommes très satisfaits. Nous avons appris que lorsque nous essayons d'écrire du code erlang où tout est immuable.

J'espère que cela t'aides.

0