If your requirement can be satisfied by interpolating hibernate messages, so you can create/name your *property file like that:
ValidationMessages.properties
And inside that:
javax.validation.constraints.NotNull.message = CUSTOMIZED MESSAGE WHEN NOTNULL is violated!
Hibernate by default searches a ResourceBundle named ValidationMessages. Also a locale might be involved: ValidationMessages_en, ValidationMessages_de, <..>
Hibernate will provide your customized message through interpolatedMessage parameter, so all ConstraintViolationException relevant information (included your message ) will be showed. So you message will be a part of real exception. Some unwieldy information will be provided!
If you want to make your custom exception (without default ConstraintViolationException behavior) check this out:
Using GenericDao concept, consider the following
public void saveOrUpdate(IEntity<?> entity) {
try {
if(entity.getId == null) {
em.persist(entity);
} else {
em.merge(entity)l
}
} catch(ConstraintViolationException cve) {
throw new ConstraintViolationEx(constructViolationMessage(cve.getConstraintViolations()));
}
}
private String constructMessage(Set<ConstraintViolation<?>> pConstraintViolations) {
StringBuilder customMessages = new StringBuilder();
for(ConstraintViolation<?> violation : pConstraintViolations) {
String targetAnnotation = violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName();
if(supportsCustomMessage(targetAnnotation)) {
applyMessage(violation, targetAnnotation, customMessages);
} else {
// do something with not customized constraints' messages e.g. append it to existing container
}
}
return customMessages.toString();
}
private void applyMessage(ConstraintViolation<?> pViolation, String pTargetAnnotation, StringBuilder pCustomMessages) {
String targetClass = pViolation.getRootBean().getClass().getName();
String targetField = pViolation.getPropertyPath().toString();
pCustomMessages.append(MessageFormat.format(getMessageByAnnotation(pTargetAnnotation), targetClass, targetField));
pCustomMessages.append(System.getProperty("line.separator"));
}
private String getBundleKey() {
return "ValidationMessages"; //FIXME: hardcoded - implement your true key
}
private String getMessageByAnnotation(String pTargetAnnotation) {
ResourceBundle messages = ResourceBundle.getBundle(getBundleKey());
switch(pTargetAnnotation) {
case "NotNull":
return messages.getString(pTargetAnnotation + ".message");
default:
return "";
}
}
private boolean supportsCustomMessage(String pTargetAnnotation) {
return customizedConstraintsTypes.contains(pTargetAnnotation);
}
Produced result:
test.model.exceptions.ConstraintViolationEx
test.model.Person : name cannot be null
test.model.Person : surname cannot be null
A hibernate ConstraintViolation provides relevant information about root class and restricted field. As you see, it applies for all hibernate supported constraints, so you need to check if current annotation can be customized by supportsCustomMessage(<..>)! If it can (it's up to you), you should get appropriate message by constraint annotation doing `getMessageByAnnotation(<..>)'.
All you need to do is implement not supported constraints logic. For example it can append it's cause message or interpolated with default message (and true exception goes to *log file)