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>
Related
I’m trying to understand a piece of Spring code that I need to adapt.
I have:
<bean id="…" class="…">
<property name="expr"
value="teams.contains(member.team) and not empty(member.projects)" />
</bean>
The corresponding class has a field
private Expression expr;
of type
org.apache.commons.jexl2.Expression
Now I am trying to find the appropriate Spring annotation to get rid of the XML file. But I cannot even understand how a simple String property can be injected as a jexl2.Expression object. How does this work?
A friend found the answer:
There was another XML file with this:
<bean id="bean_for_ExprConverter" class="package.of.custom.ExpressionConverter">
<constructor-arg ref="bean_for_JexlEngine"/>
</bean>
and also, in the project’s properties:
application.spring.converters = #{{\
#'bean_for_ExprConverter'\
}}
Thus, as long as the converter bean is defined, it should be enough to simply inject the expression string with the #Value annotation.
The following is a snippet from a project based on Spring Boot 1.3. Json serialization is made via Jackson 2.6.3.
I have the following Spring MVC controller:
#RequestMapping(value = "/endpoint", method = RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
public Results<Account> getAllAccounts() throws Exception {
return service.getAllAccounts();
}
The returned Results is as follows (getters and setters removed):
public class APIResults<T> {
private Collection<T> data;
}
The Account class is as follows (getters and setters removed):
public class Account {
#JsonView(Views.ViewA.class)
private Long id;
#JsonView(Views.ViewB.class)
private String name;
private String innerName;
}
I also have the following Json Views
public class Views {
public interface ViewA {}
public interface Publisher extends ViewB {}
}
The motive is to return different view from the same controller, based on some predict.
So I'm using AbstractMappingJacksonResponseBodyAdvice to set the view at run-time. When setting bodyContainer.setSerializationView(Views.ViewA.class), I'm getting an empty json result and not a json array of objects that only contains the id property. I suspect this is because the data property in APIResults< T > is not annotated with #JsonView, however shouldn't non annotated properties be included in all views (doc)?
Is there a way to get what i want without adding the #JsonView annotation to APIResults< T > (this is not an option).
I know i can use Jackson mixin to get the functionality i desire, however is there a way to do that using Json views ?
You were right, spring MVC Jackson2ObjectMapperBuilder has been improved to set jackson mapper feature DEFAULT_VIEW_INCLUSION to false, so not annotated property data is not serialized.
To enable the feature, use following config (XML):
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="defaultViewInclusion" value="true"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
With this config, you'll have id and innerName properties serialized when using ViewA view:
{"data":[
{"id":1,"innerName":"one"},
{"id":2,"innerName":"two"},
{"id":3,"innerName":"three"}
]}
Further, you may manage to hide innerName also, by adding some other view annotation to it.
I am downloading a json file and contents are available as arrays of arrays.
There are various validation(notNull, isNumber etc) which I want to do for the elements of child array.
One was is when I am using Spring batch and enable ValidatingItemProcessor and Bean Validation works for me.
However, I want to write a standalone solution using already existing Validator frameworks like from Apache but do not want to validate as bean but directly on array.
What should be my approach to this problem.
I am using Spring framework, so anything around that would be helpful.
We used JSR validations for our spring batch application. We annotated our classes with validations such as #NotNull,#DecimalMin. We then created a CommonValidator such as
import javax.validation.Validator;
...
public class CommonValidator<T> implements ItemProcessor<T, T>{
#Autowired
private Validator validator;
public T process(T t) throws Exception{
Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);
return constraintViolations.isEmpty()? t : null;
}
We then, added it in a CompositeItemProcessor as follows.
<bean id="validateProcessor" class="mypackage.CommonValidator" />
class="org.springframework..CompositeItemProcessor">
<property name="delegates">
<list>
<ref bean="validateProcessor"/>
<ref bean="otherProcessor"/>
And it worked. On the similar lines, you can write your own validator to validate your array. So, if the array values are valid, then the array is returned. null is returned for an invalid array.
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
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.