29

I'm using Hibernate Validator 4.2.0.Final and I'm looking for the simplest way to include class field name in my error message.

What I found is the following thread Using a custom ResourceBundle with Hibernate Validator. According to this I should create my custom annotation for each constraint annotation adding one property to each one.

Is there a cleaner way to achieve this?

The following code:

@Size(max = 5)
private String myField;

produces default error: size must be between 0 and 5.

I would like it to be: myField size must be between 0 and 5.

Dharman
  • 30,962
  • 25
  • 85
  • 135
BartoszMiller
  • 1,245
  • 1
  • 15
  • 24

9 Answers9

34

You can get the name of the field with the getPropertyPath() method from the ConstraintViolation class.

A good default error message can be:

violation.getPropertyPath() + " " + violation.getMessage();

Which will give you "foo may not be null", or "foo.bar may not be null" in the case of nested objects.

brunov
  • 973
  • 8
  • 6
7

If your messages are in .properties file then there is no interpolation variable for accessing property name but one way you can achieve that is

//in ValidationMessages.properties
app.validation.size.msg=size must be between {min} and {max}

@Size(min=10, max=15, message = "myField {app.validation.size.msg})
private String myField;

OR

//in ValidationMessages.properties
app.validation.size.msg=size must be between {min} and {max} but provided ${validatedValue}

@Size(min=10, max=15, message = "myField {app.validation.size.msg})
private String myField;

Reference: message interpolation

user3640709
  • 83
  • 1
  • 9
  • 1
    A better way so that internationalization is supported. //in ValidationMessages.properties app.FieldName=MyField app.validation.size.msg=size must be between {min} and {max} but provided ${validatedValue} @Size(min=10, max=15, message = "{app.FieldName}"+" "+ "{app.validation.size.msg}") private String myField; – Shahbaaz Khan Jun 01 '21 at 04:24
4

I put every field validation message into the properties file, like this:

field.student.name.size.message = Student name size is not valid.

and in the bean, use it like this:

@Size(max = 5, message = "${field.student.name.size.message}")  
private String myField;

I know it isn't a perfect solution, but I also don't find a better way.

Rocky Hu
  • 1,326
  • 4
  • 17
  • 32
2

I am not aware of any generic way but you can define custom error message and include field name in it.

@Size(max = 5, message = "myField size must be between 0 and 5")  
private String myField;
Ajinkya
  • 22,324
  • 33
  • 110
  • 161
1

If validating a REST call in a controller and using a controller advice, you can combine field and default message from MethodArgumentNotValidException like this:

@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception, HttpHeaders headers, HttpStatus status, WebRequest request) {
        String errorMessage = exception
                .getBindingResult()
                .getFieldErrors()
                .stream()
                .map(fieldError -> fieldError.getField() + " " + fieldError.getDefaultMessage())
                .collect(Collectors.joining(", "));


        return new ResponseEntity<>(errorMessage, HttpStatus.BAD_REQUEST);
    }
Oleg
  • 187
  • 3
  • 5
1

A better way so that internationalization is supported.

//in ValidationMessages.properties

app.FieldName=MyField

app.validation.size.msg=size must be between {min} and {max} but provided ${validatedValue}

@Size(min=10, max=15, message = "{app.FieldName}"+" "+ "{app.validation.size.msg}") private String myField;

Shahbaaz Khan
  • 177
  • 3
  • 6
0

use oval this has good number of annotations and possible ways to display messages.

Jigar Parekh
  • 6,163
  • 7
  • 44
  • 64
0

For all those who are looking for a way to access class inside your validator. Putting hibernate annotating on a class level instead of variable level gives you access to a class object (assuming that you have defined a custom validator).

public class myCustomValidator implements ContraintValidator <MyAnnotation, MyAnnotatedClass> {

    public void initialize (...){ ... };

    public boolean isValid (MyAnnotatedClass myAnnotatedClass) {

        // access to elements of your myAnnotatedClass

    }
} 
BartoszMiller
  • 1,245
  • 1
  • 15
  • 24
0

use this method(ex is ConstraintViolationException instance):

Set<ConstraintViolation<?>> set =  ex.getConstraintViolations();
List<ErrorField> errorFields = new ArrayList<>(set.size());
ErrorField field = null;
for (Iterator<ConstraintViolation<?>> iterator = set.iterator();iterator.hasNext(); ) {
    ConstraintViolation<?> next =  iterator.next();
   System.out.println(((PathImpl)next.getPropertyPath())
            .getLeafNode().getName() + "  " +next.getMessage());


}
Stephen.lin
  • 166
  • 1
  • 12