I'm trying to define error messages in a resource file, but I can't seem to get them to load so I can use them in my controller.
My servlet-context.xml file:
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename" value="classpath:messages" />
</beans:bean>
My form:
public class LoginForm {
#NotEmpty
private String username;
// getters and setters
}
My messages.properties file (in the root of my source folder, so it gets compiled to the root of my classes folder):
NotEmpty.loginForm.username=test1
NotEmpty.username=test2
NotEmpty.java.lang.String=test3
NotEmpty=test4
My controller:
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(#Valid LoginForm form, BindingResult result) {
if (result.getFieldErrors().size() > 0) {
FieldError firstError = result.getFieldErrors().get(0);
System.out.println(firstError.getDefaultMessage());
}
// ...
}
However, the output of the getDefaultMessage call is never what I define in my resource file! It is always may not be empty (the default).
I've tried a variety of different entries in my context file but it seems like it's not loading the resource file. What am I doing wrong?
According to this documentation, all you need is to put a properties file called ValidationMessages.properties at the root of your project classpath.
You can then add properties with the following format
org.hibernate.validator.constraints.NotEmpty.message=Default message, can not be empty
NotEmpty.ClassName.fieldName=fieldName can not be empty.
where ClassName is the name of your class and fieldName is the name of the field of that class.
You might need to do some configuration to set the correct MessageInterpolator, but I think the default one will do what you need.
First idea:
Try to rename property keys from NotEmpty.loginForm.username to NotEmpty (Just to check if messageSource works correctly). If still not working there is
Second idea:
Where do you perform scanning of components?
Assume that you have two spring configurations: applicationContext.xml (or other name) and servlet-context.xml.
If you have such structure <context:component-scan base-package="by.company.app" /> in applicationContext than your controllers have no defined messageSource - so it cannot load customized messages. It is because #Controller bean is in one spring context, MessageSource bean - in another. (To check this you can simple declare #Autowired MessageSource messageSource field in controller and see in debug is it null or not) In that case you can modify component-scan in applicationContext to:
<context:component-scan base-package="by.company.app">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
and add following configuration to servlet-context.xml:
<context:component-scan base-package="by" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
Hope this helps
Unfortunately it looks like a MessageSource must be defined and then used in the appropriate Java class. The getDefaultMessage() method doesn't appear able to read from message properties.
In a component-scanned class:
#Autowired
private MessageSource messageSource;
public String getMessage(FieldError field) {
return messageSource.getMessage(field, null);
}
This will iterate through all possibilities in the message properties files and then--if nothing is found--falls back on the getDefaultMessage() results.
Additionally I updated my servlet-context.xml file to define my messageSource with the basename value of /WEB-INF/classes/messages, as opposed to what I had in my question above.
I spent some time to fix this issue, I done a following changes, now it is working fine in Spring 4.0 MVC and Hibernate 4.1.9
1.put messages under source folder.
If ReloadableResourceBundleMessageSource is not working change to
class="org.springframework.context.support.ResourceBundleMessageSource">
changes property like '<'property name="basename" value="messages"/>
In Message.properties file, the key should be in the following format.
NotEmpty.userForm.userId
userForm-->Model class name.
(If your Model class name is UserForm, then it should
be mentioned as userForm)
userId--> attribute of userForm class
Related
I've searched stackoverflow, read docs and can not seem to get my #Value("${myproperty.value}") to give me anything other than null.
I have some beans that I have defined in my spring-servlet.xml as well the properties file.
<!-- Load properties files -->
<context:property-placeholder location="classpath:MyProperties.properties" ignore-unresolvable="true" />
The properties file gets loaded without errors. In the same xml I have defined a bean.
<bean id="pushNotification" class="com.mydomian.actions.MyClass"/>
In the bean I have properties that use the #Value.
private #Value("${some.property}") String propertyValue;
My properties are always null.
You need to declare
<context:annotation-config />
to enable annotation processing.
I am having difficulty understanding why something in Spring Java Config using #Autowired does not work.
First, I am trying to move all my #Autowired annotations in the Java Config classes. This has the effect of making my "POJOs" back into real POJOs. I can then not only test them easily outside of a Spring context, but can also use mock objects easily and readily.
So I first tried this:
#Configuration
public class Module3ConfigClass {
#Autowired
private Module1Bean1 module1Bean1;
#Autowired
private Module2Bean1 module2Bean1;
#Bean
public Module3Bean1 module3Bean1() {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
However, when the Module3Bean1 constructor is invoked, both passed in Beans are null. If you didn't follow my made up naming convention above, both of those beans would be created by a separate Java Config configuration file. Also note that everything is wired up correctly - I know this because everything works perfectly when the #Autowired tags are on the corresponding private member fields inside of Module3Bean1.
FWIW, I tried adding an #DependsOn annotation to module3Bean1() method, but had the same results. I guess I just would really like to understand this behavior, is it correct (I suspect it is, but why)?
Finally, I found an acceptable workaround shown here:
#Configuration
public class Module3ConfigClass {
#Bean
#Autowired
public Module3Bean1 module3Bean1(Module1Bean1 module1Bean1, Module2Bean1 module2Bean1) {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
This seems fine to me, but if anyone would care to comment on it, that would be welcome as well.
I think you came across same problem I just had. In my case problem was invalid xml configuration. In my module B I had config like :
<beans>
<context:component-scan base-package="com.moduleB"/>
<import resource="classpath:applicationContext-moduleA.xml"/>
</beans>
In moduleA context I placed "context:annotation-config" annotation.
When I change import/context order to :
<beans>
<import resource="classpath:applicationContext-moduleA.xml"/>
<context:component-scan base-package="com.moduleB"/>
</beans>
Autowiring for configuration class properties started to work.
We had the same issue and came to the conclusion that the error arose because we had a circular dependency where a BeanPostProcessor was involved.
A PropertyPlaceholderConfigurer (a BeanPostProcessor) has been configured to set its propertiesArray property with the help of another bean:
<bean id="globalPropertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
lazy-init="false" depends-on="javaLoggingConfigurer">
<property name="locations">
<list>
<value>classpath:config/host/${env.instance}.properties</value>
<value>WEB-INF/config/host/${env.instance}.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true" />
<property name="propertiesArray" value="#{springPropertyFinder.findProperties()}" />
</bean>
The used springPropertyFinder bean to set the propertiesArray is not a BeanPostProcessor but a "normal" bean that gathers all Properties instances with:
public Properties[] findProperties() {
Map<String, Properties> propertiesMap = applicationContext.getBeansOfType(Properties.class);
for (String title : propertiesMap.keySet()) {
PropertiesLoggerUtil.logPropertiesContent(logger, "Springcontext Properties ("+title+")", propertiesMap.get(title));
}
return propertiesMap.values().toArray(new Properties[propertiesMap.size()]);
}
The #Configuration class contained a bean of type Properties
So our assumption is that the #Configuration class has been created without being processed by the ConfigurationClassPostProcessor (also a BeanPostProcessor), because the PropertyPlaceholderConfigurer depends on the springPropertyFinder, which depends on the properties bean in the #Configuration class. The order of the BeanPostProcessors is probably not setup right under these circumstances.
This described setup worked in XML, but not with Java config.
I have put most of the class under
com.company.productline.product -- classpath 1
within that class path there will be service, web, domain, i18n... subpackages.
For some reason, there is another service bean I wrapped in a jar, which should work for the whole productline, hence it is under
com.company.productline -- classpath 2
So in applicationContext.xml, the base-package for component-scan have to compromise to one level up, as classpath 2 instead of classpath 1, like this
<context:component-scan base-package="com.company.productline">
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
Then to make Spring to scan #Service or #Component across the whole application even within that jar file.
However, now in applicationContext there is an error saying:
Annotation-specified bean name 'someServiceClass' for bean class
[com.company.productline.i18n.someServiceClass] conflicts with existing,
non-compatible bean definition of same name and class
[com.company.productline.product.i18n.someServiceClass]'
The problem is Spring seems find a bean class under a false package com.company.productline.i18n.someServiceClass without the product in the middle, but here are what I can confirm:
There is not a class/classpath under the package com.company.productline.i18n.someServiceClass, but there is a class under com.company.productline.product.i18n.someServiceClass.
The class someServiceClass does have a #Component annotation.
But if I take one level down of the classpath in base-package, the error is gone:
<context:component-scan base-package="com.company.productline.product">
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
the class is defined like this:
#Component
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "request")
public class SomeServiceClass implements CurrentRequest {
#Autowired
private HttpServletRequest request;
public Locale getCurrentLocale() {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
return localeResolver.resolveLocale(request);
}
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
}
So really not sure what's going on and why have this problem.
The application is running on Spring 3.1.0 on STS 2.9.1
Please help, thanks in advance.
Turns out ninn is correct. There is no other possibility but only a class with same bean name within the application.
The reason the project search doesn't work out in this case is that we have another jar file with the same service class. I wasn't know that until noticed. After remove the class within the source code then the error is gone.
Thanks ninn.
I have the following class:
#Component
public class MyClass {
#Value("${main.url}") private String mainUrl;
the following XML context:
<context:annotation-config/>
<context:component-scan base-package="mypackage"/>
<context:property-placeholder file-encoding="UTF-8" location="classpath:/app.properties" ignore-unresolvable="true"/>
and prop file:
main.url=veryniceurl.com
Injection doesn't work, it is always null.
I read a lot of similar examples and I thought that everything is ok but it isn't. Can anyone tell me if I forgot about something? I'm working with Mule ESB.
#Value doesn't seem to work with Mule. Instead you need to wire it up through the Mule XML, where I assume you are loading your component as a Spring Bean:
<spring:bean id="MyClass" class="com.example.MyClass">
<spring:property name="mainUrl" value="${main.url}"/>
</spring:bean>
Give an id to your properties and use this syntax :
#Value("#{jetProperties['jetBean.name']}")
<!-- define the properties file to use -->
<util:properties id="jetProperties" location="classpath:/jet.properties" />
From http://chrislovecnm.com/2010/03/08/spring-3-java-based-configuration-with-value/
Did you add the context placeholder in the dispatcher-servlet.xml ? As per here, Spring #Value annotation in #Controller class not evaluating to value inside properties file they seem to have solved it by adding it there instead of the application context
I'm trying to do some spring validation with the error messages in properties files.
But the examples I find all seem to have the values hardcoded, or gotten from a properties file but using a validator class and retrieving it there.
My setup is a bit different.
I'm using the #Valid annotation in my requestmapping, and my #Valid class uses #NotNull etc.
I've seen some examples where people do #NotNull(message = "blablabla");
But that's also hardcoded, and I'd like to put the messages in a properties file so I can easily edit it on the fly and so I can easily implement i18n in the future.
Any input on how to achieve this would be appreciated.
It works exactly the same way as with explicit Validator - you declare a MessageSource and write error messages in .properties files. Messages codes are formed as constraintName.modelAttributeName.propertyName:
publib class Foo {
#NotNull private String name;
...
}
.
#RequestMapping
public String submitFoo(#Valid Foo foo, ...) { ... }
messages.properties:
NotNull.foo.name=...
MessageSource declaration:
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value = "messages" />
</bean>