Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Validation custom messages - field name

Problem: how to get field name in validation messages in Spring

Is there a way I can access the field name in the ValidationMessages.properties file, for example below I tried using {0} but it doesn't work, I've seen it somewhere. I want Spring to dynamically put the field name there so I don't have to repeat it for every class.

public class RegistrationForm {

    @NotEmpty(message = "{NotEmpty}")
    private String email;


    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

ValidationMessages.properties

NotEmpty={0} TEST
like image 811
Greyshack Avatar asked Dec 13 '15 10:12

Greyshack


People also ask

What is the use of @valid annotation in Spring boot?

The @Valid annotation ensures the validation of the whole object. Importantly, it performs the validation of the whole object graph. However, this creates issues for scenarios needing only partial validation. On the other hand, we can use @Validated for group validation, including the above partial validation.

What is MessageSource in Spring?

Overview. MessageSource is a powerful feature available in Spring applications. This helps application developers handle various complex scenarios with writing much extra code, such as environment-specific configuration, internationalization or configurable values.


2 Answers

This is possible if you use the Spring message bundles (i.e. message.properties) instead of ValidationMessages.properties to localize messages.

Using your example, Spring will (in a first pass) try to localize the field name using the following message keys (or codes) in messages.properties:

[RegistrationForm.email,email]

falling back to the field name if nothing is found.

Spring then looks up the localized error message itself using the following keys:

[NotEmpty.RegistrationForm.email,NotEmpty.email,NotEmpty.java.lang.String,NotEmpty]

Note here that NotEmpty has higher priority than java.lang.String,NotEmpty so don't get fooled if you want to customize the message based on the field type.

So if you put the following content in your messages.properties, you'll get the desired behavior:

# for the localized field name (or just email as the key)
RegistrationForm.email=Registration Email Address
# for the localized error message (or use another specific message key)
NotEmpty={0} must not be empty!

From the javadoc of SpringValidatorAdapter#getArgumentsForConstraint():

Return FieldError arguments for a validation error on the given field. Invoked for each violated constraint.

The default implementation returns a first argument indicating the field name (of type DefaultMessageSourceResolvable, with "objectName.field" and "field" as codes). Afterwards, it adds all actual constraint annotation attributes (i.e. excluding "message", "groups" and "payload") in alphabetical order of their attribute names.

Can be overridden to e.g. add further attributes from the constraint descriptor.

While with ValidationMessages.properties you would use {max} to refer to the max attribute of a @Size annotation, with Spring message bundles you would use {1} (because max is the first attribute of @Size when ordered alphabetically).

For more information, you can also see my feature request to ease field name localization.

Appendix: how to find this info?

By stepping in code unfortunately (and this post now!).

To find out which keys are used for localizing the fields the errors, inspect the value of your BindingResult. In your example, you would get this error:

Field error in object 'RegistrationForm' on field 'email': rejected value []; codes [NotEmpty.RegistrationForm.email,NotEmpty.email,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [RegistrationForm.email,email]; arguments []; default message [email]]; default message [may not be empty]

SpringValidatorAdapter#getArgumentsForConstraint() takes care of making the validation annotation attributes values and the field name available for the error message.

like image 131
bernie Avatar answered Oct 02 '22 08:10

bernie


As of Bean Validation 1.1 (JSR-349), there is no exposed API that provides the contraint message interpolator the name of the actual property field. If such functionality did exist, there would still be some interpolation step required in order to convert the exposed property email into something meaningful for display purposes, particularly in a multilingual based application.

The closest you can currently get would be to extend the @NotEmpty annotation and add an attribute to it that allows you to pass the name of the property you desire.

public class RegistrationForm {
   @NotEmpty(label = "Email Address")
   private String email;
}

In your resource bundle, your message could use the {label} place holder to represent the attribute from the constraint.

Of course this won't help the multilingual use case I mentioned above, but it at least gives you the ability to define a label such as First Name for a field you may have defined as firstName.

like image 42
Naros Avatar answered Oct 02 '22 08:10

Naros