spring mvc validation best practices - java

I am learning myself Spring MVC 2.5 mostly from the docs. Can someone explain the following:
Advantages/differences of using command objects versus using #ModelAttribute to pass in the object.
Is there an easier way to do validation other then writing a Validator object?
Also, in this code how does the line ValidationUtils.rejectIfEmpty(e, "name", "name.empty"); work? How can it check if the name is empty on the person object when the person object is not passed in?
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
}
(this code is from section 5.2 from the docs)
Thanks

The question about command object is not very clear. If you mean the following syntax
#RequestMapping(...) public ModelAndView foo(Command c) { ... }
then it is the same as the following
#RequestMapping(...) public ModelAndView foo(#ModelAttribute Command c) { ... }
because #ModelAttribute can be omitted. The only case when it's actually needed is then you need to specify attribute name explicitly (otherwise it would be inferred as a class name with the first letter decapitalized, i.e. command)
In Spring 2.5 - no. In Spring 3.0 you can use declarative validation with JSR-303 Bean Validation API.
The Errors object has a reference to the object being validated.

Here is the answer of your first question.
http://chompingatbits.com/2009/08/25/spring-formtag-commandname-vs-modelattribute/
according to my experience there isn't easier way to fullfill validation, because it's easy enough. You can get it easier integrating libraries such as commons-validator into your project and use pre-defined validation rules in your forms.
http://numberformat.wordpress.com/tag/spring-mvc-validation/
and also with 3rd version of Spring you can use Bean validation using annotations.

Related

Spring AOP custom annotation

I am trying to implement custom annotation and aspect which will insert path variable into request body before validation.
For now it looks like this...
#Aspect
#Component
public class AddParameterToFormAspect {
#Before("#annotation(addParameterToForm)")
public void addParameterToForm(JoinPoint joinPoint, AddParameterToForm addParameterToForm) {
String form = addParameterToForm.form();
String pathVariable = addParameterToForm.pathVariable();
CodeSignature methodSignature = (CodeSignature) joinPoint.getSignature();
List<String> methodParamNames = Arrays.asList(methodSignature.getParameterNames());
int formIndex = 0;
int pathVariableIndex = 0;
for(String s : methodSignature.getParameterNames()) {
if(s.equals(form)) {
formIndex = methodParamNames.indexOf(s);
}
if(s.equals(pathVariable)) {
pathVariableIndex = methodParamNames.indexOf(s);
}
}
Object[] methodArgs = joinPoint.getArgs();
Object formObject = methodArgs[formIndex];
Field pathVariableObject;
try {
pathVariableObject = formObject.getClass().getDeclaredField(pathVariable);
pathVariableObject.setAccessible(true);
pathVariableObject.set(formObject, methodArgs[pathVariableIndex]);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
Controller example of working annotation...
#PostMapping("/test/{username}")
#AddParameterToForm(pathVariable = "username", form = "user")
public String test(#PathVariable String username, #RequestBody User user) {
return user.getUsername();
}
Controller example of validation not working...
#PostMapping("/{domainCode}")
#AddParameterToForm(pathVariable = "domainCode", form = "userAddForm")
public ResponseEntity<UserDto> saveUserForDomain(#PathVariable(name="domainCode") String domainCode, #RequestBody #Valid final UserAddForm userAddForm, BindingResult results) {...}
Adding path variable to form works but it seems #Valid no longer works, problem is probably in join point expression... How can I make it to do advice before validation and then validate?
Changing method parameters in a #Before advice is not meant to work. You should use an #Around advice in order to change parameters before calling thisJoinPoint.proceed(). This is because when calling thisJoinPoint.getArgs() you get copies of primitive type parameters, you cannot manipulate the originals in a before-advice. You are lucky that you want to manipulate object types in this case, so that is the reason it works. Using an around-advice would enable you to pass completely new arguments to a method or just manipulate the original objects, you are free to choose.
Furthermore, you should - whenever possible - use args() in order to bind your method arguments of interest to advice parameters in order to be able to interact with them in a non-cryptic and type-safe manner. Creating a local variable and assigning some value to it will not influence the method parameter of the same type at all. Why should it?
Feel free to ask follow-up questions if this explanation is not comprehensive enough for you. Then I could add some sample code for you, too.
Update after question edit:
After having inspected you code a bit more closely and in addition to my remarks earlier today in my comments under your question, disregarding the content of your aspect code, your actual problem is that the validation check cause by #Valid annotations is performed before the method is executed. I.e. what is validated is not the state after the aspect has done its job (populate member fields in your target objects) but the state before the aspect runs. It is actually the same problem discussed in this question, see also M. Deinum's and my suggestions how to solve it:
Maybe you want to try full AspectJ via LTW (load-time weaving) and see if a call() pointcut instead of the implicit execution() pointcut used by Spring AOP solves the problem. You would weave into the calling code (method calls) instead of the callee (method execution) itself. Chances are, that this happens before validation is performed.
A more Spring-like way to solve it is to use a Spring interceptor (M. Deinum mentions HandlerInterceptor) instead of an aspect. There is also a link to an example by someone else.
Having said that, I still recommend to refactor your code so as not to use reflection and matching strings on method parameter names or class member names. I think you could also get rid of your custom annotation by matching your pointcut on methods parameters with #RequestBody and #PathVariable annotations.

Java - Custom/standard validation with Annotations

I'm using annotations in a project. The thing is i'm making custom validation that (partly) depends on annotations. I'm also making own annotations, but I want to use as much as I can from the JSR 303 standard.
to check if a field 'passes' the annotation constraints i've written some methods. Example:
static boolean isNotNullValid(Field f){
boolean valid = true;
if(f.isAnnotationPresent(NotNull.class)){
Object o = ObjectGetter.getFieldValue(f);
if(o==null){
valid = false;
}
}
return valid;
}
It's quite a lot of work to do this type of validation for all annotations. Is there some method i'm missing, like .isValid() ? I mean, of course, for the standard annotations.
Thanks in advance
You're not supposed to code that by yourself. You should instead rely on an implementation of the JSR, for example Hibernate Validator. The Validator it implements allows getting a set of constraint violations based on the annotations on the bean.

Spring MVC + Hibernate: data validation strategies

We all know, that Spring MVC integrate well with Hibernate Validator and JSR-303 in general. But Hibernate Validator, as someone said, is something for Bean Validation only, which means that more complex validations should be pushed to the data layer. Examples of such validations: business key uniqueness, intra-records dependence (which is usually something pointing at DB design problems, but we all live in an imperfect world). Even simple validations like string field length may be driven by some DB value, which makes Hibernate Validator unusable.
So my question is, is there something Spring or Hibernate or JSR offers to perform such complex validations? Is there some established pattern or technology piece to perform such a validation in a standard Controller-Service-Repository setup based on Spring and Hibernate?
UPDATE: Let me be more specific. For example, there's a form which sends an AJAX save request to the controller's save method. If some validation error occurs -- either simple or "complex" -- we should get back to the browser with some json indicating a problematic field and associated error. For simple errors I can extract the field (if any) and error message from BindingResult. What infrastructure (maybe specific, not ad-hoc exceptions?) would you propose for "complex" errors? Using exception handler doesn't seem like a good idea to me, because separating single process of validation between save method and #ExceptionHandler makes things intricate. Currently I use some ad-hoc exception (like, ValidationException):
public #ResponseBody Result save(#Valid Entity entity, BindingResult errors) {
Result r = new Result();
if (errors.hasErrors()) {
r.setStatus(Result.VALIDATION_ERROR);
// ...
} else {
try {
dao.save(entity);
r.setStatus(Result.SUCCESS);
} except (ValidationException e) {
r.setStatus(Result.VALIDATION_ERROR);
r.setText(e.getMessage());
}
}
return r;
}
Can you offer some more optimal approach?
Yes, there is the good old established Java pattern of Exception throwing.
Spring MVC integrates it pretty well (for code examples, you can directly skip to the second part of my answer).
What you call "complex validations" are in fact exceptions : business key unicity error, low layer or DB errors, etc.
Reminder : what is validation in Spring MVC ?
Validation should happen on the presentation layer. It is basically about validating submitted form fields.
We could classify them into two kinds :
1) Light validation (with JSR-303/Hibernate validation) : checking that a submitted field has a given #Size/#Length, that it is #NotNull or #NotEmpty/#NotBlank, checking that it has an #Email format, etc.
2) Heavy validation, or complex validation are more about particular cases of field validations, such as cross-field validation :
Example 1 : The form has fieldA, fieldB and fieldC. Individually, each field can be empty, but at least one of them must not be empty.
Example 2 : if userAge field has a value under 18, responsibleUser field must not be null and responsibleUser's age must be over 21.
These validations can be implemented with Spring Validator implementations, or custom annotations/constraints.
Now I understand that with all these validation facilites, plus the fact that Spring is not intrusive at all and lets you do anything you want (for better or for worse), one can be tempted to use the "validation hammer" for anything vaguely related to error handling.
And it would work : with validation only, you check every possible problem in your validators/annotations (and hardly throw any exception in lower layers). It is bad, because you pray that you thought about all the cases. You don't leverage Java exceptions that would allow you to simplify your logic and reduce the chance of making a mistake by forgetting to check that something had an error.
So in the Spring MVC world, one should not mistake validation (that is to say, UI validation) for lower layer exceptions, such has Service exceptions or DB exceptions (key unicity, etc.).
How to handle exceptions in Spring MVC in a handy way ?
Some people think "Oh god, so in my controller I would have to check all possible checked exceptions one by one, and think about a message error for each of them ? NO WAY !". I am one of those people. :-)
For most of the cases, just use some generic checked exception class that all your exceptions would extend. Then simply handle it in your Spring MVC controller with #ExceptionHandler and a generic error message.
Code example :
public class MyAppTechnicalException extends Exception { ... }
and
#Controller
public class MyController {
...
#RequestMapping(...)
public void createMyObject(...) throws MyAppTechnicalException {
...
someServiceThanCanThrowMyAppTechnicalException.create(...);
...
}
...
#ExceptionHandler(MyAppTechnicalException.class)
public String handleMyAppTechnicalException(MyAppTechnicalException e, Model model) {
// Compute your generic error message/code with e.
// Or just use a generic error/code, in which case you can remove e from the parameters
String genericErrorMessage = "Some technical exception has occured blah blah blah" ;
// There are many other ways to pass an error to the view, but you get the idea
model.addAttribute("myErrors", genericErrorMessage);
return "myView";
}
}
Simple, quick, easy and clean !
For those times when you need to display error messages for some specific exceptions, or when you cannot have a generic top-level exception because of a poorly designed legacy system you cannot modify, just add other #ExceptionHandlers.
Another trick : for less cluttered code, you can process multiple exceptions with
#ExceptionHandler({MyException1.class, MyException2.class, ...})
public String yourMethod(Exception e, Model model) {
...
}
Bottom line : when to use validation ? when to use exceptions ?
Errors from the UI = validation = validation facilities (JSR-303 annotations, custom annotations, Spring validator)
Errors from lower layers = exceptions
When I say "Errors from the UI", I mean "the user entered something wrong in his form".
References :
Passing errors back to the view from the service layer
Very informative blog post about bean validation

Struts 2 Conditional Annotation Validation without XML

I have a form with several fields (i.e. a,b,c,d,...) and the project I am currently doing right now is using Annotations for form validation in Struts2. XML usage is being discouraged.
I need to check a certain condition before I will validate form elements b, c, and d.
I was able to do the following:
#Validations {
requiredStrings = {
#RequiredStringValidator(...),
#RequiredStringValidator(...),
}
}
public String doSomething(){
...
return SUCCESS;
}
Is there a way to do this in Struts2 Annotation alone? Most similar questions I have found in SO all tell me to use XML method. Thanks.
Use an expression validator, or write a custom validator.

How to make Spring accept fluent (non-void) setters?

I have an API which I am turning into an internal DSL. As such, most methods in my PoJos return a reference to this so that I can chain methods together declaratively as such (syntactic sugar).
myComponent
.setID("MyId")
.setProperty("One")
.setProperty2("Two")
.setAssociation(anotherComponent)
.execute();
My API does not depend on Spring but I wish to make it 'Spring-Friendly' by being PoJo friendly with zero argument constructors, getters and setters. The problem is that Spring seems to not detect my setter methods when I have a non-void return type.
The return type of this is very convenient when chaining together my commands so I don't want to destroy my programmatic API just be to compatible with Spring injection.
Is there a setting in Spring to allow me to use non-void setters?
Chris
Thanks to all (and especially Espen who went to a lot of effort to show me the various options within Spring).
In the end, I found a solution myself that doesn't require Spring configuration.
I followed the link from Stephen C then found a reference to the SimpleBeanInfo class within that set of Threads. This class allows a user to write their own bean method resolution code by placing another class in the same package as the class with the non-standard setters/getters to override the logic of with 'BeanInfo' appended onto the classname and implementing the 'BeanInfo' interface.
I then did a search on Google and found this blog which pointed the way. The solution on the blog was quite basic so I padded it out for my purposes.
Per Class (with fluent setters)
public class MyComponentBeanInfo<T> extends SimpleBeanInfo {
private final static Class<?> _clazz = MyComponent.class;
PropertyDescriptor[] _properties = null;
public synchronized PropertyDescriptor[] getPropertyDescriptors() {
if (_properties == null) {
_properties = Helpers.getPropertyDescriptionsIncludingFluentSetters(_clazz);
}
return _properties;
}
public BeanDescriptor getBeanDescriptor() {
return new BeanDescriptor(_clazz);
}
}
PropertyDescriptor generation method
public static PropertyDescriptor[] getPropertyDescriptionsIncludingFluentSetters( Class<?> clazz) {
Map<String,Method> getterMethodMap = new HashMap<String,Method>();
Map<String,Method> setterMethodMap = new HashMap<String,Method>();
Set<String> allProperties = new HashSet<String>();
PropertyDescriptor[] properties = null;
try {
Method[] methods = clazz.getMethods();
for (Method m : methods) {
String name = m.getName();
boolean isSetter = m.getParameterTypes().length == 1 && name.length() > 3 && name.substring(0,3).equals("set") && name.charAt(3) >= 'A' && name.charAt(3) <= 'Z';
boolean isGetter = (!isSetter) && m.getParameterTypes().length == 0 && name.length() > 3 && name.substring(0,3).equals("get") && name.charAt(3) >= 'A' && name.charAt(3) <= 'Z';
if (isSetter || isGetter) {
name = name.substring(3);
name = name.length() > 1
? name.substring(0,1).toLowerCase() + name.substring(1)
: name.toLowerCase();
if (isSetter) {
setterMethodMap.put(name, m);
} else {
getterMethodMap.put(name, m);
}
allProperties.add(name);
}
}
properties = new PropertyDescriptor[allProperties.size()];
Iterator<String> iterator = allProperties.iterator();
for (int i=0; i < allProperties.size(); i++) {
String propertyName = iterator.next();
Method readMethod = getterMethodMap.get(propertyName);
Method writeMethod = setterMethodMap.get(propertyName);
properties[i] = new PropertyDescriptor(propertyName, readMethod, writeMethod);
}
} catch (IntrospectionException e) {
throw new RuntimeException(e.toString(), e);
}
return properties;
}
Advantages to this approach:
No custom spring configuration (Spring is not aware of the non-standard setters and sees them as normal). No dependancy on any Spring .jar files but accessible from Spring.
Just seems to work.
Disadvantages to this approach:
I have to place create a BeanInfo class for all of my API classes with non-standard setters. Luckily there are only around 10 such classes and by moving the method resolution logic into a seperate class I only have one place to maintain.
Closing Thoughts
In my opinion, Spring should deal with fluent setters natively, they don't hurt anyone and it should just ignore the return value.
By requiring that setters be rigidly void, it has forced me to write a lot more boiler plate code than I would have needed otherwise. I appreciate the Bean Specification, but bean resolution is trivial using reflection without even using the standard bean resolver so Spring should offer the option of its own bean resolver that will handle this situations.
By all means, leave the standard mechanism as the default, but offer a one-line configuration option. I look forward to future versions where this might be optionally relaxed.
Is there a setting in Spring to allow me to use non-void setters?
The simple answer is No - there is no such setting.
Spring is designed to be compatible with the JavaBeans spec, and that requires the setters to return void.
For a discussion, refer to this Spring Forums thread. There are possible ways around this limitation mentioned in the forum, but there is no simple solution, and I don't think anyone actually reported that they had tried this and that it worked.
Spring can also be configured with Java configuration.
An example:
#Configuration
public class Config {
#Bean
public MyComponent myComponent() {
return MyComponent
.setID(id)
.setProperty("One", "1")
.setProperty("Two", "2")
.setAssociation(anotherConfig.anotherComponent())
.execute();
}
#Autowired
private AnotherConfig anotherConfig;
#Value("${id}")
private String id;
}
You have a nice immutable object. You have actually implemented the Builder pattern!
Updated to respond to Chris's comment:
I guess it's not exactly what you want, but using properties files solves some issues. See the id field in the example above.
Else, you can use Spring's FactoryBean pattern:
public class MyComponentFactory implements FactoryBean<MyComponent> {
private MyComponent myComponent;
public MyComponentFactory(String id, Property propertyOne, ..) {
myComponent = MyComponent
.setID(id)
.setProperty("One", "1")
.set(..)
.execute();
}
public MyComponent getObject() throws Exception {
return myComponent;
}
public Class<MyComponent> getObjectType() {
return MyComponent.class;
}
public boolean isSingleton() {
return false;
}
}
With the FactoryBean, you shield the configuration from the object returned from the getObject() method.
In the XML configuration, you configure the FactoryBean implementation. In this case with <constructor-arg /> elements.
One simple suggestion, it is customary not to use setters, but the properties names themselves. So have a setter, and have another method for the builder:
component.id("MyId")
.property("One")
.property2("Two")
.association(anotherComponent)
.execute();
As far as I know, there is no simple switch. Spring uses the Beans convention, and expects a void setter. Spring works with beans at the property level via an instance of the BeanWrapper interface. The default implementation, BeanWrapperImpl, uses introspection, but you could create your own modified version that uses reflection to find methods matching your pattern.
EDIT: Looking at the Spring code, BeanWrapperImpl is hard-wired into the bean factories, there is no simple way to replace this with another implementation. However, as spring uses introspection, we can work on getting java.beans.Introspector to produce the results we want. Here are the alternatives in order of decreasing pain:
change the method signature on your setters to comply.
implement your own BeanInfo classes for each of your beans
Use reflection to plug dynamically generated BeanInfo classes into the introspector.
The first two options are probably not really options for you, as they involve quite a lot of changes. Exploring the third option in more detail:
To know which beans are being instantiated by spring, implement your own BeanFactoryPostProcessor. This gets to see all the bean definitions before they are used by the BeanFactory. Your implementation iterates over all the BeanDefinitions in the factor, and fetches the bean class from each definition. Now you know all the classes that are being used.
With a list of classes, you can set about creating your own BeanInfos for these classes. You use the Introspector to generate the default BeanInfo for each class, which would give you read-only properties for your properties with return value setters. You then create a new BeanInfo, based on the original, but with PropertyDescriptors referencing setter methods - your return value setters.
With new beanInfos generated for each class, you need to make sure that the Introspector returns these when asked for the beaninfo for your class. The introspector has a private Map that is used to cache beanInfos. You can get hold of this via reflection, enable access - setAccessible(true) - and add your BeanInfo instances to it - map.put(Class,BeanInfo).
When spring asks the Introspector for the BeanInfo for your bean class, the introspector returns your modified beanInfo, complete with setter methods mapped to your setters with return values.
As others have said, it's not just Spring-friendliness you risk losing. A non-void setter isn't really a setter as far as JavaBeans are concerned, and all sorts of other tools (validators, marshallers, viewers, persisters, whatever else you can dream up) will probably use Introspector and BeanInfo, which expect setters to be null.
With this in mind, how flexible is the requirement that they be called setX? A lot of fluent interfaces in Java use withX instead. If you're using Eclipse, you can probably create a code generation template to make X getX(), void setX(X x), and X withX(X x) for you. If you're using some other codegen tool, I can imagine adding withX fluent setter/getter methods would also be easy.
The with word seems a bit odd, but when you see it alongside a constructor it reads really well.
Request r = new Request().withEndpoint("example.com")
.withPort(80)
.withSSL(false)
.withFoo("My Foo");
service.send(r);
One such API is the AWS SDK for Java, which you can consult for examples. An off-topic caveat is that boolean getters may be called isX, but Boolean getters must be called getX.

Categories