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
}
}
Related
I am developing an application using Spring MVC 3 annotated style controllers. In some ocassions I need to add/modify some field values depending on session variables or some other condition. To complicate things, the field may have a fixed value if some condition is matched, and read user input if not. The question is: There is a way to modify the form after binding but before validation using spring mvc 3? It was quite simple with SimpleFormController (onBind method), but I can't find a way in spring mvc 3.
An example:
a) I initialize the binder for my form. Add a validator, set the list of allowed fields, and add a list of generic property editors
#InitBinder(value = COMMAND_NAME)
#Override
public void initBinder(final WebDataBinder binder, final HttpServletRequest httpServletRequest) {
binder.setValidator(reenvioAsientoValidator);
binder.setAllowedFields(ReenvioAsientoForm.getListaCamposPermitidos());
.... Add some custom property editors for booleans, integers ....
}
b) Create model object
#ModelAttribute(value = COMMAND_NAME)
public ReenvioAsientoForm rellenaModelo(final HttpServletRequest httpServletRequest) {
final ReenvioAsientoForm form = new ReenvioAsientoForm();
... Add some field values, which cannot be modified by user ...
return form;
}
c) Binding happens: And it can modify any field that is in the allowedFields list. Even those I setted in phase b)
d) THIS IS WHAT I CAN'T DO. I need to set/modify some fields of the form. Can't be done in the create model phase, because those fields are in the allowedFields list (Depending on different conditions, they can be readonly or accept user input)
e) Validation happens
f) Controller POST method is invoked
#RequestMapping(value = URI_REENVIO_ASIENTO, method = RequestMethod.POST)
public ModelAndView submit(#Valid #ModelAttribute(COMMAND_NAME) final ReenvioAsientoForm form, final BindingResult result, HttpServletRequest request) {
.....
}
Somethings I've tried:
Modify inside validator, before validation: That is a possible solution, but I find it nasty, because I am using the validator for something it is not intended. Plus it only works if the form is validated.
Using a CustomPropertyEditor. This way I can check the condition and set the value during binding. The problem is that the binder is fired only if a the property is present in the request. If there were someway to fire it always, it would be a nice solution
The easiest workaround is to avoid using #Valid to trigger validation.
#Autowired
Validator validator;
#RequestMapping(value = URI_REENVIO_ASIENTO, method = RequestMethod.POST)
public ModelAndView submit(#ModelAttribute(COMMAND_NAME) final ReenvioAsientoForm form, final BindingResult result, HttpServletRequest request) {
// here comes the custom logic
// that will be executed after binding and before validation
// trigger validation
validator.validate(form, result);
// handle validation result and return view name
...
}
See related issue in Spring JIRA and the explanation that such hook / annotation won't be implemented - #MVC should provide an "onBind" hook prior to automatic validation.
Or I'm doing smth wrong, or it's really not suitable to work together. I'm talking about nested entities, since almost each Hibernate entity has it.
Here's the simple entity:
#Entity
...
public class Car implements Serializable {
String name;
#ManyToOne Category category;
...
}
And the simple controller as well:
#RequestMapping(value = "/cars/add", method = RequestMethod.POST)
public void add(Car car) {
// persist the car here
}
Now I want to specify a category directly from the form. Since it isn't simple object but entity, I'm unable to do that, isn't it?
So, to specify the category seems I'm forced to send it separately from Car object... It's ugly approach that makes no sense to use Hibernate with Spring at all.
Or I'm wrong and there're ways better a lot?
How your form structure is?
I suggest you to use json(means #RequestBody in controller) to submit the form or use #CommandObj to submit the form
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.
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
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.