Spring Custom Validation With Dynamic Values? - spring

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.

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
}
}

What is the best way to pass values from jsp to controller in Spring mvc

I have a jsp page that is dynamic configured. By different choice, the page has different components, just like dropdown list, list box and datetime etc. For one choice, the page may have only two dropdown list, and by another choice, the page has more enter field. Each enter field has different name. Even one page has two dropdown lists, the two lists have different names.
Just want to get your suggestion, what is the best way to get all these values to controller in Spring MVC.
I would do it as follows:
JSP: enclose all the input fields (textbox/select/checkbox/radio) in <FORM> tags and set the action attribute of the form to call the Controller.
Controller:
Define a simple Java bean class with attributes corresponding to each of the input field in the form
Accept this class type as a parameter to the method in the controller that will be called upon <FORM> submission and annotate the parameter with #RequestBody.
See Mapping the response body with the #ResponseBody annotation for more details on completing the wiring.
Create a DTO to hold all possible form element
Class MyFormData {
private String name;
private Double salary;
private List<String> hobbies;
......
}
In controller, use #ResponseBody
#RequestMapping(value = "/something", method = RequestMethod.POST)
public void handle(#RequestBody MyFormData formData, Model model) {
...
}
If your UI is so dynamic, you might as well bite the bullet and go for a Javascript solution. Spring MVC will simply receive and return JSON as #RequestBody and #ResponseBody and not worry so much about the fundamental MVC.
JSP can only get you so far in terms of dynamic UI behavior. Once you get comfortable with JQuery and/or AngularJS, you'll never look back.

hibernate validation - validate one of two paths

I use Spring MVC and Hibernate Validator. I have a OrderForm where you can choose from different payment methods. You have a radio button where you choose your payment method and enter the relevant parameters for the chosen payment methods.
Of course, if someone has chosen "Direct Debit" I don't want validation errors within the "PayPal" Form. At the time I do it like this:
public class OrderForm
{
#NotNull
private Integer customerId
private PaymentMethodDebitForm paymentMethodDebitForm;
private PaymentMethodPayPalForm paymentMethodPayPalForm;
private String paymentSelection;
#Valid
public PaymentForm getPaymentForm ( )
{
if (paymentSelection.equals("PayPal"))
{
return paymentMethodPayPalForm;
}
return paymentMethodDebitForm;
}
This way the validator gets only the form of the selected payment method.
I have two problems.
Spring generates error codes for this with the name of the abstract superclass ("PaymentForm") and not the concret class ("PaymentMethodDebitForm"). As I use this form at a different place as the concrete subclass, I get two different codes resolved. I worked around this by setting the code in the forms:
public class PaymentMethodDebitForm extends PaymentForm
{
#NotNull
#Size(min = 3, max = 50, message = "{paymentMethodDebitForm.iban.Size}")
private String iban;
}
In my jsp I need to refer to the concrete class when I render input field and refer to the super class when I render the error:
<form:input path="paymentMethodDebitForm.iban" size="40" maxlength="50" />
<form:errors path="paymentMethodForm.iban" />
not so nice.
How do you handle polymorphic stuff when it comes to forms and validation with spring/hibernate? Is there some advice how to handle situations like this?
I think I would try to use validation groups via <f:validateBean validationGroups="..." /> or I would separate the forms. This is also discussed here - Validating different Validation Groups JSF 2.0

Validating wizard pages with Spring 3

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.

Resources