web-dev-qa-db-fra.com

Validation de chaîne Java à l'aide de valeurs enum et d'annotations

Je veux valider une chaîne par rapport à un ensemble de valeurs en utilisant l'annotation . Ce que je veux, c'est fondamentalement ceci

@ValidateString(enumClass=com.co.enum)
String dataType;

int maxValue;
int minValue;
int precision;

ou

@ValidateString(values={"String","Boolean", "Integer"})
String dataType;

int maxValue;
int minValue;
int precision;

Je souhaite également valider d'autres variables en fonction de la valeur définie dans dataType,

if (dataType = "String") maxValue, minValue, precision tout doit être nul ou nul.

Je ne vois pas comment y parvenir par des annotations personnalisées ... . .

Quelqu'un s'il vous plaît aidez-moi

21
Joe

C'est ce que j'ai fait.

Annotation

public @interface ValidateString {

    String[] acceptedValues();

    String message() default "{uk.dds.ideskos.validator.ValidateString.message}";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { }; 
}

Classe de validation

public class StringValidator implements ConstraintValidator<ValidateString, String>{

    private List<String> valueList;

    @Override
    public void initialize(ValidateString constraintAnnotation) {
        valueList = new ArrayList<String>();
        for(String val : constraintAnnotation.acceptedValues()) {
            valueList.add(val.toUpperCase());
        }
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if(!valueList.contains(value.toUpperCase())) {
            return false;
        }
        return true;
    }

}

Et je l'ai utilisé comme

@ValidateString(acceptedValues={"Integer", "String"}, message="Invalid dataType")
String dataType;

Long maxValue;
Long minValue;

Maintenant, je dois savoir comment mettre en œuvre le contrôle conditionnel. Si String, alors maxValue et minValue doivent avoir la valeur null ou zéro.

Des idées?

20
Joe

Voici donc le code qui utilise la validation Spring et qui fonctionne très bien pour moi. Code complet donné ci-dessous. 

import Java.lang.annotation.Documented;
import Java.lang.annotation.ElementType;
import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;
import Java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import javax.validation.constraints.NotNull;

@Documented
@Constraint(validatedBy = EnumValidatorImpl.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@NotNull(message = "Value cannot be null")
@ReportAsSingleViolation
public @interface EnumValidator {

  Class<? extends Enum<?>> enumClazz();

  String message() default "Value is not valid";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};

}

Mise en œuvre de la classe ci-dessus:

import Java.util.ArrayList;
import Java.util.List;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class EnumValidatorImpl implements ConstraintValidator<EnumValidator, String> {

  List<String> valueList = null;

  @Override
  public boolean isValid(String value, ConstraintValidatorContext context) {
    if(!valueList.contains(value.toUpperCase())) {
      return false;
    }
    return true;
  }

  @Override
  public void initialize(EnumValidator constraintAnnotation) {
    valueList = new ArrayList<String>();
    Class<? extends Enum<?>> enumClass = constraintAnnotation.enumClazz();

    @SuppressWarnings("rawtypes")
    Enum[] enumValArr = enumClass.getEnumConstants();

    for(@SuppressWarnings("rawtypes")
    Enum enumVal : enumValArr) {
      valueList.add(enumVal.toString().toUpperCase());
    }

  }

}

UTILISATION DE L'ANNOTATION CI-DESSUS IS TRÈS SIMPLE

 @JsonProperty("lead_id")
  @EnumValidator( enumClazz=DefaultEnum.class,message="This error is coming from the enum class", groups = {Group1.class })
  private String leadId;
20
Rajeev Singla

Ditch la représentation de chaîne, et faire une vraie énumération.

public enum DataType {
   STRING,
   BOOLEAN,
   INTEGER;
}

De cette façon, vous évitez de faire la comparaison de chaînes de la variable String dataType précédente pour déterminer si elle se trouve dans l’énumération. Soit dit en passant, il est également impossible d'attribuer une valeur non valide à la variable membre dataType et, comme les énumérations sont garanties d'être des singletons dans le chargeur de classes, la sauvegarde enregistre également l'empreinte mémoire.

Cela vaut la peine de changer votre code pour utiliser des énumérations. Cependant, en supposant que vous ne puissiez pas le faire, vous pouvez au moins modifier l'annotation pour utiliser des énumérations.

@ValidateString(DataType.STRING) String dataType;

et ainsi votre annotation ValidateString pourra au moins bénéficier des énumérations, même si le reste du code ne le fait pas.

Désormais, si vous ne pouvez absolument pas utiliser d'énumération, vous pouvez définir des entiers publics statiques, qui mappent chaque valeur acceptée.

public class DataType {
  public static final int STRING = 1;
  public static final int BOOLEAN = 2;
  ...
}

Cependant, si vous utilisez une chaîne pour le paramètre d'annotation, nous n'avons pas de système de vérification de type qui s'étend dans le type pour spécifier que seules des valeurs particulières sont autorisées. En d'autres termes, Java n'a pas la capacité de faire quelque chose comme ceci:

public int<values=[1,3,5,7..9]> oddInt; 

qui jetterait une erreur si vous tentiez d’attribuer

 oddInt = 4;

Pourquoi est-ce important? En effet, s'il ne s'applique pas à Java standard, il ne peut pas s'appliquer à l'énumération implémentée dans les classes Java standard.

8
Edwin Buck

J'accepte la réponse de Rajeev Singla https://stackoverflow.com/a/21070806/8923905 , juste pour optimiser le code et permettre au paramètre String d'être nul, s'il n'est pas obligatoire et peut être vide dans votre application :

1- Supprimez l'annotation @NotNull sur l'interface

2- Voir le code modifié ci-dessous pour l'implémentation.

public class EnumValidatorImpl implements ConstraintValidator <EnumValidator,String> {

    private List<String> valueList = null;

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return null == value || valueList.contains(value.toUpperCase());
    }

    @Override
    public void initialize(EnumValidator constraintAnnotation) {
        valueList = new ArrayList<>();
        Class<? extends Enum<?>> enumClass = constraintAnnotation.enumClass();

        Enum[] enumValArr = enumClass.getEnumConstants();

        for(Enum enumVal : enumValArr) {
            valueList.add(enumVal.toString().toUpperCase());
        }

    }
}
0
Emmanuel H

Voici un exemple détaillé avec la fonctionnalité d'un message d'erreur dynamique par Hibernate Documentation

https://docs.jboss.org/hibernate/validator/4.1/reference/en-US/html/validator-customconstraints.html#validator-customconstraints-simple

0
Chen