Programmatically refresh the spring mvc resource bundle - java

ResourceBundleMessageSource messages are configured in Spring's configuration file as
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="WEB-INF/strings/appstrings" />
Whenever I changed any message in that properties file I have to restart server.
I want to read these updated messages programatically in my application without restarting server.
How can I read these messages programatically in one of my #Controller while running application.

There is a ReloadableResourceBundleMessageSource ( http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/context/support/ReloadableResourceBundleMessageSource.html ) in spring that should do what you want.
You can find more info here on stackoverflow:
How to Inject Spring ReloadableResourceBundleMessageSource
How to Inject Spring ReloadableResourceBundleMessageSource

Define your ResourceBundle property in applicationContext.xml file like:
<!-- Message Source for appstrings -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="WEB-INF/strings/appstrings" />
</bean>
In you Java class/controller auto-wire it as:
private ReloadableResourceBundleMessageSource messageSource;
#Autowired
public void setMessageSource(MessageSource messageSource) {
this.messageSource = (ReloadableResourceBundleMessageSource) ((DelegatingMessageSource) messageSource).getParentMessageSource();
}
Then call clearCache() in any function in that class/controller.
messageSource.clearCache();
I got this exception in controller
ReloadableResourceBundleMessageSource incompatible with org.springframework.context.support.DelegatingMessageSource
When you try to run it through messageSource in your controller, you get NOTHING, empty string. And if you look closely, you will find that you have a DelegatingMessageSource in your messageSource property, with an empty parent source, which means it is EMPTY, i.e. always returns blank.
Here’s the solution for this little challenge: move your messageSource definition from spring-servlet.xml to applicationContext.xml!
Read more..

Related

How to manually reload properties file from Spring messageSource

For spring framework, I want to manually reload data inside properties file. Actually, have to write reload servlet that will manually reload data when I manually run this servlet file.
I have already defined spring configuration for messageSource.
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
p:basename="classpath:/message" />
But don't want to autoreload at certain amount of time for example can autoreload when setting:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
p:basename="classpath:/message"
p:cacheSeconds="1" />
I tried before by clearCaches() but not autoreload.
It is working now. Need to inject messageSource into servlet file and call clearCache(). It does clear previous properties data and reload updated properties file.
In ReloadServlet.java,
ReloadableResourceBundleMessageSource rs = Global.getBean("messageSource", ReloadableResourceBundleMessageSource.class);
rs.clearCache();
In Global.java,
private static ApplicationContext context;
public static <T> T getBean(String s, Class<T> type) {
return context.getBean(s, type);
}
Thanks.
I don't know, what you mean manually reload properties file. Spring already provide to load properties file as below.
Configure your properties file in your spring configuration file. Eg. applicationContext.xml or spring-beans.xml
<util:properties id="MY_CONFIG" location="classpath:MY_CONFIG.properties"/>
In your sping bean, inject as below
#Resource(name = "MY_CONFIG")
private Properties properties;
Your servlet invoke that spring bean.
Update
If you would like to load the file from Servlet or other classes directly
Load properties file in Servlet/JSP

how to define and use multiple property files using ResourceBundleMessageSource in spring

Can I define two property files using ResourceBundleMessageSource like:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>com/app/view/web/AppResource1</value>
<value>com/app/view/web/AppResource2</value>
</list>
</property>
</bean>
If that is possible with ResourceBundleMessageSource, How to use both the property files in Bean file. Till now, I am using only one property file in any bean by injecting messageSource in to it and using like:
public class BeanOne {
public BeanOne(ResourceBundleMessageSource bundleMessageSource) {
this.messageSource = bundleMessageSource;
}
....
this.messageSource.getMessage("",locale);
}
Please tell me how to access both property files in a bean. Thanks.
The properties from both files are included in the message source.
If you have com/app/view/web/AppResource1:
com.app.view.web.propertyA=foo
And com/app/view/web/AppResource2:
com.app.view.web.propertyB=bar
Then in your bean, you access can them:
messageSource.getMessage("com.app.view.web.propertyA", LOCALE); // foo
messageSource.getMessage("com.app.view.web.propertyB", LOCALE); // bar

NoSuchMessageException - Spring ReloadableResourceBundleMessageSource vs ResourceBundleMessageSource

I defined the following Spring bean:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages</value>
</list>
</property>
</bean>
The controller:
#Controller
public class EuserController {
#Inject
MessageSource messageSource;
#RequestMapping(value="/euser/{empId}", method=RequestMethod.DELETE)
public #ResponseBody String deleteEeuserById(#PathVariable(value="empId") Integer id) {
return messageSource.getMessage("deleteEuser.success", null, LocaleContextHolder.getLocale());
}
}
And it works fine. But when I'm trying to replace:
org.springframework.context.support.ReloadableResourceBundleMessageSource
with:
org.springframework.context.support.ResourceBundleMessageSource
and I get a org.springframework.context.NoSuchMessageException.
What does this happen when using the org.springframework.context.support.ResourceBundleMessageSource instead?
ReloadableResourceBundleMessageSource is an alternative to ResourceBundleMessageSource that is capable of refreshing the messages while the application is running. It's also more powerful as you are not limited to bundles on the classpath but you can load files from other locations too.
When using a ResourceBundleMessageSource you need to restart your application when making changes as ResourceBundleMessageSource doesn't reload your bundles when you change them. The classpath: prefix also needs to be removed. This is because of the way the two classes work:
The ResourceBundleMessageSource uses a JDK class to do its thing: ResourceBundle. It delegates to it to load the bundle. Basically, the bundle you give to ResourceBundleMessageSource must conform to what ResourceBundle expects and processes. ResourceBundle does not know how to handle the classpath: prefix and so it fails.
ReloadableResourceBundleMessageSource on the other hand is "smarter" and knows how to load bundles from other places, not just the classpath. It works with a Spring class: Resource. There are various implementations out of the box. When you give a bundle to ReloadableResourceBundleMessageSource, since it can load files from various places, you have to be explicit with the location and say "My file is on the classpath". You say that by adding the classpath: prefix and Spring knows how to handle it.

Spring: No message found under code for locale 'en_US'

applicationContext-Service.xml
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list><value>messages</value></list>
</property>
</bean>
I have messages_en_US.properties under /src/messages_en_US.properties
registerForm.passwordNotMatch=Password does not match.
This is line of code is bringing up the error:
binding.addError(new FieldError(REGISTER_FORM, "passwordNotMatch", messageSource.getMessage("registerForm.passwordNotMatch", null, locale)));
Error: No message found under code 'registerForm.passwordNotMatch' for locale 'en_US'.
What might be wrong?
does it work if you change to:
classpath:messages
?
I had the experience that if using ReloadableResourceBundleMessageSource, in jsp will not find the properties file. adding classpath: before the basename solved my problem.
Well even though was my project managed by maven, I think you can give it a try anyway.
For those using #Bean annotation for bundleMessageSource.
Add the name for #Bean.
name="messageSource"
Use the same name we used to create the MessageSource object in #RestController class
#RestController
public class HelloWorldController {
#Autowired
private MessageSource messageSource;
#GetMapping(path = "/hello-world-internationalized")
public String helloWorldInternationalized(#RequestHeader(name = "Accept-Language", required = false) Locale locale) {
return messageSource.getMessage("good.morning.message", null, locale);
}
}
Then in the #SpringBootApplication class
#Bean(name="messageSource")//wont work without the bean name
public ResourceBundleMessageSource bundleMessageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
Referred this link
I had the same issue. I tried classpath: but it didn't make a difference. Ended up putting in a carriage return on the last line of my properties file (so the cursor sits on the next line, which is the end of the file).
Also, if you're using Maven and you place your properties file like so: /resources/xxxx.properties, the resource directory is automatically pulled into your generated war, so classpath: is not necessary.
I think instead of <property name="basenames"> it should be <property name="basename">.

How can I inject a property value into an annotation configured spring mvc 3.0 controller

First: I'm using Spring 3.0
I have a problem when configuring my controller class. The controller uses a web service which I want to define the endpoint address using a .properties file.
#Controller
public class SupportController {
#Value("#{url.webservice}")
private String wsEndpoint;
...
In my application context xml-file, I've defined this:
<context:property-placeholder location="/WEB-INF/*.properties" />
I've been reading the documentation, trying different approaches (like adding prefix systemProperties.),but I keep getting an error message telling me that it doesn't exist.
Field or property 'url' cannot be
found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'
Ok. I've figured it out.
Now, in the controller:
#Value("#{settings['url.webservice']")
Then in the context configuration I have this "helper bean":
<util:properties id="settings"
location="/WEB-INF/supportweb.properties"></util:properties>
This should work, too:
#Value("${url.webservice}")
private String wsEndpoint;
I have this configuration and it works fine:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
and I iniejct the property in this way
#Value("${root.log.level}")
private String prop;
the field is correctly initialized to "DEBUG" value.
you should check that the
<context:property-placeholder location="/WEB-INF/*.properties" />
is defined in webmvc-config.xml where you create instances of the #Controllers

Categories

Resources