Why I'm getting org.springframework.context.NoSuchMessageException in spring boot? - spring

I'm having properties/messages file name:
messages_en.properties
And I have the property inside:
country.AF.name=Afghanistan
here is the messages class:
#ApplicationScope
#Configuration
#Slf4j
public class Messages {
private ResourceBundleMessageSource messageSource;
private MessageSourceAccessor accessor;
#PostConstruct
private void init() {
messageSource();
accessor = new MessageSourceAccessor(messageSource, Locale.ENGLISH);
log.info("Messages initialized");
}
public String get(String code) {
return accessor.getMessage(code);
}
public void messageSource() {
messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("classpath:messages_en.properties");
messageSource.setUseCodeAsDefaultMessage(true);
}
The full error I'm getting is as follow:
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770) ~[jackson-databind-2.12.3.jar:2.12.3]
Postman show wrong results, I need to get all the countries:

Did you add the below things message Sources bean configuration
messageSource
.setBasename("classpath:messages_en.properties")

Related

Spring boot properties that depend on other properties

Do we have anyway where we can define one property is dependent on the other property?
messages.properties
product.name=XYZ
product.title=XYZ title
I have already tried the below one but its not working
product.name=XYZ
product.title=${product.name} title
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource =
new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Component
public class Messages {
#Autowired
private MessageSource messageSource;
private MessageSourceAccessor accessor;
#PostConstruct
private void init() {
accessor = new MessageSourceAccessor(messageSource);
}
public String get(String code, #Nullable Object[] args) {
return accessor.getMessage(code, args);
}
public String get(String code) {
return accessor.getMessage(code);
}
}

How to solve `No message found under code 'good.morning.message' for locale 'us'`?

I'm trying to test a internationalization but I keep getting the message "No message found under code 'good.morning.message' for locale 'us'." each time I make a GET request.
I'm using Netbeans IDE for my project. Below are my codes
#SpringBootApplication
public class RestfulWebServicesApplication {
public static void main(String[] args) {
SpringApplication.run(RestfulWebServicesApplication.class, args);
}
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.US);
return localeResolver;
}
#Bean
public ReloadableResourceBundleMessageSource bundleMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
ControllerClass
#RestController
public class HelloWorldController {
#Autowired
private MessageSource messageSource;
#GetMapping("/hello-world-internationalized")
public String helloWorldInternationalized(#RequestHeader(name="Accept-Language", required=false) Locale locale) {
return messageSource.getMessage("good.morning.message", null, locale);
//return "Good morning";
}
}
Here's my messages.properties file:
good.morning.message=Good Morning
And here's the link to my folder structure
Change bundleMessageSource() name to messageSource().

Hibernate validation message from properties

I am trying to get a custom message from property file, but I can't.
My configs:
#Bean
public LocalValidatorFactoryBean localValidatorFactoryBean() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource());
return bean;
}
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:/messages/ValidationMessages");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setFallbackToSystemLocale(true);
return messageSource;
}
Class which must be valid:
public class NewUserDto {
#NotEmpty(message = "{NotEmpty.newUserDto.email}")
private String email;
}
Value in my property file: NotEmpty.newUserDto.email = Some value.
But instead Some value I get {NotEmpty.newUserDto.email}, why it is so?
If you are using java configuration. You can refer to the below example:
Delcare a bean like this
public class Employee implements Serializable {
#Email #NotEmpty
private String email;
}
A custom message is located in a file messages.properties
Email.employee.email=Please provide a valid Email address
and this file is added in WebMvcConfigurerAdapter
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
I found this example from the post Spring MVC Form Validation Annotation Example
If I understood correctly, you are trying to inject a String message from properties file, which in it, you have an entry of:
NotEmpty.newUserDto.email
And it got a value that should act as your message error in case of bean validation failure.
In this case:
First, use expression language to inject the property. like this:
#Component
public class NewUserDto {
#Value("${NotEmpty.newUserDto.email}")
private String msg;
#NotEmpty(message = msg)
private String email;
}
Don't forget to annotate your class with #Component annotation and turn it to bean in order to do this #Value injection. of course, you'll have to add to your configuration file the next:
<context:component-scan base-package="package.to.NewUserDto" />
You can try to do it directly, like this:
#Component
public class NewUserDto {
#NotEmpty(message = #Value("${NotEmpty.newUserDto.email}"))
private String email;
}

Spring 4 & Hibernate 5 validator messageSource does not work

I can't get use to work hibernate validation 5.1.0.Final with Spring MVC 4.2.5.RELEASE.
My WebConfig:
#Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
return validator;
}
#Bean
#Autowired
public MethodValidationPostProcessor getValidationPostProcessor(LocalValidatorFactoryBean validator) {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setValidator(validator);
return processor;
}
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/messages");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setUseCodeAsDefaultMessage(true);
return messageSource;
}
#Override
public Validator getValidator() {
return validator();
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor l = new LocaleChangeInterceptor();
l.setParamName("lang");
return l;
}
#Bean
public SessionLocaleResolver localeResolver(){
SessionLocaleResolver s = new SessionLocaleResolver();
s.setDefaultLocale(Locale.ENGLISH);
return s;
}
I have an ExceptionHanlder which gets validation messages and push it back as a json:
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
#ExceptionHandler(ConstraintViolationException.class)
#ResponseBody
public ValidationError handleConstraintViolation(final ConstraintViolationException exception) {
ValidationError v = new ValidationError();
exception.getConstraintViolations().forEach(violation -> {
v.addError(violation.getPropertyPath().toString(), violation.getMessage());
});
logger.warn(exception, exception);
return v;
}
I have 3 files in src/main/resources/i18n/: messages_en_EN.properties, messages_pl_PL.properties, messages.properties.
My model class with validation has one validated parameter:
#Column(name = "VALUE_", nullable = false)
#Email(message = "{Email.contractorContactEmail.value}")
#NotNull(message = "{NotNull.contractorContactEmail.value}")
private String value;
What I see is that hibernate validator look into classpath:ValidationMessages properties not into my spring message source. It may be ok for me but Hibernate does not want to translate those messages - locale is always server default. What am I doing wrong?? How can I fix it?
PS. In controller I use #org.springframework.validation.annotation.Validated.
PS2. I am sure that my messageSource is working correctly because if I add this code into ExceptionHandler it translates perfectly but I know that it is bad practice.
exception.getConstraintViolations().forEach(violation -> {
String messageTemplate = violation.getMessageTemplate();
if (messageTemplate.startsWith("{") && messageTemplate.endsWith("}")) {
String key = StringUtils.substring(messageTemplate, 1, messageTemplate.length() - 1);
v.addError(violation.getPropertyPath().toString(), messageSource.getMessage(key, null, LocaleContextHolder.getLocale()));
}
});
What I can tell you right away, judging from your configuration, your messages are in the wrong place - you've configured the message source to look at i18/messages but your messages are in the classpath root. So, your message source definition should look like:
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setUseCodeAsDefaultMessage(true);
return messageSource;
}
Aside from that, the rest of the configuration looks pretty much okay. I'm guessing that you're using the WebMvcConfigurerAdapter class?
EDIT:
For future reader's reference, the issue was not configuration-related, JPA entity was missing a #Valid annotation on a #OneToMany field so controller-level validation failed to pick it up and Hibernate's JPA validator used default messages.

Spring MockMvc Passing Nested Form Parameters

I have the following form
public class MyForm {
private Account account;
}
public class Account {
private String firstName;
}
How do I pass firstName parameter?
(The following approach does not work)
mockMvc.perform(post("/xyz")
.param("account.firstName", "John"))
.andExpect(model().hasErrors())
.andExpect(view().name("/xyz"))
.andExpect(status().isOk())
Finally I resolved this issue. Since I am using standalone setup I had to define validator and messagesource.
void setupTest() {
MockitoAnnotations.initMocks(this)
this.mockMvc = MockMvcBuilders.standaloneSetup(getController())
.setValidator(getValidator())
.alwaysDo(MockMvcResultHandlers.print())
.build()
}
private MessageSource getMessageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
messageSource.setUseCodeAsDefaultMessage(true);
return messageSource;
}
private LocalValidatorFactoryBean getValidator() {
def validator = new LocalValidatorFactoryBean()
validator.setValidationMessageSource(getMessageSource());
return validator;
}

Resources