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 !
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 .