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.
Related
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
I am using Spring for loading localized resource bundles into my application. Here is what I have done.
<bean id="systemMessages" class="o.s.c.s.ResourceBundleMessageSource">
<property name="basename" value="locale/system">
</bean>
<bean id="clientMessages" class="o.s.c.s.ResourceBundleMessageSource">
<property name="basename" value="locale/client">
</bean>
I want to load messages based on the locale in my controller, and I tried both these ways below
#Autowired
#Qualifier("clientMessages")
ResourceBundleMessageSource clientMessages;
#Resource(name="systemMessages")
ResourceBundleMessageSource systemMessages;
EDIT
The application is a JAXRS application and the injection is being tried in a Global Exception Mapper. From the comments I now understand that this class would have been created by the JAXRS container and not Spring ( Code below). How to let Spring know that this injection must work?
import javax.ws.rs.WebApplicationException;
//other imports
public class GlobalWebApplicationException extends WebApplicationException{
private String systemMessage;
private String clientMessage;
//Autowire the multiple resourcebundles
public GlobalWebApplicationException (String key, Locale locale) {
// this is where I want to use the injected object fetch the property
}
public doSomething(){
// Business Logic
}
}
But the injection is not happening and I am getting an NPE. How do I achieve this?
When using Spring and having it do auto wiring using annotations the fields cannot be null. The dependencies need to be satisfied on startup of the application. If that doesn't happen there can be 1 of 2 things wrong
You haven't enabled annotation processing
You aren't using a spring managed bean but are creating instances yourself
For the first option add <context:annotation-config /> to your application context, or if you want to do component scanning add <context:component-scan /> the latter already implies annotation processing.
For the second option you need to make your bean a spring managed bean and use that instead of creating new instances yourself.
Is there a way to easily use Spring Injection to grab one or more *.xml data files from a folder location (either in a deployed *.war or on a server folder) and inject that data from the *.xml files into a Java class (e.g. in a web service)? I have been asked by another programmer if I can do this.
I've had a look at a few links on stackoverflow, but so far the easiest way I've found is to put the *.xml files into a particular folder location (e.g. WEB-INF/classes) and use something like this to retrieve them:
Thread.currentThread().getContextClassLoader.getResourceAsStream("/WEB-INF/classes/data.xml")
The above method is easy; however, it is obviously not Spring Injection. Is there a way to do this using Spring Injection instead? I would have thought that since configuration files can be loaded this way, that xml data could also be loaded similarly.
Thanks.
Spring provides a class called Resource which you can use to inject resource files into a spring bean. So you can do this:
public class Consumer {
public void setResource(Resource resource) {
DataInputStream resourceStream = new DataInputStream(resource.getInputStream());
// ... use the stream as usual
}
...
}
Then:
<bean class="Consumer">
<property name="resource" value="classpath:path/to/file.xml"/>
</bean>
or,
<bean class="Consumer">
<property name="resource" value="file:path/to/file.xml"/>
</bean>
You can also directly use the #Value annotation:
public class Consumer {
#Value("classpath:path/to/file.xml")
private Resource resource;
...
}
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..
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">.