2016-03-07 6 views
15

Sto cercando di far funzionare Kotlin con la convalida di jsr 303 su un progetto spring-data-rest.kotlin data class + validazione bean jsr 303

Data la seguente classe di dati declarartion:

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

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

L'annotazione @Size non ha alcun effetto qui, facendomi in grado di salvare un utente con un nome di 1 carattere.
Funziona bene quando si esegue lo stesso esempio ma in una classe Java anziché Kotlin.

Questo mi fa pensare a un problema di Kotlin.

Grazie in anticipo per l'aiuto!

+0

quale dovrebbe essere l'obiettivo dell'annotazione? Parametro costruttore o campo? – voddan

risposta

23

È necessario utilizzare Annotation use-site targets poiché il valore predefinito per una proprietà dichiarata nel costruttore è quello di colpire l'annotazione sul costruttore parametro al posto del getter (che sarà visto da JavaBeans host compatibili) quando ci sono più opzioni disponibili. Anche l'utilizzo di una classe data potrebbe essere inappropriato qui (vedere la nota alla fine).

@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 
) 

Il property bersaglio dalla documentazione Kotlin può sembrare allettante, ma può essere visto solo da Kotlin e non Java. Solitamente lo get fa il trucco e non è necessario sul bean set.

La documentazione descrivono il processo come:

Se non si specifica un target uso in loco, l'obiettivo viene scelto in base al l'annotazione @Target dell'annotazione in uso. Se ci sono più bersagli applicabili, il primo obiettivo applicabile dal seguente elenco viene utilizzato:

  • param
  • proprietà
  • campo

E l'annotazione @Size è:

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

Pertanto dal PARAMETER è un target valido e sono disponibili più destinazioni (parametro, campo, metodo [get/set]) che sceglie PARAMETER che non è ciò che si desidera. Pertanto, affinché un host JavaBean visualizzi la proprietà, cercherà il getter (le proprietà sono definite dal getter/setter e non dal campo di supporto).

In uno dei Java samples, mostra:

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

    // ... 

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

    // ... 
} 

che corrisponde il nostro utilizzo di avere sul getter. Se dovesse essere sul campo come mostrano alcune annotazioni di convalida, vedere la destinazione del sito di utilizzo field. Oppure se il campo deve essere accessibile al pubblico, consulta lo @JvmField annotation in Kotlin.

NOTA:Come accennato nelle note dagli altri, si dovrebbe probabilmente prendere in considerazione non utilizzando una classe data per le entità se usano un ID generato automaticamente dal momento che non esisterà per i nuovi oggetti lo stesso che per il recuperati oggetti; e una classe data genererà equals e hashCode per includere tutti i campi compresi quelli che non dovrebbe. Puoi leggere le indicazioni a riguardo dal Hibernate docs.

+0

Sei rock! Grazie ! È anche possibile utilizzare l'annotazione '@get: Dimensione (min = 5, max = 15)'. – pellenberger

+2

Anche se è la risposta corretta, vale la pena notare che non si dovrebbe usare comunque 'data class' per l'entità. Il motivo è che genererà i metodi 'equals' e' hashCode' usando tutte le proprietà, incluso 'id', che non è il comportamento desiderato per l'entità JPA. Vedi qui: https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html – waste

+0

grazie @waste, ho apportato una modifica per aggiungere la nota direttamente nel risposta. –

Problemi correlati