[Java] Création d'annotations originales

Contexte

Si je l'ai implémenté avec de nombreuses annotations dans le modèle d'origine, j'ai reçu une critique disant "C'est difficile à voir, donc si vous faites vos propres annotations et que vous l'utilisez, ce sera plus facile à voir", alors je l'ai essayé.

before classe de contrôleur

@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping(path = "/sample")
public class SampleController {

/**
   *Exemple d'API d'acquisition de données
   *
   * @id de paramètre ID de données d'échantillon
   * @retour Informations détaillées sur les exemples de données
   */
  @GetMapping(path = "{id}", produces = "application/json; charset=UTF-8")
  @ResponseStatus(HttpStatus.OK)
  public Response getSampleDataDetails(@Nonnull @Pattern(regexp = "[0-9]{8}") 
                                       @PathVariable final String id) {
    log.info(String.format("SampleController { id : %s }", id));
    return idUseCase.getSampleDataDetails(id);
  }
}

classe de modèle

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ModelSample {

  @NotBlank
  @Size(max = 1024)
  private String name;

  @Digits(integer = 3, fraction = 2)
  private Double percentage;

}

after classe de contrôleur

@Validated
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping(path = "/sample")
public class SampleController {

  /**
   *Exemple d'API d'acquisition de données
   *
   * @id de paramètre ID de données d'échantillon
   * @retour Informations détaillées sur les exemples de données
   */
  @GetMapping(path = "{id}", produces = "application/json; charset=UTF-8")
  @ResponseStatus(HttpStatus.OK)
  public Response getSampleDataDetails(@Id @Valid @Nonnull
                                       @PathVariable final String id) {
    log.info(String.format("SampleController { id : %s }", id));
    return idUseCase.getSampleDataDetails(id);
  }
}

classe de modèle

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Validated
public class ModelSample {

  @Name
  @Valid
  private String name;

  @Percentage
  @Valid
  private Double percentage;

}

Créer une classe d'annotations

Vous pouvez sentir que les annotations sont actualisées avant / après. Pour réaliser cela, créez d'abord une classe d'annotations.

ʻId annotation class`

@Target(ElementType.PARAMETER)
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Pattern(regexp = "[0-9]{8}")
@Nonnull
public @interface Id {

  String message() default "id: don't match format";

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

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

}

Commentaire

@Target L'argument @ Target spécifie où appliquer l'annotation.

valeur Où postuler
ElementType.TYPE Classe, interface, annotation, type enum
ElementType.FIELD champ
ElementType.CONSTRUCTOR constructeur
ElementType.METHOD Méthode

@Retention Dans l'argument de «@ Retention», spécifiez la plage pour contenir l'annotation.

valeur Plage à tenir
RetentionPolicy.RUNTIME Tenez au moment de l'exécution.
RetentionPolicy.CLASS Gardez dans le fichier de classe. (Non conservé lors de l'exécution.)
RetentionPolicy.SOURCE Gardez dans le fichier source. (Il n'est pas conservé dans le fichier de classe.)

Si vous n'ajoutez pas * @Retention, RetentionPolicy.CLASS sera la valeur par défaut.

@Constraint Dans l'argument de @ Constraint, attribut validateBy, spécifiez la validation à exécuter par cette annotation. Si vous souhaitez implémenter votre propre processus de validation, spécifiez ici la classe de validateur qui implémente le processus. Cette fois, nous allons créer une combinaison de contraintes existantes, donc cet argument est laissé vide.

Annotation de contrainte

Ajoutez des annotations de contrainte telles que «@ Pattern» et «@ Nonnull» à votre propre classe d'annotations. L'annotation ajoutée ici est vérifiée lors de la validation de la classe à l'aide de l'annotation d'origine.

@interface Vous pouvez définir vos propres annotations en utilisant @ interface.

message Pour message, spécifiez le message lorsque la contrainte est violée.

groups groups spécifie un attribut pour déterminer s'il faut exécuter la vérification des contraintes en fonction de la situation. L'attribut groups vous permet de regrouper des contraintes dans n'importe quel groupe, et vous pouvez spécifier ce groupe lors de l'exécution de la validation pour vérifier différentes contraintes pour chaque groupe. Cette fois, il n'est pas nécessaire de les regrouper, il est donc implémenté vide.

payload payload spécifie un attribut qui donne une catégorie arbitraire, telle que la gravité, pour les violations de contrainte. Je vais l'utiliser au besoin, mais cette fois il n'y a pas de catégorie particulière, donc je l'implémente vide.

List List est une annotation imbriquée et est utilisée lorsque la même contrainte est définie plusieurs fois dans des conditions différentes. Cette fois, nous n'utiliserons pas la même contrainte car nous ne la définirons pas plusieurs fois dans des conditions différentes.

Créer d'autres classes d'annotations

De même, créez des annotations pour «nom» et «pourcentage».

Classe d'annotation pour name

@Target(ElementType.FIELD)
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Size(max = 1024)
@NotBlank
public @interface Name {
  String message() default "name: don't match format";

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

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

Classe d'annotation pour «pourcentage»

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Digits(integer = 3, fraction = 2)
public @interface Percentage {
  String message() default "percentage: don't match format";

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

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

Commentaire

@Size Indique que la longueur de la chaîne dans le champ cible se situe dans la plage de tailles spécifiée.

@Digits Spécifiez le nombre maximum de chiffres dans la partie entière pour ʻintégrateuret le nombre maximum de chiffres pour la partie fractionnaire dansfraction. @Digits (integer = 3, fraction = 2)` signifie que "sur le nombre maximum de chiffres, 2 chiffres sont le maximum après la virgule décimale".

Joindre des annotations aux classes utilisées

classe de contrôleur

@Validated
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping(path = "/sample")
public class SampleController {

  /**
   *Exemple d'API d'acquisition de données
   *
   * @id de paramètre ID de données d'échantillon
   * @retour Informations détaillées sur les exemples de données
   */
  @GetMapping(path = "{id}", produces = "application/json; charset=UTF-8")
  @ResponseStatus(HttpStatus.OK)
  public Response getSampleDataDetails(@Id @Valid @Nonnull
                                       @PathVariable final String id) {
    log.info(String.format("SampleController { id : %s }", id));
    return idUseCase.getSampleDataDetails(id);
  }
}

classe de modèle

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Validated
public class ModelSample {

  @Name
  @Valid
  private String name;

  @Percentage
  @Valid
  private Double percentage;

}

point important

Bonus: créez votre propre processus de validation

Vous pouvez ajouter votre propre processus de validation au lieu de combiner des contraintes existantes pour créer une annotation comme celle-ci. Dans un tel cas, nous implémenterons la classe de validateur. Nous mettrons en œuvre le processus de validation des identifiants créé cette fois.

ʻId annotation class`

@Target(ElementType.PARAMETER)
@Retention(RUNTIME)
@Constraint(validatedBy = {idValidator.class})
@Pattern(regexp = "[0-9]{8}")
@Nonnull
public @interface Id {

  String message() default "id: don't match format";

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

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

}

Classe d'implémentation du traitement de validation

public class IdValidator implements ConstraintValidator<id, String> {

@Override 
   public void initialize(Id id) {} 

@Override 
   public boolean isValid(String value, ConstraintValidatorContext context) { 
     String pattern = "[0-9]{8}"; 
     if (!StringUtils.isEmpty(value)) {
       return value.matches(pattern);
     }
     return false; 
   } 
 } 

description de la classe d'identifiant

@Constraint Définissez la classe de traitement de validation dans @ Constraint.

Commentaire de classe IdValidator

ConstraintValidator<A,T> Varidata doit implémenter ConstraintValidator <A, T>. A est l'annotation de contrainte et T est le type de valeur d'entrée. Cette fois, j'ai créé une annotation de contrainte par moi-même, donc je l'ai implémentée en supposant que A recevra la classe id et T recevra la valeur sous forme de chaîne.

A est initialize et T est le type d'argument de isValid.

initialize ʻInitialize` vous permet d'obtenir la valeur d'attribut de l'annotation de contrainte définie dans la propriété JavaBeans. Je n'en ai pas besoin cette fois, alors je l'ai créé vide.

isValid Si la validation est effectuée avec ʻisValid` et que la valeur de retour est false, ConstraintVaiolation sera générée comme un échec de validation. Le processus sera décrit ici. Cette fois, il détermine si la valeur reçue correspond à l'expression régulière et renvoie vrai ou faux. S'il n'est pas inclus dans l'instruction if en premier lieu, il peut être déterminé que la valeur reçue n'est pas une chaîne, donc false est renvoyé.

Joindre des annotations aux classes utilisées

L'utilisation est la même que lors de la création en combinant des annotations existantes.

@Validated
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping(path = "/sample")
public class SampleController {

  /**
   *Exemple d'API d'acquisition de données
   *
   * @id de paramètre ID de données d'échantillon
   * @retour Informations détaillées sur les exemples de données
   */
  @GetMapping(path = "{id}", produces = "application/json; charset=UTF-8")
  @ResponseStatus(HttpStatus.OK)
  public Response getSampleDataDetails(@Id @Valid @Nonnull
                                       @PathVariable final String id) {
    log.info(String.format("SampleController { id : %s }", id));
    return idUseCase.getSampleDataDetails(id);
  }
}

Encore une fois, faites attention à ce qui suit.

Résumé

On m'a dit: «Faites vos propres annotations!» Et j'ai appris que vous pouvez faire vos propres annotations. Quand je l'ai fait, la classe de modèles est devenue beaucoup plus propre et plus facile à voir. J'ai pensé que c'était un mérite qu'il soit devenu plus facile de comprendre quel type de validation était appliqué à chacun. L'implémentation des annotations n'a pas été trop difficile, mais il m'a fallu un certain temps pour réaliser que cela ne fonctionnerait pas sans les «@ Validated» et «@ Valid» dans le Controller et les classes qui utilisent les annotations.

Matériel de référence

Démarrez avec Java EE 7 (23) - Bases de la validation de Bean http://enterprisegeeks.hatenablog.com/entry/2016/02/15/072944

Démarrez avec Java EE 7 (24) - Créez des contraintes personnalisées avec Bean Validation http://enterprisegeeks.hatenablog.com/entry/2016/02/29/072811

Détails fonctionnels de TERASOLUNA Global Framework --5.5 Vérification des entrées https://terasolunaorg.github.io/guideline/public_review/ArchitectureInDetail/Validation.html#validation-basic-validation

Recommended Posts

[Java] Création d'annotations originales
Histoire des annotations Java
[Java] Annotation
[Java] Annotation
création de fichier java
création de répertoire java
[Java] Présentation de Java
Création automatique du rapport de résultat du test unitaire Java
Collection expirée de java
Caractéristiques prévues de Java
[Java] Importance de serialVersionUID
Eclipse ~ Création de projet Java ~
Utiliser l'annotation de marqueur d'origine
NIO.2 examen de Java
Avis sur Java Shilber
java --Unification des commentaires
java (mérites du polymorphisme)
Examen NIO de Java
[Java] Trois fonctionnalités de Java
Résumé du support Java 2018
Création de Java Discord Bot
[Java] Création d'un programme de calcul 1
[Session d'étude interne] Bases de l'annotation Java (2017/11/02) ~ En construction ~
Créer un multi-projet Java avec Gradle
À propos des instances Java
[Java] Utilisation de Mirage-Basic de SQL
[Java] Pratique de la gestion des exceptions [Exception]
[Java11] Résumé du flux -Avantages du flux-
Principes de base de l'utilisation des caractères (Java)
java learning day 4
[Java] Compréhension débutante de Servlet-①
Java fin du mois plusMonths
[Java] Résumé des expressions régulières
[Java] Résumé des opérateurs (opérateur)
[Java] Implémentation du réseau Faistel
[Java] Comparateur de la classe Collection
Résumé des bases du langage Java
Résumé de la classe Java Math
Énumération de toutes les combinaisons Java
java (héritage du principe is-a)
Avantages et inconvénients de Java
Avantages de la méthode statique Java
[Java] Résumé de la syntaxe de contrôle
Implémentation Java de tri-tree
Résumé du traitement des erreurs Java
[Java] Résumé des modèles de conception
[Java] Résumé des opérations mathématiques
[Lire Java efficace] Chapitre 2 Item 5 "Eviter la création d'objets inutiles"
[Java] Comparaison de vitesse de combinaison de chaînes
Pensez à une stratégie de mise à jour Java
[Java] Supprimer les éléments de la liste
[Pour les débutants] Résumé du constructeur java
Diverses méthodes de la classe Java String
Cause fondamentale du bogue du framework Java
À propos de Biocontainers fastqc et Java
[Édition Java] Histoire de la sérialisation
À propos de Lambda, Stream, LocalDate de Java8
Création de l'environnement de développement Play Framework 2.6 (Java)
Lire CSV en Java (annotation Super CSV)