Validating wizard pages with Spring 3 - spring

I started researching how to create a controller for a wizard-like form in Spring and came across the AbstractWizardFormController, which I quickly noticed was deprecated.
I then dug a bit further and found how to accomplish something similar with Spring 3. This example does not do any sort of validation though (e.g. via #Valid), so I'm wondering how does one validate each step of a wizard?
Would it be possible for each step have its own backing Form object and then use #SessionAttributes to store their values for when a final submit is called (presumably on the last page of the form)?
Thanks for any help.
(P.S.: Solutions that don't require WebFlow would be ideal.)

I don't know of a way to pull this off with the #Valid annotation, but you should be able to take advantage of the JSR-303 validation to accomplish this. As a somewhat contrived example:
public class User {
#NotNull(message = "First name can't be blank", groups = {Step1.class, FinalStep.class})
private String firstName;
#NotNull(message = "Last name can't be blank", groups = {Step1.class, FinalStep.class})
private String lastName;
#NotNull(message = "Email can't be blank", groups = {Step1.class, FinalStep.class})
private String emailAddress;
#NotNull(message = "Please provide a valid address", groups = {Step2.class, FinalStep.class})
private Address address;
// getters/setters...
public interface Step1 {}
public interface Step2 {}
public interface FinalStep {}
}
You can take advantage of the fact that JSR-303 supports validation groups by providing marker interfaces to represent your wizard steps.
Then, instead of relying on the #Valid annotation, inject a Validator instance into your controller and call:
validator.validate(user, /*<step interface>.class*/);
in your processPage method (referencing Controller in your linked question), and then
validator.validate(user, FinalStep.class);
in your processFinish call.

Use #Validated.
From Spring's documentation:
Variant of JSR-303's Valid, supporting the specification of validation groups. Designed for convenient use with Spring's JSR-303 support but not JSR-303 specific.
Can be used e.g. with Spring MVC handler methods arguments. Supported through SmartValidator's validation hint concept, with validation group classes acting as hint objects.
Can also be used with method level validation, indicating that a specific class is supposed to be validated at the method level (acting as a pointcut for the corresponding validation interceptor), but also optionally specifying the validation groups for method-level validation in the annotated class. Applying this annotation at the method level allows for overriding the validation groups for a specific method but does not serve as a pointcut; a class-level annotation is nevertheless necessary to trigger method validation for a specific bean to begin with. Can also be used as a meta-annotation on a custom stereotype annotation or a custom group-specific validated annotation.

Related

Where to validate uniqueness of field in Spring/Hibernate

I am building a REST API using spring and hibernate. I have come across the issue where I want to create a user and want to know the best practice on how to validate that the user can be created.
My controller has the #Valid annotation on the User object that gets passed into the method, and this checks for valid structure, however there is no #Unique property that gets picked up by #Valid.
I am using the #Column(unique = true) but this throws an error at the persistence level and I feel like that is quite low level and makes it difficult to throw a custom UsernameAlreadyExistsException().
My question here is what is the best practice in terms of preforming this type of validation. I thought about creating a custom annotation but it seems quite messy especially because as the project grows I would need multiple validators for different fields and it also seems to be closley related to tying the service layer to the annotation which seems messy
In my opinion, using custom annotation is the best approach to do stuff like this, you can inject some bean in ConstraintValidator and perform validation. However you can try one of the below unusual approaches, maybe it will fit your requirements.
Spring AOP
Spring Handler Interceptor
JPA Event Listeners
It's just my opinion about this, in most cases I think I will create custom annotations to handle it.
A good practice would be to put validation both on the database (which we know nothing about, but it is not complicated really) and on the Spring's side.
As #kamil-w already said, a good is to write custom constraint validator, see here for an example.
Keep in mind that you can always pass parameters like to constraint annotation, and then access them in your ConstraintValidator, for example.:
#Entity
public class Member {
// ...
#UniqueField(fieldName = "login", context = Member.class)
private String login;
}
#Component
public class UniqueFieldValidator implements ConstraintValidator<UniqueField, Object> {
#PersistenceUnit
private EntityManagerFactory emf;
private Class validationContext;
private String fieldName;
#Override
public void initialize(UniqueField uniqueField) {
this.validationContext = uniqueField.validationContext();
this.fieldName = uniqueField.fieldName();
}
#Override
public boolean isValid(Object value, ConstraintValidatorContext cxt) {
// use value, this.validationContext, this.fieldName and entity manager to check uniqueness
}
}

#Valid annotation on selected fields only

I have an account class where I use notations as follows:
#NotNull
private String name;
In account there are many fields, which I use independently in two forms. The issue is that as my first form doesn't contain
private String name;
When I submit the form the validation check fails as a field that isn't in the actual form is being checked.
Essentially the validation will always fail as the variable is in the same class but isn't being used in this particular form.
To get around this would I have to use the Spring Validator class?
Thank you.
I think you may not overcome this kind of problem while having validation annotations. But you can try these:
Create two custom classes for two forms and validate name just for one of them, and do not validate for another.
And also you can try to validate your own field manually in the controller method. Autowire validator class, and validate inside the method.
#Autowired
Validator validator;
public methodA(Model model, #ModelAttribute("modelA") ModelA modelA, BindingResult result){
validator.validate(modelA, result);
if (result.hasErrors()){
// do something
}
else {
// do something else
}
}

Spring Custom Validation With Dynamic Values?

I have a form that has two fields:
<input id="password"...
<input id="confirmpassword"...
I have a form binding object that binds to these two variables.
class FormBindingClass
{
private String password;
private String confirmPassword;
......
......
}
Now I validate the above two fields using #NotEmpty and #Pattern validators, however I need to make sure that confirmPassword matches the password on the server side!
If it does not then I need to fail the binding result and show the error back to the user. How can I accomplish this? I explored making custom annotations something like:
#MustMatch(password)
private String confirmPassword;
But I cannot pass dynamic values to annotation can I? How can I solve this tricky issue.
This is a validation at your dao layer andfor which ina general case you would throw an exception to the web layer and handle apprppriately.So you have to manually validate this in your business logic and construct the error response at the web layer.
The spring MVC validations are basically for form backed data and which doesn't have any business logic dependency.

Spring Validation

I am trying to use something of this sort in my Command Object for Spring.
#NotBlank
private String carrier;
#NotBlank(applyIf = "this.carrier EQUALS 'GlobalCrossing'")
private String port;
Please let me know, if this is possible. The field carrier can have many values, If the value is GlobalCrossing then a not blank check should be applied on port field.
Can I do this with spring validation modules or there is another way of achieving the same?
Since your validation is order dependent (i.e. carrier must be set before port) you might want to perform your validation post initialization.
In Spring, you can do any of these to create an initialization callback method:
Implement the org.springframework.beans.factory.InitializingBean interface.
Declare an initialization method with the init-method attribute (of the bean tag).
Declare a default initialization method for your beans with the default-init-method attribute (of the beans tag).
However you do it, you can then perform the validation in the initialization callback method.
Here is a link to the reference for initialization callbacks.
Since you can annotate also methods you can try this.
import javax.validation.constraints.*;
.
.
.
#AssertTrue
private boolean isPortNotBlankIfCarrierEqualsGlobalCrossing() {
return carrier.compareTo("GlobalCrossing") == 0 ? port.isBank() : true;
}

Spring Framework validate request parameter or path variable

I know I can validate forms in Spring, but can I apply similar validate to URL parameters? For example, I have a method in my controller as follows:
public String edit(#PathVariable("system") String system,
#RequestParam(value="group") String group,
ModelMap model) throws DAOException {
Can I validate the values of system and group before the method is called, to ensure they are of a certain value or match a certain regex?
Thanks
You may be able to use Spring Asserts for this. The Assert api (http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/util/Assert.html) runs a supplied expression against the specified parameters and if the expression equates to false then it throws an exception.
Ex:
Assert.isTrue(system.equals("ValidSystemName"), "You must supply a valid system");
It also contains functions to check that parameters are not null or are not empty strings, etc.
Create an annotation that marks parameters that should be validated. This annotation needs a #Retention of RUNTIME and a #Target of ElementType.PARAMETER.
Create a validator implemented as an AspectJ Aspect.
Wrap calls to controllers with this validator.
A sample annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
#Documented
public #interface ValidSystemParameter {
}
A sample validator:
#Aspect
public class ValidSystemParameterValidator {
#Pointcut("TODO: write your pointcut expression")
public void controllerMethodWithValidSystemParameter();
#Before(pointcut = "controllerMethodWithValidSystemParameter()")
public void validateSystemParameter(String systemParameter) {
// validate the parameter (throwing an exception)
}
}
To learn about the AspectJ pointcut expression language see: http://www.eclipse.org/aspectj/doc/released/progguide/language-joinPoints.html
To learn about AspectJ integration in Spring see: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-ataspectj
I might be a little late, but with Spring 3.0 you have the option of using JSR-303 validation with the #Valid annotation. There are also some more specific annotations as #DateTimeFormat and #NumberFormat. More details here: http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/validation.html#validation-mvc
As I see it you have two options:
Define your request parameters as objects and user JSR-303
validation.
Use the Assert api as mentioned above.
If you just want to make a simple validation on a single value, I would go with the latter (that's what I did when I had simple int values to check for max value).

Resources