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

StackOverflow https://stackoverflow.com/questions/2146129

  •  23-09-2019
  •  | 
  •  

Question

Je dois vous assurer qu'aucun attribut d'objet est nul et ajouter de la valeur par défaut dans le cas si elle est nulle. Yat-il un moyen facile de faire cela, ou dois-je le faire manuellement en vérifiant chaque attribut par ses accesseurs?

Était-ce utile?

La solution

Vous pouvez utiliser la réflexion pour itérer sur le champ de l'objet, et les définir. Vous auriez évidemment besoin d'une sorte de correspondance entre les types ou même les noms des champs et des valeurs par défaut nécessaires, mais cela peut se faire 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()));
  }
}

[Mise à jour]

Avec Java moderne, vous pouvez utiliser des annotations pour définir les valeurs par défaut des champs sur une base par classe. pourrait ressembler à une mise en œuvre complète 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;
}

Ensuite, les valeurs par défaut pour un TestPojo peut être réglé simplement en exécutant test.setDetaults()

Autres conseils

Vous devez filtrer manuellement l'entrée aux constructeurs et setters. Eh bien ... vous pouvez utiliser la réflexion, mais je ne voudrais pas le conseiller. Une partie du travail des constructeurs et setters est de valider l'entrée. 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 les fonctions wrapper pour le contrôle réel et jeter l'exception.

Peut-être vérifier Hibernate Validator 4.0 , la mise en œuvre de référence du JSR 303: Bean validation .

Ceci est un exemple d'une 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 Mise en route avec JSR 303 (Bean validation) - partie 1 et partie 2 ou la "section Mise en route" du guide de référence qui fait partie de la distribution Hibernate Validator.

Solution non réfléchissante pour Java 8, sans utiliser une série de cas de, serait de diffuser tous les champs et vérifier l'état NULL:

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

Cela reste assez facile à maintenir, tout en évitant le marteau de réflexion. Cela retourne vrai pour les attributs null.

Vous pouvez créer une fonction qui renvoie une valeur booléenne et vérifie tous les attributs. Vous pouvez appeler cette fonction pour faire le travail pour vous.

Vous pouvez initialiser l'objet avec des valeurs par défaut. De cette façon, il n'y a pas besoin pour vous de faire une vérification.

Je n'ai pas assez contexte pour vous donner une bonne réponse, mais je vais vous suggère de vous rendre le code immuable autant que possible. Utilisez des champs public final. Plus getters ou setters: tous les domaines doit être défini par le constructor. Votre code est plus court, plus lisible et vous empêche de l'écriture de code avec des effets secondaires.

Il ne vous empêche pas d'arguments nuls passer à votre constructeur mais ... Vous pouvez toujours vérifier tous les arguments comme suggéré par @cletus, mais je vais vous suggérer de jeter IllegalArgumentException au lieu de NullPointerException qui ne donne pas non nouvelle indication sur ce que vous avez fait.

Quoi qu'il en soit, c'est ce que je fais autant que je peux et amélioré mon code (lisibilité, la stabilité) à une grande extension. Tout le monde dans mon équipe le fait et nous sommes très heureux. Nous avons appris que lorsque nous essayons d'écrire un code de erlang où tout est immuable.

Hope this helps.

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

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

it helps

est de ne pas vérifier nulle, au lieu que ce sera utile pour la conversion d'un objet existant à un objet vide (objet frais). 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)
        {

        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top