web-dev-qa-db-fra.com

classe de données kotlin + validation du bean jsr 303

J'essaie de faire travailler Kotlin avec la validation jsr 303 sur un projet Spring-Data-Rest.

Étant donné la déclaration de classe de données suivante:

@Entity data class User(
    @Id 
    @GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
    var id: Long? = null,

    @Size(min=5, max=15)
    val name: String
)

L'annotation @Size n'a aucun effet ici, ce qui me permet d'enregistrer un utilisateur avec un nom de 1 caractère.
Cela fonctionne bien lors de l'exécution du même exemple mais dans une classe Java au lieu de Kotlin.

Cela me fait penser à un problème Kotlin.

Merci d'avance pour votre aide !

35
pellenberger

Vous devez utiliser Annotation use-site cibles car la valeur par défaut pour une propriété déclarée dans le constructeur est de cibler l'annotation sur le paramètre constructeur au lieu de getter (qui sera vu par les hôtes compatibles JavaBeans) quand plusieurs options sont disponibles. L'utilisation d'une classe data peut également être inappropriée ici ( voir note à la fin).

@Entity data class User(
    @Id
    @GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
    var id: Long? = null,

    @get:Size(min=5, max=15) // added annotation use-site target here
    val name: String
)

La cible property des documents de Kotlin peut sembler tentante, mais elle ne peut être vue que de Kotlin et non de Java. Généralement, get fait l'affaire, et il n'est pas nécessaire sur le bean set.

Les documents décrivent le processus comme:

Si vous ne spécifiez pas de cible d'utilisation du site, la cible est choisie en fonction de l'annotation @Target de l'annotation utilisée. S'il existe plusieurs cibles applicables, la première cible applicable de la liste suivante est utilisée:

  • param
  • propriété
  • champ

Et le @Size l'annotation est:

@Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER})

Par conséquent, puisque PARAMETER est une cible valide et que plusieurs cibles sont disponibles (paramètre, champ, méthode [get/set]), il choisit PARAMETER qui n'est pas ce que vous voulez. Par conséquent, pour qu'un hôte JavaBean voit la propriété, il recherchera le getter (les propriétés sont définies par le getter/setter et non par le champ de support).

Dans l'un des exemples Java , il montre:

public class Book {
    private String title;
    private String description;

    // ...

    @NotEmpty(groups={FirstLevelCheck.class, Default.class})
    @Size(max=30)
    public String getTitle() {
        return title;
    }

    // ...
}

Ce qui correspond à notre utilisation de l'avoir sur le getter. S'il devait se trouver sur le terrain comme le montrent certaines annotations de validation, consultez la cible field use-site. Ou si le champ doit également être accessible au public, voir @ JvmField annotation dans Kotlin.

REMARQUE: Comme mentionné dans les notes des autres, vous devriez probablement envisager de NE PAS utiliser un data classe pour les entités si elles utilisent un ID généré automatiquement car il n'existera pas pour les nouveaux objets comme pour les objets récupérés; et une classe data générera equals et hashCode pour inclure tous les champs, y compris ceux qu'elle ne devrait pas. Vous pouvez lire des conseils à ce sujet dans les documents Hibernate .

51
Jayson Minard