milletron
milletron

Reputation: 380

Gracefully handling ConstraintValidationExceptions in Hibernate

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.

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

Answers (2)

Matt
Matt

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

Affe
Affe

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

Related Questions