How to internationalize spring-mvc form error messages? - spring

I want to translate the default error messages for form validation, for example, when I annotate a field as #NotEmpty, I should receive an error like:
may not be empty
when I left the field empty. Now I want this message in other languages, so what should I do in order to translate them? I want this to work with every field annotated with #NotEmpty, and also for other messages...
Thanks!

Spring can hook up into your internationalized error codes I think ...
My validator class extends Validator and implements setting a MessageSource and then can pass in errorCode like below and Im guessing it autolooks it up via the MessageSource set (which i set via a Spring Bean):
public static void rejectIfEmptyOrWhitespace(Errors errors,
String field,
String errorCode,
String defaultMessage)
http://docs.spring.io/spring-framework/docs/4.2.x/javadoc-api/org/springframework/validation/ValidationUtils.html#rejectIfEmptyOrWhitespace-org.springframework.validation.Errors-java.lang.String-java.lang.String-java.lang.String-
Here is a pretty close example to what I have (minus they use LocaleResolver):
http://vardhan-java2java.blogspot.com/2010/08/spring-internationalization-i18n.html

You can add custom messages to #NotEmpty by using it like this:
#NotEmpty( message = "Your error message")

Related

Changing dependency in running spring application

How to change dependency in already deployed application. So when application starts it send notification through email, but at some moment we should be able to change to send notification through sms.
How to do that in Spring Boot?
thats a work for a strategy pattern, it does not have anything to do with spring itself
You should have 2 strategies one for email and one for sms, in each strategy you will autowired the needed bean.
check this link for strategy implementation
https://www.tutorialspoint.com/design_pattern/strategy_pattern.htm
You can define a property in a Singleton bean? let's call it notificationMethod and assign by default EMAIL. (the property could be enum or string or int no matter).
You need a controller method to change the property.
#Autowired
private MyNotificationMethodHolderService service;
#RequestMapping(value = "/changeNotificationMethod")
#ResponseBody
public String change(#RequestParam("methodName") String methodName) {
service.setNotificationMethod (methodName);
}
Your notification service checks the property and sends notification according to the value (Strategy pattern according to comments).
If you need to change method you invoke
<HOST>:<PORT>/context/changeNotificationMethod?methodName=SMS

How to prevent Spring from using default conversion logic when using a Formatter

I wrote a custom Spring formatter (which implements the org.springframework.format.Formatter interface) for converting form input values to BigDecimal values for dollar inputs. The formatter does not accept values with more than two digits after the decimal place. In that case, a ParseException is thrown by the formatter's parse() method.
public class InputDollarBigDecimalFormatter
implements Formatter<BigDecimal>
{
#Override
public BigDecimal parse(String text, Locale locale)
throws ParseException
{
// ...
}
#Override
public String print(BigDecimal amount, Locale locale)
{
// ...
}
}
The formatter is registered so it can be applied using an annotation named #InputDollarBigDecimalFormat.
A field in my form-backing object, to which the formatter is applied, looks like this:
#InputDollarBigDecimalFormat
private BigDecimal price;
The formatter is working fine.
The problem is that when the ParseException is thrown, Spring still attempts to convert the input value to a BigDecimal using the default conversion. This means an input value of 100.123 is still successfully converted to a BigDecimal, even though my custom formatter throws a ParseException.
How can I prevent Spring from converting the input value to a BigDecimal when my custom Formatter has rejected the value by throwing a ParseException?
I'm using Spring 3.1.0.
Spring formatters are documented here.
UPDATE:
After stepping through the code with a debugger, I see that the logic for this is in the org.springframework.beans.TypeConverterDelegate class. Spring is clearly doing this on purpose, so I can see only the following possible solutions:
(1) If possible, un-register the default PropertyEditor for BigDecimal values. It appears Spring registers a org.springframework.beans.propertyeditors.CustomNumberEditor for converting a string to a BigDecimal. Of course, this solution has the downside that the default PropertyEditor would not be available for other BigDecimal fields (that do not use the custom formatter).
(2) Create a Dollar class that wraps a BigDecimal and change the custom formatter to work with the Dollar class. The type of field would also have to change to Dollar. This would be a bit of a nuisance when working with the values.
(3) Perhaps Spring has realized it is incorrect to fall back to the default PropertyEditor when a custom formatter has rejected a value and so this has been changed in a more recent version of Spring. I'm doubtful, but if anyone knows either way, your help would be appreciated.
(4) But perhaps the correct solution is to view the custom formatter as just helping out the default PropertyEditor by allowing more formats. In addtion to limiting the value to two decimal places, my custom formatter also allows for the input value to include a dollar sign and commas. I could leave that logic, but remove the decimal place restriction. Then I could add a custom bean validation (JSR 303) constraint that rejects the value if it does not have exactly two digits after the decimal place (unless it has none). I would just have to annotate my field with the constraint:
#InputDollarBigDecimalFormat
#WholeDollarOrCentsConstraint
private BigDecimal price;
Of course, I would also have to add an error message for the constraint, in addition to the one for the formatter.
If any of these seems like the correct solution to you, feel free to add an answer with your reasoning.
Here's what worked for me. If you have a look in TypeConverterDelegate, the very first thing it does (and also later along as part of the 'fallback conversion' bit) is that it checks if there is a custom PropertyEditor registered for the given type. If there is, it completely bypasses the conversionService part (which is what swallows your exception) and uses the editor instead.
So instead of your suggestion (1), you could try creating your own class that extends
PropertyEditorSupport and register it for BigDecimal (see here for an example of how to do that). You could then throw an IllegalArgumentException in your setAsText method.

How to use different error codes for validation messages?

I have a Spring Boot REST server which should return specific error codes when invalid input is provided. I don't need any i18n here, just plain English error codes like 'missing' is sufficient.
Using Spring Boot with Hibernate Validator, after validation I get a back Spring Errors object.
For each error I can get the code and defaultMessage. For a #NotBlank constraint this would return NotBlank and may not be null resp.
Basically I want to translate this error to just missing as I'm not interested in i18n translation. Also other constraints I want to more REST friendly error codes.
I though to use use a simple messages.properties or ValidationMessages.properties inside src/main/resources but this wouldn't work unfortunately. Note I tried both adding a general NotBlank=missing and specific NotBlank.entity.field=missing properties.
I'm not sure why it's not working... maybe because resolving i18n messages (in jsp world) does not go directly via Spring Errors but through the MessageCodesResolver implementation (just guessing).
Probably I could get the error code from the Spring Error and do a lookup from the message code resolver.
But I wonder why error.getDefaultMessage does not return the appropriate value form the ValidationMessages.properties.
Any suggestion is welcome.
The default message is the message as stated by the programmer. In the case of those JSR-303 annotations probably the ones as Hibernate thought of them. The default message including the code is passed to the MessageSource.getMessage method, which contains a parameter defaultMessage
When you look at the Errors object or actually the ObjectError method you will see that it implements the MessageSourceResolvable interface. This means you can just pass the error, as is, to the MessageSource, including the Locale if you want.
#RequestMapping
public Object foo(#Valid #RequestBody MyObject obj, Errors errors, Locale locale) {
for (ObjectError err : errors.getAllErrors()) {
String msg = messageSource.getMessage(err, locale);
// Do something with msg
}
}
Something like the above should resolve the message. The advantage of using the ObjectError itself is that next to the code you also have the parameters (for #Range or #Min) which you can then use in your message with placeholders.

Custom validation message

I have a problem with validating some data types.
There are int, short, DateTime and so on except string.
Suppose i have following property in my view model class
public int? LineNumber { get; set; }
When i input incorrect value i get mvc error "The value 'balblabl' is not valid for LineNumber."
But what if i want just out something like "Value incorrect"? Or what if i want to use other language? I have no idea how to do it(of course i can use string instead of int but it is painfull workaround)
i already tried dataannotationsextensions [DataAnnotationsExtensions.Integer(ErrorMessage = "Please enter a valid number.")] attribute. It is not working. I cannt to use custom validation attribute because of after binder convertation i get null value in all cases with incorrect value. I just cannt to do my own validation. I can to write my own binder but it looks like a joke. Really i think custom validation message is one of must have featerus and i cannt belive asp.net mvc doesnt has a simple way to do it.
I would like to add another, in my opinion, easy way to add and maintain custom error messages.
using the FluentValidation NuGet package.
It hooks up with mvc pretty easy have a look here
You can easily specify numerous rules for your models and display custom error messages that can use a resource file an example:
public class CreateProductCommandValidator : AbstractValidator<CreateProductCommand>
{
public CreateAgendaPointCommandValidator()
{
RuleFor(cmd => cmd.price)
.NotEmpty()
.WithMessage(Translations.CreateProduct_Price)
}
}
}
Documentation: FluentValidationDocumentation
Those errors are automatically added by the default model binder when it cannot parse the input string into its destination type. They are not like data annotations, where you can specify a resource instead of a harcoded string error message.
However you can use your own resource files, see this other question. Once you have created the resource file, you will update the global.asax for the default model binder to use it:
DefaultModelBinder.ResourceClassKey = "MyResources";
After a custom resource file has been set in the property ResourceClassKey of the default model binder, values will be resolved according to the following criteria (as per the MSDN):
If the property is not set, MVC uses the standard MVC resources.
If the property is set to an invalid class key (such as a resource
file that does not exist), MVC throws an exception.
If the property is set and the class key exists but the resource
names in the file do not exist in the application, MVC uses the
standard MVC resources.
If the property is set and the specified resources are available,
MVC uses the resources in the file.
If you need to know the key values for a particular message check this. For the message The value '{0}' is not valid for {1}., you will need to add a value with the key DefaultModelBinder_ValueInvalid

Using Spring's MessageSource for setting FieldError default messages

After my form backing object is validated I have a BindingResult, which contains a list of FieldError. Each FieldError has a defaultMessage. How is that message set and why doesn't it use my Spring MessageSource? I would like that default message to be derived from my Spring's MessageSource.
EDIT:
I see that the error codes are being set correctly in the FieldError object. It's just the default message in that object is not coming from my MessageSource. For instance, when I enter a string for a field that is an int I want it to get my message from messages.properties:
typeMismatch=Invalid type was entered.
The only way I can get that message is if I take my FieldError object and pass it into the MessageSource manually like so:
messageSource.getMessage(fieldError, null); // This gets my message from messages.properties.
If you're using a Validator, you can specify the keys for the messages in the MessageSource in the Validator implementing class, usually using ValidationUtils methods. Section 6.2 of the Spring documentation has a good example.
Spring will also try to resolve error codes by convention if you're using something other than a Validator like JSR-303 Bean Validation.
Let's say you had a form backing object called 'Address' with an int field called 'zipcode.' If the user entered a string for the zipcode field, by default Spring will use the DefaultMessageCodesResolver and look in the MessageSource for a key called 'typeMismatch.address.zipcode.' If it doesn't find that key, it will try 'typeMismatch.zipcode,' then 'typeMismatch.int,' then 'typeMismatch.'
Or, you can implement your own MessageCodesResolver.

Resources