MessageSource Spring: NotSerializableException - java

I'm using MessageSource to implement Internationalization in Spring.
I have something like this.
In my Config class:
#Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setUseCodeAsDefaultMessage(true);
return messageSource;
}
My Spring Bean
#Component
class MyClass implements Serializable {
#Autowired(required = true)
private MessageSource messages;
}
When I run my Project I get this Exception:
Caused by: java.io.NotSerializableException: org.springframework.context.support.ReloadableResourceBundleMessageSource
Can SomeOne please guides me how to resolve this.

As per the information you have provided here, the problem is with your ReloadableResourceBundleMessageSource class as it does not implement Serializable interface.
This causes by your class MyClass implements Serializable as variables in a Serializable class should be either Serializable or transient.
So according to your class either your ReloadableResourceBundleMessageSource class should implement Serializable interface or in your MyClass, the variable should as follows
#Autowired(required=true)
private transient MessageSource messages;
Hope it helps

Related

Validation errors not picked up from resource file

I followed this link to implement a domain validation. However when I attempt to move the messages into a properties file, it doesn't work. I feel like it might be an issue with my validator implementation but can't quite figure out what is wrong. I followed a Baeldung article for this. The output doesn't get parsed and instead is displayed as "{modeltype.size.max}".
My domain object property looks like this:
#Column(name = "MODEL_TYPE")
#Size(max = 20, message = "{modeltype.size.max}")
private String modelType;
I also defined Beans for both the MessageSource & LocalValidatorFactoryBean like so:
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Bean
public LocalValidatorFactoryBean getValidator() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource());
return bean;
}
My domain-specific validator method defined inside of the domain itself and called in the constructor:
private void validate(Equipment equipment) {
EntityValidator<Equipment> equipmentEntityValidator =
new AbstractEntityValidator<>(Validation
.buildDefaultValidatorFactory()
.getValidator());
Set<ConstraintViolation<Equipment>> failedValidations =
equipmentEntityValidator.validate(equipment);
List<String> failedValidationMessages = new ArrayList<>();
failedValidations.forEach(failedValidation -> failedValidationMessages.add(failedValidation.getMessage()));
if (!failedValidationMessages.isEmpty()) throw new ValidationException(String.join(",", failedValidationMessages));
}
This exception is then handled inside of the GlobalExceptionHandler and part of the response DTO are the constraint violations.

MessageSource doesn't reload properties file

There is a messageSource Bean:
#Bean
public MessageSource messageSource(){
ReloadableResourceBundleMessageSource messageSource=new ReloadableResourceBundleMessageSource();
messageSource.setDefaultEncoding("UTF-8");
messageSource.setBasenames("classpath:/messages/messages");
return messageSource;
}
I have read somewhere that If I use ReloadableResourceBundleMessageSource messageSource shouldn't be cached and everytime look into the properties file if theere is particular string. Sadly with bean created that way It doesn't work. After compiling If I add some properties Spring Boot won't find it.
Properties file is in /resources/messages/messages.properties and /resources/messages/messages_en.properties .
Try this solution.
First: configure the bean in your web configuration as shown below.
#Bean
public MessageSource messageSource () {
ReloadableResourceBundleMessageSourceExt messageResource =
new ReloadableResourceBundleMessageSourceExt();
messageResource.setAlwaysUseMessageFormat(false);
messageResource.setBasenames("classpath:messages");
messageResource.setDefaultEncoding(CHARACTER_ENCODING);
messageResource.setFallbackToSystemLocale(true);
messageResource.setUseCodeAsDefaultMessage(false);
messageResource.setCacheSeconds(1); // by default it set to -1 which means cache
// forever messageSourse.
// set 0 to check reload messeageSource on
// every getMessageSource request but reload
// only those files which last modified
// timestamp is changed.
// value greater than 1 is treated as the
// time interval between reload.
return messageResource;
}
Second: create a class which extends ReloadableResourceBundleMessageSource to expose the protected method of its inner class as shown below.
public class ReloadableResourceBundleMessageSourceExt extends ReloadableResourceBundleMessageSource {
public Properties getPropertiesByFileName(String fileName){
return super.getProperties(fileName).getProperties();
}
}
Third: Now Autowired the bean like this.
#Service
public class MyMessagesBundleService {
final private String fileName = "classpath:messages";
#Autowired
ReloadableResourceBundleMessageSourceExt messageSource;
Properties properties = messageSource.getPropertiesByFileName(this.fileName);
// now change the properties and saved it.
// after saved call clear cache and get again.
messageSource.clearCache();
}

How to inject MessageSource resource bundle with Spring?

Hi have two different message bundles. How can I directly inject them into a spring bean MessageSource?
The following does not work:
#Resource(name = "${messages_one_EB.properties}")
private MessageSource messageSourceOne;
#Resource(name = "${messages_two_EN.properties}")
private MessageSource messageSourceTwo;
Result: java.lang.IllegalArgumentException: Could not resolve placeholder 'messages_one_EB.properties'
Probably it works similar, but how? I could not find any example in the docs.
Both bundles are placed under src/main/resources/
I guess you can declare 2 different beans for your message sources and then inject them by name:
#Bean
public MessageSource messageSource1() {
final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:i18n/messages1");
messageSource.setFallbackToSystemLocale(false);
messageSource.setCacheSeconds(0);
return messageSource;
}
#Bean
public MessageSource messageSource2() {
final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:i18n/messages2");
messageSource.setFallbackToSystemLocale(false);
messageSource.setCacheSeconds(0);
return messageSource;
}
Then in your class:
#Resource(name = "messageSource1")
private MessageSource messageSourceOne;
#Resource(name = "messageSource2")
private MessageSource messageSourceTwo;

Spring-boot ReloadableResourceBundleMessageSource not working

I have created a class TestReloadableResourceBundleMessageSource by extending ReloadableResourceBundleMessageSource in my application and implemented like this.
public class TestReloadableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {
//....
}
#Bean
public TestReloadableResourceBundleMessageSource messageSource() {
String messagesPath = "C:/messages";
TestReloadableResourceBundleMessageSource messageSource = new TestReloadableResourceBundleMessageSource();
messageSource.setBasename("file:" + messagesPath);
messageSource.setCacheSeconds(0);
messageSource.setDefaultEncoding(Charsets.UTF_8.name());
return messageSource;
}
But when I'm changing the properties file values, save and reload the page I'm getting the old values not new values without restarting the server.
My properties files are not in class path.
What could be reason and how can I reload it. Any solution will be appreciated.
I'm using spring-boot 1.4.4.RELEASE .
Below code is working for me.
#Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
String messageFolderPath = propertyLocation + "/" + "i18n";
resource.setBasename("file:"+messageFolderPath+"/messages");
resource.setDefaultEncoding("UTF-8");
resource.setCacheSeconds(10);
return resource;
}

Spring 3.1: How do I inject a bean created in a different configuration class

I'm just setting up a web application using Spring 3.1 and I'm trying to do this by using java configuration.
I have two configuration classes "AppConfig" (general bean definitions) and "WebConfig" (Spring MVC configuration). How can I reference a bean that has been declared in AppConfig in the WebConfig class?
Below, the validator in the AppConfig configuration class should use the messageSource fromn WebConfig.
AppConfig:
#Configuration
#ComponentScan(basePackages = { "com.example" })
public class AppConfig {
#Bean
public Validator validator() {
final LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
return validator;
}
}
WebConfig:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.example.common.web", "com.example.web" })
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public ReloadableResourceBundleMessageSource messageSource() {
final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
return messageSource;
}
}
When I want to reference a bean from the same configuration class, I'd just call its setup method, but I obviously cannot do this when the bean is declared in another class.
Your advice will be greatly appreciated!
Configurations are beans, too, so you can use #Autowired
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
private Validator validator;
...
}
There are two ways to do so:
public class WebConfig {
#Autowired
AppConfig appconfig;
...
}
or, as Aaron Digulla mentioned:
public class WebConfig {
#Autowired
Validator validator;
...
}
I prefer the first form, with one autowiring you can access the whole configuration, and then you can access its beans, by calling theNewBean.setValidator(appConfig.validator());.
I think Aaron Digulla and Amir Pashazadeh are both correct but there is also another annotation since JSR 330 was introduced. You can also use #Inject
#Inject
private Validator validator;
http://docs.spring.io/spring/docs/3.0.x/reference/beans.html#beans-autowired-annotation

Categories

Resources