kotlin data class + bean validation jsr 303
Solution 1:
You need to use Annotation use-site targets since the default for a property declared in the constructor is to target the annotation on the constructor parameter instead of the getter (which will be seen by JavaBeans compliant hosts) when there are multiple options available. Also using a data
class might be inappropriate here (see note at end).
@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
)
The property
target from the Kotlin docs may look tempting, but it can only be seen from Kotlin and not Java. Usually get
does the trick, and it is not needed on the bean set
.
The docs describe the process as:
If you don’t specify a use-site target, the target is chosen according to the @Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following list is used:
- param
- property
- field
And the @Size
annotation is:
@Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER})
Therefore since PARAMETER
is a valid target, and multiple targets are available (parameter, field, method [get/set]) it choses PARAMETER
which is not what you want. Therefore for a JavaBean host to see the property it will look for the getter (properties are defined by the getter/setter and not the backing field).
In one of the Java samples, it shows:
public class Book {
private String title;
private String description;
// ...
@NotEmpty(groups={FirstLevelCheck.class, Default.class})
@Size(max=30)
public String getTitle() {
return title;
}
// ...
}
Which matches our usage of having it on the getter. If it were to be on the field like some of the validation annotations show, see the field
use-site target. Or if the field must also be publicly accessible, see the @JvmField annotation in Kotlin.
NOTE: As mentioned in notes from others, you should likely consider NOT using a data
class for entities if they use an auto-generated ID since it will not exist for new objects the same as for retrieved objects; and a data
class will generate equals
and hashCode
to include all fields including the ones it should not. You can read guidance about this from the Hibernate docs.
Solution 2:
Use the @get
or @field
targets for validation annotations. Annotations with the target @param
(first default) and @property
are not supported.
e.g:
From @NotEmpty
To @field:NotEmpty
data class Student(
@field:NotEmpty @field:Size(min= 2, message = "Invalid field") var name: String? = ""
)
GL
- Jayson Minard
- Annotation use site targets