I am fairly new to JPA and want to find best practices when handling persistence exceptions from JPA for things like say, unique constraint violations which can be addressed by the user. There are tons of examples on how to write JPA apps, but almost nothing on how to hand exceptions kicked out by them. :/
For example registering a user, the person enters an email address that is already in active use by the system and gets a constraint violation:
try {
em.persist(credentials);
} catch (javax.persistence.PersistenceException ex) {
which produces this error when a duplicate email is added:
WARNING: SQL Error: 0, SQLState: 23505
SEVERE: ERROR: duplicate key value violates unique constraint "EMAIL_UQ_IDX"
Detail: Key (email)=([email protected]) already exists.
How can I get a meaningful answer back to the user? For example something like: Oops looks like someone is using that email address already, are you sure you haven't registered before? Is there a facility built in to parse this or will I need to run regexes against the exception message in a (possibly a series of) if statement(s)?
And what about if it is caught on the business tier... what are best practices for kicking it up to the presentation tier... like I said before, so that a 'nice' message can be provided for the user.
Added for clarity: Just so people know, I had, have, and am still looking at all the different types of persistence exceptions, and here is some of the research I've been doing I didn't include with the "try statement" example I included above:
try {
em.persist(credentials);
} catch (javax.persistence.PersistenceException ex) {
System.out.println("EXCEPTION CLASS NAME: " + ex.getClass().getName().toString());
System.out.println("THROWABLE CLASS NAME: " + ex.getCause().getClass().getName().toString());
Throwable th = ex.getCause();
System.out.println("THROWABLE INFO: " + th.getCause().toString());
Logger.getLogger(CredentialsControllerImpl.class
.getName()).log(Level.INFO, "Credentials Controller "
+ "persistence exception "
+ "EXCEPTION STRING: {0}", ex.toString());
Logger.getLogger(CredentialsControllerImpl.class
.getName()).log(Level.INFO, "Credentials Controller "
+ "persistence exception "
+ "THROWABLE MESSAGE: {0}", th.getMessage());
Logger.getLogger(CredentialsControllerImpl.class
.getName()).log(Level.INFO, "Credentials Controller "
+ "persistence exceptions "
+ "THROWABLE STRING: {0}", th.toString());
}
:)
You typically don't use the low-level exceptions to do that.
Instead, you explicitely check that the email is available (using a query), and perist the email only if it doesn't exist.
Sure, there could be a race condition if two threads do the same check in parallel, but it will be extremely rare, and the database constraint is there to guarantee the uniqueness.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With