For example, I have a class like this
public class RegisterDto implements IRegisterDto {
@Length(min = 2, max = 255)
String alias;
@Valid
@NotNull
EmailDto email;
@Valid
@NotNull
Password password = new Password();
@StringEnumeration(enumClass = Role.class)
String type;
String timeZone;
}
And nested class like this
public class Password implements IPassword {
public Password(String password) {
this.password=password;
}
public Password() {
}
@Length(min = 8, max = 255)
@NotEmpty
String password;
}
That example works perfectly with Spring MVC Form Binding. For nested classes, we need to have a constructor with String argument, and Property with the same name as field in form. There is probably more tricks like that, but they are not documented very well.
So, I want to have a validation for nested fields with @Valid annotation. I modified AnnotationExtractor for such functionality
/**
* Return annotations for a given field name
*/
private List<Annotation> fieldAnnotations() {
Field field = this.fieldFinder.findField(this.targetClass, this.targetFieldName);
if (field != null) {
List<Annotation> annotations = Arrays.asList(field.getAnnotations());
List<Annotation> toAdd = new ArrayList<>();
for(Annotation a:annotations)
if(a.annotationType().isAssignableFrom(Valid.class)){
Field nestedField = this.fieldFinder.findField(field.getType(), this.targetFieldName);
if(nestedField!=null)
toAdd.addAll(Arrays.asList(nestedField.getAnnotations()));
}
toAdd.addAll(annotations);
return toAdd;
}
return Collections.emptyList();
}
It's not a perfect code, but working well in my case. There is probably better solution for somebody, who known code of this library better than me.
By the way, that project is a great time saving thing. Thanks for that!
a little bit cleaner solution
Hi,
thanks for using the dialect, we appreciate your feedback.
This library is focused on translate server validation to HTML5 client validation,
so @Valid does not match this prerequisite.
The annotation @Valid gives an indication to check the validity of the annotated field itself but, it doesn't define any validation rule unlike @Email for example, that establishes some sort of restrictions to the annotated field related to e-mail address formatting.
In the example and the patch that you provided as a solution, there're some conditions not generally applicable.
Well, the good news.
Html5ValidationDialect supports nested classes, so your Password class should be validated as well.
The point here underlies in the HTML form and the validation object, RegisterDto.
In order to validate the password field, given your classes structure, your HTML should look like:
This should work. Ensure the th:field attribute for the password field references the final property in the field chain.
You can find in the AnnotationExtractorTest unit test a similar use case.
As an exercise, you can write your own test to check that could look like:
Final thoughts.
Yep, I know about the @Valid is special case of JSR303 Annotation. That's why I cannot provide solution by implementing custom ValidationPerformer.
That is a default meaning of @Valid, right?
Yep, that is true. I will probably need to find all annotations nested field.
That's a pretty elegant solution. Only a little more chance to have a typo.
I'm doing nested fields to share validation rules between many forms.
I already have a 2 layers. That's a data transfer object, with minimum logic (only custom conversions between types).
Now I'm doing much more experiments in that library. In example, I need to have a possibility to override default ValidationPerformers behavior, so I changed ValidationPerformerFactory.performers to Map.
I will probably post better solution, for such problem, soon.
Last edit: globalbus 2015-04-18