Complex Spring form validation using javax.validation - spring

What I'm trying to accomplish is:
Have a bean backed form being validated, for example using the following class
public class PersonForm {
#NotNull
String name;
List<Long> interests;
// This attribute is not filled out in the form
List<Interest> realInterests;
}
So, "name" and "interests" come from the web form. "name" has some constrains (NotNull) and using #Valid does what it is supposed to do.
"interests" is a list of Interest ids.
After doing the initial validation of the "name" I fill out the List collection.
#CustomValidInterest
public class Interest {
Long id;
String name;
boolean available;
}
I want to validate this structure afterwards. "#CustomValidInterest" is a custom validation annotation.
I can do a 2-stage validation using do this with Validation Groups.
The problem is, if some "Interest" object is not valid I want to associate the error message with the "interests" field (List< Long > type), so when I retrieve the form errors the error is associated with the right field.
Maybe I'm trying to use validation the wrong way. I was trying to avoid having a bunch of programmatic comparisons which filled errors manually.

Answering my own question, this is achievable using PropertyEditors. The form might return a List< Long > but the form object can have only a List < Interest > which is built using said Property mapper. After that a #Valid on that list should validate any constraints that "Interest" enforces.

Related

How to handle "Save as draft" with Hibernate validation annotations

Say I have a simple form with the following field the user has to fill in:
name
surname
birth date
address
The data needs to be saved in a database table with the same fields/columns. All the columns are not nullable.
The form offers two buttons: "Save" and "Save as draft" to let the user finish compiling the form later.
The first will check if all the fields are correctly filled whereas the second doesnt make any check other than "cannot insert number in name field".
I tend to use Hibernate Validation annotations on my DTO, but in this case will break the function "Save as draft".
How would you handle this scenario?
Technologies I'm using: Spring Boot/MVC to expose the REST service consumed by frontend, hibernate/Spring DATA to save data to database.
You can use a validation function instead of annotations directly on the attributes. That way your validation can have some logic in it.
#Value
class MyDto{
String name;
String surname;
DateTime birthdate;
Address asdress;
boolean draft;
#AssertTrue
private boolean validateInstance(){
if(!isDraft()){
// do validation
}
return true;
}
}
Create an interface for your entry and create two implementations of that interface.
One being the actualEntry with the annotations.
The other being the draft without those annotations.

How to validate a single field in a Spring bean?

It seems like the preferred way to validate a spring annotated bean is by using #valid, like in the block below, however I want to display error messages one field at a time still using Spring annotations. I know I can validate the whole form after each field and show only messages for a single field, but that is inefficient, anyone know of a better way?
#RequestMapping(value="/register",method=RequestMethod.POST)
public #ResponseBody RegisterResponse registerSubmit(#Valid #ModelAttribute("registerData") Register registerData, BindingResult result ){
RegisterResponse rr= new RegisterResponse();
if(!result.hasErrors()) {
rr.setStatus("SUCCESS");
rr.setResult(result);
}
else {
rr.setStatus("FAIL");
rr.setResult(result.getAllErrors());
}
return rr;
}
Return from the Validator#validate method upon hitting the first Error.
For this
You need to have a Custom Validator implementing org.springframework.validation.Validator where you have control of validating the fields in the order you need, whereas, using #Valid annotation will validate all the fields in your Form Bean and return the BindingResult for all the fields.
I was able to make things work by filtering out the errors that had an empty/null fields, this does work but is a bit inefficient since we validate entire bean even though we care for the first field. I'd love to hear of a better way to accomplish this kind of step by step form field validation.
I used something like the following:
private List<ObjectError> removeEmpties(BindingResult result) {
List<ObjectError> errors = result.getAllErrors();
ArrayList<ObjectError> myErrors = new ArrayList<ObjectError>();
for(ObjectError error: errors){
FieldError realThing = (FieldError) error;
if (realThing.getRejectedValue()!=null && !realThing.getRejectedValue().toString().isEmpty()){
myErrors.add(error);
}
}
return myErrors;
}

Play framework 2: one model approach

The problem:
When programming with play framework I feel that I'm stumbling with same problem than in many times at the past which is creating several models of the same type just because I want to add, update or use different data about certain model in different use cases.
Let me explain, lets consider of a example where I have 2 different views: register and login
I would have following User model:
/**
* Example User class (simple annotations for demo purposes).
*
*/
#Entity
public class User {
#Id
public Long id;
#Required
public String email;
#Required
public String password;
#Required
public String firstName;
#Required
public String lastName;
}
In case of registering: I would have all corresponding fields in register.scala.html : email, password, firstName, lastName - because I will need them all when I register, right?
But also I would want to use repeatPassword field to confirm that user has typed password correctly, so I would add this into User model:
#Required
#Transient
public String repeatPassword;
Ok, then I would extend this model to have repeat password confirmation check in order to correct my "automatic" validations when form is submitted, like this:
public String validate() {
if(!password.equals(repeatPassword)) {
return "Passwords doesn't match.";
}
return null;
}
}
So even now I would have one extra attribute repeatPassword which is not persisted to database but used within registration.
Problem #1: Our model starts to go confusing piece by piece.
In case of login: I would want to use same model because its a User which is trying to sign in, right? But instead of all the fields I would only need email, password.
Problem #2: My User model cant be used in login because its already customized to be used within registration - I would need to move repeatPassword and validate() method to separate UserRegistation model, plus duplicate firstName lastName etc. fields or mix using both User and UserRegistration model within registration and to render two different forms to same registration view = confusing.
Problem #3: My login page cant use User model because it has annotations in place, if I dont add all the necessary fields like firstName, lastName etc. I will get errors. Again, I would need to create separate UserLogin model just because I want to login to work.? Example below:
public class UserLogin {
#Required
public String email;
#Required
public String password;
public String validate() {
if(User.authenticate(email, password) == null) {
return "Invalid user or password";
}
return null;
}
}
So very fast, I would have 3 different models just to represent User, one of them is persisted to database and two others is used to validate errors when we are completing login and registration functionality at template side.
So my question is: How on earth I should begin to solve this mess? code complexity is rising very fast :) Should I create separate models.template and models.database packages where template models are only ones within annotations and in case of no errors I start to fill real model before saving or updating its info to database? I need desperately answers from you guys/girls, Can we make one model approach? thnx in advance.
I'll start from the end: you don't need to use whole model for changing password or loggin-in (also you don't need to create separate, 'non-persisted' sub-models), although Form<YourModel> is useful while filling large objects, you can just avoid them and rely on common DynamicForm.
In such case of course it won't use constraints added with annotations to the model's fields but you can validate them manually.
For an example: in registration form you can check if #Required fields like email, firstName, lastName exists (tip: also add MinLength and MaxLength constraints), but you should remove #Required annotation from password field.
Next after checking if the form hasn't any errors you can check if password and repeatedPassword are the same and it they are identical you can also add some individual (advised) strength check - most probably it wouldn't be possible with the annotations in the model.
In case of logging form the thing is ever easier: using DynamicForm data just try to find existing User with given password if result is null that means, the user doesn't exists or password is invalid.
Finally, tip: There is ready-to-use, full-stack authentication and authorisation module available for Play 2.0 by Joscha Feth (and I'm huge advocate of this solution.)

How to programatically turn on/off a Data Annotation Validation Attribute

So, I am using ASP.NET MVC 3 and Entity Framework 4.1 (code-first).
I have a class like this:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
[Range(18, 99)]
public int Age { get; set; }
}
The range validation is fired correctly. But, for example, in some situations I would like to change the range for the Age attribute. Or even turn it off. How could I do it without changing my Model class? Is this possible to made programatically?
You can use the IValidatableObject interface and define custom validation rules.
See my answer at:
Using Data Annotations to make a field required while searching for another in a form mvc 3
Its usually just a matter of implementing the interface and determine when to enforce your rules.
I just realised the solution for this case.
Eg. A user can have an authorization to create a 14 years old person.
Before save the Model, we can invoke DataContext.GetValidationErrors() and infer if the only error validation is that we want to disable, and then set
DataContext.Configuration.ValidateOnSaveEnabled = false;
So, this way we are able to save the model.
Yes, it is possible to inject validators programmatically. Altering existing validators presents separate issues, as some attributes are read-only, so you may have to delete and replace your existing validator.
You can add a class to work on the validators by following my answer to this question.

In Spring MVC 3, how do I bind an object to a query string when the query string parameters don't match up with the object fields?

A 3rd party is sending me part of the data to fill in my domain object via a query string. I need to partially fill in my domain object, and then have the user fill in the rest via a form. I don't have any control over the query string parameters coming in, so I can't change those, but I'd really like to be able to use Spring MVC's data binding abilities, rather than doing it by hand.
How can I do this?
To add some complication to this, some of the parameters will require extensive processing because they map to other objects (such as mapping to a user from just a name) that may not even exist yet and will need to be created. This aspect, I assume, can be handled using property editors. If I run into trouble with this, I will ask another question.
Once I have a partially filled domain object, passing it on to the edit view, etc. is no problem, but I don't know how to properly deal with the initial domain object population.
The only thing I have been able to come up with so far is to have an extra class that has it's properties named to match the inbound query parameters and a function to convert from this intermediary class to my domain class.
This seems like a lot of overhead though just to map between variable names.
Can you not just have the getter named differently from the setter, or have 2 getters and 2 setters if necessary?
private int spn;
// Standard getter/setter
public int getSpn() {
return spn;
}
public void setSpn(int spn) {
this.spn = spn;
}
// More descriptively named getter/setter
public int getShortParameterName() {
return spn;
}
public void setShortParameterName(int spn) {
this.spn = spn;
}
Maybe that is not standard bean convention, but surely would work?

Resources