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.
- I want to leverage Javax's (and Hibernate's) validation annotations,
- I want to correct, or throw out, invalid objects,
- I want to leverage javax's PrePersist, etc annotations to handle repetitive or time-based actions on my objects.
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).
- I thought about trying to set the object to null or using session.evict(myObject) without success to "break" the knowledge Hibernate has about the object.
- I could [run the validation "manually"] before I try to save it(http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#d0e2697), at the cost of it being performed twice--which seems silly, but that doesn't call the @PrePersist hooks, leading to erroneous violations.
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.