Reputation: 380
There are a LOT of posts on S.O. an other sites related to performing Hibernate validation, catching exceptions, and so forth. However, all of them put me up against some very unideal design choices in the situation described below. This seems like such a common situation I can't believe there's not a clean solution.
Using the three in concert doesn't seem to work.
When an exception occurs Hibernate won't let you commit a transaction. I'll get a constraint violation exception anytime I have an invalid object. I can't find authoritatively if a ConstraintViolationException is included in this, or treated as a special case[1], however...
I seem to be able to proceed if I catch a ConstraintViolationException and move on to the next object, but Hibernate complains when I try to flush or commit the transaction because I have objects which have not been assigned an id (by the database).
What does one do?
To be concrete, I have lots (10,000+) objects, a small handful of which are always going to be invalid.
@Entity
public class myPojo implements Serializable {
@Id
@GeneratedValue
private long id;
@NotBlank
private String anotherString;
@NotNull
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
@NotNull
@Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
@NotNull
@Temporal(TemporalType.TIMESTAMP)
private Date postedDate;
@PrePersist
protected void onPrePersist() {
this.createdAt = new Date();
this.updatedAt = this.createdAt;
if (this.postedDate == null)
this.postedDate = this.createdAt;
}
}
I want to save this function, and catch any objects with constraint violations:
void saveResource(MyPojo myPojp) {
try {
session.saveOrUpdate(mypojo);
}
catch (final ConstraintViolationException ex) {
System.err.println("Could not save " + myPojo + " because " +
this.getValidationErrors(myPojo));
}
}
Where getValidationErrors() returns a String of all the ConstraintViolations that are found by manually creating and using a validation factory.
The only other possibilities I know of are performing a single transaction around each save (which seems like a bad idea since if real exceptions do occur I don't want ANY of the items to persist) or perhaps writing a custom validator to be run manually before I call save that calls the prepersist hooks (maintainability nightmare!).
[1]: I know that's a crummy reference, but I've been doing so much reading I can't find it again. Would be happy for someone to clarify in more technical details what errors cause a transaction to become invalid vs are recoverable.
Upvotes: 2
Views: 2810
Reputation: 11805
public interface PersistValidationGroup { }
@NotBlank
private String anotherString;
@NotNull(groups={PersistValidationGroup.class})
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
@NotNull(groups={PersistValidationGroup.class})
@Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
@NotNull(groups={PersistValidationGroup.class})
@Temporal(TemporalType.TIMESTAMP)
private Date postedDate;
Then, when you validate manually:
validator.validate(object, javax.validation.groups.Default.class);
At this point, only those fields marked with the Default validation group (which by the way is what is used if you leave the "groups" attribute blank) will be validated. Anything in the PersistValidationGroup would not be validated.
However, hibernate will call like this I believe:
validator.validate(object);
So all groups would be validated.
Upvotes: 2
Reputation: 47984
Thought 1: why put application level validation annotations on fields you're managing yourself in the PrePersist, that aren't set by users?
Thought 2: You could use Validation groups so that you can pre-check only those fields that are set at the user level and ignore the system managed ones.
Upvotes: 3