Yes, I found a solution, but the annoying thing is that is doesn't work the same all the time. I have both seam and struts apps that needed this and you have to tweak the while loop in the getViolatedConstraintName(). Also I am doing this for postgres. Your milage will vary for other db's I am sure
Code:
import org.hibernate.exception.ConstraintViolationException;
import org.postgresql.util.PSQLException;
/**
*
* @author turekg
*/
public class ExceptionUtils {
/**
* Gets the name of the violated constraint. Note call hierarchy is different than Struts' !
*
* @param ex RuntimeException
* @return constraint name
*
*/
public static String getViolatedConstraintName(Throwable t) {
Throwable cause = t;
while (cause != null) {
if (cause instanceof PSQLException) {
break;
}
cause = cause.getCause();
}
//We are now dealing with a ConstraintViolationException
PSQLException psqlException = (PSQLException) cause;
int sqlState = Integer.valueOf(psqlException.getSQLState()).intValue();
switch (sqlState) {
// CHECK VIOLATION
case 23514: return extractUsingTemplate("violates check constraint \"","\"", psqlException.getMessage());
// UNIQUE VIOLATION
case 23505: return extractUsingTemplate("violates unique constraint \"","\"", psqlException.getMessage());
// FOREIGN KEY VIOLATION
case 23503: return extractUsingTemplate("violates foreign key constraint \"","\"", psqlException.getMessage());
// NOT NULL VIOLATION
case 23502: return extractUsingTemplate("null value in column \"","\" violates not-null constraint", psqlException.getMessage());
// TODO: RESTRICT VIOLATION
case 23001: return null;
// ALL OTHER
default: return null;
}
}
public static boolean isViolatedConstraint(Throwable t) {
Throwable cause = t;
while (cause != null) {
if (cause instanceof ConstraintViolationException) {
return true;
}
cause = cause.getCause();
}
return false;
}
/**
* Extracts the constraint name based on a template (i.e.,
* <i>templateStart</i><b>constraintName</b><i>templateEnd</i>).
*
* @param templateStart
* The pattern denoting the start of the constraint name within the
* message.
* @param templateEnd
* The pattern denoting the end of the constraint name within the
* message.
* @param message
* The templated error message containing the constraint name.
* @return The found constraint name, or null.
*/
private static String extractUsingTemplate(String templateStart, String templateEnd, String message) {
int templateStartPosition = message.indexOf(templateStart);
if (templateStartPosition < 0) {
return null;
}
int start = templateStartPosition + templateStart.length();
int end = message.indexOf(templateEnd, start);
if (end < 0) {
end = message.length();
}
return message.substring(start, end);
}
}