5

I'm trying to do a nested validation in my Spring application.

public class Parent{

   public interface MyGroup{}

   @NotNull(groups = MyGroup.class)
   private Child child;

   // getters and setters omited

}

public class Child{

   public interface OptionalGroup {}

   @NotBlank(groups = OptionalGroup.class)
   private String aField;

}

I already looked at @Valid from javax.validation package but it doesn't support group. I also checked @Validated annotation from spring but I can't applied it on a field.

I want to do something like :

public class Parent{

   public interface MyGroup{}

   @NotNull(groups = MyGroup.class)
   @CascadeValidate(groups = MyGroup.class, cascadeGroups = OptionalGroup.class) 
   // 'groups' correspond to parent group and 'cascadeGroups' to a group that needs to be apply to the Child field.

   private Child child;

}

And then I can pragmatically do wherever I want:

@Inject SmartValidator validator;

public void validationMethod(Parent parent, boolean condition) throws ValidationException {
   if(condition){
      MapBindingResult errors= new MapBindingResult(new HashMap<>(), target.getClass().getSimpleName());

      validator.validate(parent, errors, Parent.MyGroup.class); // validate all constraints associated to MyGroup

      if(errors.hasErrors()) throw new ValidationException(errors); // A custom exception
   }

}

Any ideas how to do that?

Thanks a lot

LG_
  • 1,999
  • 1
  • 16
  • 21
  • `@Validated` is for specifying which groups to use when validating. So when submitting a form from the web only validate those groups specified. You can specify 0 or more groups to use for validating. – M. Deinum Sep 07 '15 at 11:10
  • Yes I can not achieve what I want with this annotation but I talked about it because of its philosophy. My question is not related to forms or web, only to cacascading validation groups – LG_ Sep 07 '15 at 12:14
  • That is't really related to Spring but on how bean validation works. Spring doesn't add anything to it. – M. Deinum Sep 07 '15 at 12:15
  • Alright. I am looking for something different. I want to be able to write @CascadeValid(groups = MyParentGroup.class, subgroups = MyChildGroup.class) on a field of my parent object. Then with this annotation, I want my validator to be able to detect it and launch nested validation on my child object. – LG_ Sep 07 '15 at 12:20

1 Answers1

7

I finally found the solution. Actually I misunderstood what @Validwas made for.

The key is to declare same group for Parent and child attribute.

Solution :

public class Parent{

   public interface MyGroup{}

   @NotNull(groups = MyGroup.class)
   @Valid // This annotation will launch nested validation
   private Child child;

   // getters and setters omited

}

public class Child{

   @NotBlank(groups = Parent.MyGroup.class) // Declare same group
   private String aField;

}

In this case, when I do :

 @Inject SmartValidator validator;

public void validationMethod(Parent parent, boolean condition) throws ValidationException {
   if(condition){
      MapBindingResult errors= new MapBindingResult(new HashMap<>(), target.getClass().getSimpleName());

      // validate all constraints associated to MyGroup (even in my nested objects)
      validator.validate(parent, errors, Parent.MyGroup.class); 

      if(errors.hasErrors()) throw new ValidationException(errors); // A custom exception
   }

}

If a validation error is detected in my child field 'aField', the first associated validation error code (see FieldError.codes) will be 'NotBlank.Parent.afield'.

I should have better checked @Valid documentation.

LG_
  • 1,999
  • 1
  • 16
  • 21