spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="meassageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="resource\message">
</property>
</bean>
</beans>
Main.java class file
public class Main {
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("spring.xml");
System.out.println(context.getMessage("emp", null, Locale.US));
}
}
My properties file is in src/resource folder. File name is mesaage_en_US.properties.
I have also tried with different file names like message.property, message_en.property and with different locales like Locale.English, Locale.UK but no luck.
I moved the property file to src folder but getting same exception.
I am getting following exception.
Exception in thread "main" org.springframework.context.NoSuchMessageException: No message found under code 'emp' for locale 'en_US'.
at org.springframework.context.support.DelegatingMessageSource.getMessage(DelegatingMessageSource.java:65)
at org.springframework.context.support.AbstractApplicationContext.getMessage(AbstractApplicationContext.java:1234)
at org.beans.Main.main(Main.java:14)
Please help.
message_en_US.properties
emp=Hello Employee.
I like to use a PropertySourcesPlaceholderConfigurer for that. Here's a great tutorial to get you started.
Basically, you'll want to add:
<context:property-placeholder location="classpath:foo.properties" />
to your spring xml config file, where "foo.properties" is a resource's absolute path within the class path.
Then you can inject them into fields like this:
#Value( "${jdbc.url}" )
private String jdbcUrl;
where "jdbc.url" is the reference name in your properties file.
Of course, the #Value won't work inside your static void main, but I really doubt static void main is where you want to use your properties anyway. You ought to be accessing them from a Spring Bean.
I think this is duplicated from this question. Basically, it has to do with a mismatch between your bundle and the locale specified in code.
Instead of getting message from ApllicationContext I am getting message from MeassageSource itself. I changed my spring.xml like this
<bean id="employee" class="org.bean.Employee" >
<property name="id" value="1"/>
<property name="name" value=""/>
<property name="dept" value=""/>
<property name="messages" ref="messageSource"/>
</bean>
Now I am calling messages.getMessage(this.messages.getMessage("emp", null, Locale.UK)) from Employee class. Its working.
Change to
<property name="basename" value="message" />
with message_en_US.properties in the same folder as your spring.xml.
EDIT : You have a typo in your bean name when defining the MessageSource. It's name should have been exactly messageSource. Because of that extra a in meassageSource ApplicationContext failed to load it.
I've reproduced your error and found the problem. It has to do with Spring not finding the bundle. I think you should be getting a warning before the exception with the following message:
WARNING: ResourceBundle [resource\message] not found for MessageSource: Can't find bundle for base name resource\message, locale en_US
This has been the hint. The problem is related to your project structure and how the bundles are searched when specifying setBasename property. Please take a look at this.
Anyway I think you should put your bundles in the more standard location src/main/resources. If you follow this convention, your messageSource bean should be defined like this:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="message" />
</bean>
With this approach your example should produce the desired line:
Hello Employee.
Related
I am enabling message i18n in my Spring web app. For this, I have below code in my servlet.xml
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
After adding above code, as soon as I hit my application in browser, I get below exception log:
SEVERE: Servlet.service() for servlet [default] in context with path [/ERP-Web] threw exception [Filter execution threw an exception] with root cause
java.lang.StackOverflowError
at org.springframework.context.support.ReloadableResourceBundleMessageSource.getMergedProperties(ReloadableResourceBundleMessageSource.java:235)
at org.springframework.context.support.ReloadableResourceBundleMessageSource.resolveCodeWithoutArguments(ReloadableResourceBundleMessageSource.java:176)
at org.springframework.context.support.AbstractMessageSource.getMessageInternal(AbstractMessageSource.java:209)
at org.springframework.context.support.AbstractMessageSource.getMessageFromParent(AbstractMessageSource.java:257)
where last 2 lines were repeated 100s of times and gives me StackoverflowException.
Exactly same exception is coming when I am using ResourceBundleMessageSource class.
My spring version is 4.3.6.RELEASE.
Below is content of my properties file
action.add.success = New {0} added successfully.
action.add.failure = Some error occurred in adding new {0}. Please try again later or contact administrator.
Sample project is on GitHub
I have tested your sample code in github and when running it has shown the error described, then modify the following:
Config:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
Class:
#RequestMapping(method=RequestMethod.GET)
#ResponseBody
public String getMessage() {
String msg = messageSource.getMessage("hello.world", null, LocaleContextHolder.getLocale());
return msg;
}
hello.word is the property with text in your file with name message_en.properties.
With this modifications the code run.
Edit for unknown message codes:
I tried with unknown message codes and the error was repeated, so I look at the registry and found that there could be more than one beans with the same name (potential circular references), but I have not detected why this happens, but if you It needs to work you have to rename the beans like this.
<bean id="myMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages/message"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
and then use:
#Autowired
private MessageSource myMessageSource;
but i think this not resolve the principal problem with the circular potential error.
Very strange situation ;-)
The fundamental problem is that the messageSource gets auto-wired to itself (in the parentMessageSource property) because you use default-autowire="byType" this causes the stackoverflow exceptions for unknown message codes that messes up everything. Must say that logback adds mess to the mess as sometimes seems that the exception happens in its code, Log4J handles it better.
Autowiring is not good for big projects, and this your situation is a classical case of why, however if you must use it change the messageSource bean adding the following:
<property name="parentMessageSource"><null/></property>
In this way you wire yourself the parent and no autowiring happens.
This restores the normal situation in which not found messages are reported with a NoSuchMessageException
Then:
In controller you must request hello.world message, not message
You are missing a default resource, that is a no-locale-suffix file that represents the default locale or your application. In your case would be messages/message.properties To be simple the default locale of your application is that one for which you have all messages. Start with that and then add new languages (that might be incomplete).
Update
As far as I run your demo project:
Remove default-autowire="byType", which will set your message source's parent to itself, which causes stackoverflow;
Avoid LocaleContextHolder.getLocale(), which relay on system default locale;
Use right basename, which is different for ReloadableResourceBundleMessageSource and ResourceBundleMessageSource which solves following warning;
ResourceBundle [messages/message] not found for MessageSource: Can't find bundle for base name messages/message, locale en_US
Runnable example
StackTrace
As far as I could see from your stack trace, you may have three problems:
You don't supply arguments, but your property needs it;
The message source you have has cyclic dependency with its parent, which causes the StackOverflow (because AbstractMessageSource has a model like classloader, i.e. delegation to parent if it can't resolve);
I am not sure whether your properties is really found by message source, if it found, even with cyclic dependency, it will not StackOverflow;
Suggestions
When it comes to why there exists cyclic dependency, I can't tell whether it is a bug of spring or mis-configuration according to current info;
If you are not convenient to provide a example project, you may try 4.1.6 Relase, which I tried, works fine;
You may set log level to DEBUG or set breakpoint, to see whether you property file is really loaded;
The way you should use the ResourceBundleMessageSource is setting the path to the messages files on the basename property.
For example, if you have two messages files:
messages_en.properties
messages_es.properties
located at resources folder. Your bean configuration should be something like:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
Where messages is the prefix of the name of both files.
Maybe the Exception is thrown because Spring id trying to load the classpath automatically, and you have it included too, so it tries to load it again and again...
You can find a working example on Mkyong's.
This is what worked for me in my applicationContext.xml file:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:i18n/message" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
Note that i put the properties files in the follwoing path :
src/main/resources/i18n/message_en.properties
I'm learning to use resouce bundle for printing locale-dependent messages in my project.
application.xml:
<bean class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="ru.bpc.svat.svnr.integration.banking.messages" />
</bean>
<bean class="ru.bpc.svat.svnr.integration.banking.application.SpringContextMessageFactory" />
Directory src\main\resources\ru\bpc\svat\svnr\integration\banking contains files:
messages.properties
messages_ru.properties
messages_ru_RU.properties
each having line:
test = testmessage
In my test class I get an instance of message factory and try to get a message:
#Autowired private MessageFactory messageFactory;
...
messageFactory.getMessage("test", new Object[]{}, Locale.getDefault());
And then I get an exception:
No message found under code 'test' for locale 'ru_RU'.
What's wrong with it? This might be a foolish question, but it's my first experience. Thank you for your answers.
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>locale\customer\messages</value>
</property>
</bean>
</beans>
finally use SpringContext context.getMessage() method read your value.
Note: Assume your properties files are located at “resources\locale\customer\” folder.as mentioned in value tag above.
Basically those files needs to be in class-path of your project.
Let me know if it solves your problem, then accept my answer!
what if you place you files directly into src/main/resources (& not in subdirectory of src/main/resources? Just a thought.Normally, it should be able to find the file if it is there on classpath.
Try to replace:
<bean class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="ru.bpc.svat.svnr.integration.banking.messages" />
</bean>
on
<bean class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="ru\bpc\svat\svnr\integration\banking\messages" />
</bean>
make sure that the path relative from your class. In other case put resource in src/main/resources and use classpath:\ suffix
I'm trying to implement a group of tests for my app. In this case, I have some mybatis mappers whose beans are defined in my applicationContext.xml. For example:
<bean id="usersMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.myapp.dao.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
I've been looking for hours how to implement junit tests properly because some internet posts are deprecated or not up to date. This is my junit class actually:
#ContextConfiguration(locations = {"classpath:*applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class GroupTest {
#Autowired
ApplicationContext context;
#Test
public void testCreateGroup() throws SQLException {
UserMapper um = (UserMapper)context.getBean("usersMapper");
}
}
There are no errors during the startup. When I try to get the bean usersMapper returns an exception (There is no bean definition..) Maybe, is not loading the properly applicationContext?
I also tried Mockito with no success. I've read it does cool things, but is it capable of loading the context as well as Spring? When I call the getUsers method from UserMapper, it returns null. This is my implementation:
#ContextConfiguration(locations = {"classpath:*applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class GroupTest {
#Mock
private UserMapper userMapper;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testCreateGroup() throws SQLException {
userMapper.getUsers();
}
}
For the record... my applicationContext.xml is placed in /src/main/webapp/WEB-INF/applicationContext.xml
Hope you can guide me the right way. Thank you
Edit1: applicationContext.xml and context.xml added:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/adminDB"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="/WEB-INF/mybatis-config.xml" />
</bean>
<bean id="usersMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="es.unican.meteo.dao.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
</beans>
It seems that Peter Hart solution loads the applicationContext.xml but a new problem appears. I need to use a jndi Resource in my app (reference included in applicationContext.xml). Is this no possible in test environment?
The exception shows the following:
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
This is my context.xml
<Context>
<Resource name="jdbc/adminDB" auth="Container" type="javax.sql.DataSource"
maxActive="20" maxIdle="10" username="***" password="***"
driverClassName="org.apache.derby.jdbc.ClientDriver"
url="jdbc:***"/>
</Context>
The problem is that you've requested a classpath resource, and WEB-INF/applicationContext.xml is probably not on the classpath (it usually wouldn't be).
You could try moving the applicationContext.xml to somewhere on the classpath. I'm guessing that you are using maven, in which case, this would usually either be src/main/resources, or src/test/resources (if this is specific to a particular test, rather than a 'real' application context file). I would also fix your #ContextConfiguration as #ohiocowboy suggests (assuming you put it directly in that directory, as things will generally work better if you're explicit about the location).
If your application context absolutely needs to be in WEB-INF/applicationContext.xml, you might try using file:src/main/webapp/WEB-INF/applicationContext.xml. If you run from the base directory of the project with mvn test, it should work, and it would probably work from the eclipse test runner also (no idea about Idea or NetBeans, but my guess is that it might work).
Your application context is not being loaded properly. The locations attribute of the #ContextConfiguration annotation should be "classpath:main/webapp/WEB-INF/applicationContext.xml", "classpath:**/applicationContext.xml" or "classpath*:applicationContext.xml". When you run the test, the application is not deployed, hence WEB-INF will not be in the classpath(unless you have added it to the test classpath yourself).
When using a mock object, you need to provide mock implementations for the methods that are going to be called. The getUsers() method is returning null because you have not set the desired result. You can check the mockito website for examples at http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html.
try
#ContextConfiguration(locations = {"classpath:/applicationContext.xml"})
UPDATE
Actually that doesn't work either because. The applicationContext.xml isn't on the classpath. It needs to be moved into the WEB-INF/classes directory.
I have three different .properties files in a Spring Batch project, and I'm trying to set which .properties file should be used as a JobParameter. I'd like to be able to run the job like so:
java CommandLineJobRunner context.xml jobName region=us
The region should specify which .properties file should be used. The problem is getting the context to recognize the JobParameter. I've tried the following to no avail:
<context:property-placeholder location="classpath:batch.#{jobParameters['region']}.properties"/>
And also:
<util:properties id="batchProperties" location="classpath:batch.#{jobParameters['region']}.properties"></util:properties>
I had heard that adding scope="step" could fix similar issues, but I tried adding that to both of the above solutions and still had exceptions.
I think I'm missing a fundamental idea of why I can't get this working, but I'm unable to figure out what that idea is.
If anyone has any suggestions on getting this working and/or explaining why my previous approaches failed, I'd appreciate it.
This is not the right way to proceed (it is impossible do what you are trying to do).
You have to think that jobParameters is available only when a job is running and only for its composing steps marked with scope="step" (and not <context:property-placeholder> nor <util:properties> has a step attribute).
A way for solving the problem is to load properties file in job's execution context before first step is running with a listener:
public class PropertyLoaderJobExecutionListener extends StepExecutionListenerSupport {
Properties countryProperties;
public void setCountryProperties(Properties pfb) {
this.countryProperties = pfb;
}
#Override
public void beforeStep(StepExecution stepExecution) {
super.beforeStep(stepExecution);
// Store property file content in jobExecutionContext with name "batchProperties"
stepExecution.getJobExecution().getExecutionContext().put("batchProperties", countryProperties);
}
}
in your job.xml
<bean id="loadPropertiesListener" class="PropertyLoaderJobExecutionListener" scope="step">
<property name="pfb">
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:batch.#{jobParameters['region']}.properties" />
</bean>
</property>
</bean>
and register this listener in your first step (you can't do that in your JobExectionListsner.beforeJob() because there isn't a scope="job" for now and late-binding of #{jobParameters['region']} value is not available).
To access your data with spEL use this syntax:
#{jobExecutionContext.get('batchProperties').getProperty('language')}
or a better syntax to access properties (IDK spEL so good, sorry).
Hope to be clear and can help to solve your problem.
EDIT (full code of my working job.xml):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-util-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<job id="sourceJob" xmlns="http://www.springframework.org/schema/batch">
<step id="step1">
<tasklet ref="getRemoteFileTasklet" />
<listeners>
<listener ref="loadPropertiesListener" />
</listeners>
</step>
</job>
<bean id="loadPropertiesListener" class="PropertyLoaderJobExecutionListener" scope="step">
<property name="pfb">
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:batch.#{jobParameters['region']}.properties" />
</bean>
</property>
</bean>
<bean id="getRemoteFileTasklet" class="GetRemoteFileTasklet" />
Say, I have the following bean in Spring context:
<bean class="some.class.BlabBlahBlah">
<property name="location" value="classpath:somefile.xml"/>
</bean>
Currently somefile.xml is placed in the src/main/java, but I'd like to place it somewhere in the file system. Is there a way to do that? I tried to set full path instead of this classpath: but it didn't work. Thanks in advance.
By reference (Table 4.1), you should probably use a file system resource path:
<property name="location" value="file:/path/to/file.xml" />