MessageSource doesn't reload properties file - java

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();
}

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.

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;
}

How to read properties file in Controller using annotations only? Spring MVC

How to read properties file in Controller using annotations only?
Properties file contains (env.properties):
document.portal.path=http://flana.gost.com/service
Spring Controller:
#Controller
#RequestMapping("/kap/*")
#SessionAttributes({"user", "KapForm", "activity"})
public class KapController {
#Value("${document.portal.path}")
private String URL;
}
Nothing else is done. In XML, we use to use placeholder, which i am not getting how to introduce in it. So I am getting exception.
Injection of autowired dependencies failed;
You can achieve it in two ways
Option 1
In config class put #PropertySource and define a bean for PropertySourcesPlaceholderConfigurer as below -
#Configuration
#PropertySource("classpath:someFile.properties")
public class SampleConfig {
// other configs...
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Option 2
In config class directly specify the bean for PropertyPlaceholderConfigurer and supply the name of property file as ClassPathResource
#Configuration
public class SampleConfig {
// other configs...
#Bean
public static PropertyPlaceholderConfigurer placeHolderConfigurer(){
PropertyPlaceholderConfigurer placeHolderConfigurer = new PropertyPlaceholderConfigurer();
ClassPathResource[] cpResources = new ClassPathResource[]
{ new ClassPathResource( "someFile.properties" ) };
placeHolderConfigurer.setLocations(cpResources);
placeHolderConfigurer.setIgnoreUnresolvablePlaceholders(true);
return placeHolderConfigurer;
}
}
Do note that the bean definition for place holder need to be static as per java docs (excerpts below)
Special consideration must be taken for #Bean methods that return Spring BeanFactoryPostProcessor (BFPP) types. Because BFPP objects must be instantiated very early in the container lifecycle, they can interfere with processing of annotations such as #Autowired, #Value, and #PostConstruct within #Configuration classes. To avoid these lifecycle issues, mark BFPP-returning #Bean methods as static.
Another way out found is
import org.springframework.context.MessageSource;
#Autowired
private MessageSource messageSource;
cutiePie = messageSource.getMessage("cutie.pie.property", new Object[] {},"cutie.pie.property", LocaleContextHolder.getLocale());

How to avoid getting bean programmatically for Enums?

I have the Enum:
public enum EmployeeErrorCode {
DELETE_SUCCESS,
//... Other enumerators
#Override
public String toString(){
ApplicationContext ctx = ContextLoader
.getCurrentWebApplicationContext();
MessageSource messageSource = (MessageSource) ctx
.getBean("messageSource"); //How to avoid this?
switch (this) {
case DELETE_SUCCESS:
return messageSource.getMessage("deleteEmployee.success",
null, LocaleContextHolder.getLocale());
//... Other cases
default:
return null;
}
}
}
In the toString nethod I specified the messages for any Enumerator, but I used getBean method to programmatically get the appropriate bean. How can I avoid that?
I tried to inject the bean via
#Autowired
MessageSource messageSource;
but it didn't work. In fact, messageSource was just null. Is there a way to do that corretly at all?
If MessageSource is a bean that opens a properties file, then for example if your properties file is called Messages.properties, then you can use
ResourceBundle bundle = ResourceBundle.getBundle("Messages", LocaleContextHolder.getLocale());
String message = bundle.getString("deleteEmployee.success");
EDIT: Another possible method is to inject the MessageSource into your enums (idea from my solution at Java Generics and Enum, loss of template parameters ), like so:
public enum EmployeeErrorCode {
DELETE_SUCCESS {
#Override
public String toString() {
return messageSource.getMessage("deleteEmployee.success", null, LocaleContextHolder.getLocale());
}
},
//... Other enumerators
private MessageSource messageSource;
static class EnumInitializer {
#Autowired
private MessageSource messageSource;
#PostConstruct
public void init() {
for(EmployeeErrorCode errorCode : EmployeeErrorCode.values() {
errorCode.messageSource = getMessageSource();
}
}
public MessageSource getMessageSource() {
return messageSource;
}
}
}
But I think the other one is a bit cleaner.

Categories

Resources