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
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.
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.
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.
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.
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
.
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