I have a situation using hibernate persistence with hibernate validations and although I've thought of a few hack-ish approaches, I don't know the best way to solve this problem using hibernate persistence and validation.
Simply put, I have a User object and I want to persist it. But before I persist it I want to validate it. Pretty standard stuff.
Now, a User object has a password and we have rules about valid passwords. Eg: minimum of 8 characters, include at least 1 number, etc...I want to validate these things.
But when I persist I need to encrypt/salt/hash the password. But after I do the salting/hashing there is obviously no reasonably way to do the above validations on the password.
So, I thought I could use the @PrePersist and @PreUpdate annotations for this. My thought was in the User class I have a method called onCreate(). I tagged it with @PrePersist and I do something like this (I have something similar for onUpdate()):
@PrePersist
protected void onCreate() {
encryptPassword();
}
I thought that when I call entityManager.persist() it would first call the validations, then call onCreate() and then persist. So the validations would validate the original, non-salted/hashed password. And the salting/hashing would happen later.
When I ran my tests and debugged though, I found that methods tagged with @PrePersist get called before validations run meaning I can't validate my password anymore.
How do I hook the salting/hashing of the password correctly into the entityManager.persist() lifecycle so that I can validate correctly and after that salt and hash and finally persist?
Thanks.
Use two bean properties, one for persistence and the other for validation / conversion. Something like this:
@Entity
@MyCustomConstraint(...)
public class User implements Serializable {
// place persistence annotations here, for example
@Lob @Column(...)
private byte[] hashedPassword;
// place validation constraints here, for example
@Size(min = 8, max = 16)
@Transient
private String password;
public byte[] getHashedPassword() {
return this.hashedPassword;
}
protected void setHashedPassword(byte[] hashedPassword) {
this.hashedPassword = hashedPassword;
}
public void setPassword(String password) {
this.password = password;
this.setHashedPassword(this.hashAndSaltMyPassword(this.password));
}
protected String getPassword() {
return this.password;
}
protected byte[] hashAndSaltMyPassword(String password) {
...
}
}
Done.