Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSR-303 validation groups define a default group

I have a bean that has a lot of fields annotated with JSR-303 validation annotations. There is a new requirement now that one of the fields is mandatory, but only in certain conditions.

I looked around and have found what I needed, validation groups.

This is what I have now:

public interface ValidatedOnCreationOnly { }  @NotNull(groups = ValidatedOnCreationOnly.class) private String employerId; @Length(max = 255) @NotNull private String firstName; @Length(max = 255) @NotNull private String lastName; 

However, when I run this validation in a unit test:

@Test public void testEmployerIdCanOnlyBeSetWhenCreating() {     EmployeeDTO dto = new EmployeeDTO();      ValidatorFactory vf = Validation.buildDefaultValidatorFactory();     Set<ConstraintViolation<EmployeeDTO>> violations = vf.getValidator().validate(dto, EmployeeDTO.ValidatedOnCreationOnly.class);      assertEquals(violations.size(), 3); } 

It turns out that all of the non-group annotated validations are ignored and I get only 1 violation.

I can understand this behaviour but I would like to know if there is a way I can make the group include all non-annotated parameters as well. If not I'd have to do something like this:

public interface AlwaysValidated { }  public interface ValidatedOnCreationOnly extends AlwaysValidated { }  @NotNull(groups = ValidatedOnCreationOnly.class) private String employerId; @Length(max = 255, groups = AlwaysValidated.class) @NotNull(groups = AlwaysValidated.class) private String firstName; @Length(max = 255, groups = AlwaysValidated.class) @NotNull(groups = AlwaysValidated.class) private String lastName; 

The real class I'm working with has a lot more fields (about 20), so this method turns what was a clear way of indicating the validations into a big mess.

Can anyone tell me if there is a better way? Maybe something like:

vf.getValidator().validate(dto, EmployeeDTO.ValidatedOnCreationOnly.class, NonGroupSpecific.class); 

I'm using this in a spring project so if spring has another way I'll be glad to know.

like image 395
Geoffrey De Vylder Avatar asked Feb 12 '16 08:02

Geoffrey De Vylder


People also ask

What is JSR 303 Bean Validation?

1 Overview of the JSR-303 Bean Validation API. JSR-303 standardizes validation constraint declaration and metadata for the Java platform. Using this API, you annotate domain model properties with declarative validation constraints and the runtime enforces them.

What is group validation?

Validation groups allow you to organize validation controls on a page as a set. Each validation group can perform validation independently from other validation groups on the page. You create a validation group by setting the ValidationGroup property to the same name (a string) for all the controls you want to group.

What is the difference between @valid and @validated?

The @Valid annotation ensures the validation of the whole object. Importantly, it performs the validation of the whole object graph. However, this creates issues for scenarios needing only partial validation. On the other hand, we can use @Validated for group validation, including the above partial validation.

What are Group constraints?

Group constraints are optional linear constraints that group assets together and enforce bounds on the group weights (see Group Constraints).


2 Answers

There is a Default group in javax.validation.groups.Default, which represents the default Bean Validation group. Unless a list of groups is explicitly defined:

  • constraints belong to the Default group
  • validation applies to the Default group

You could extends this group:

public interface ValidatedOnCreationOnly extends Default {} 
like image 112
Ali Dehghani Avatar answered Sep 22 '22 19:09

Ali Dehghani


just wanted to add more:

if you're using spring framework you can use org.springframework.validation.Validator

@Autowired private Validator validator; 

and to perform validation manually:

validator.validate(myObject, ValidationErrorsToException.getInstance()); 

and in controller:

@RequestMapping(method = RequestMethod.POST) public Callable<ResultObject> post(@RequestBody @Validated(MyObject.CustomGroup.class) MyObject request) {     // logic } 

although in this way extending from javax.validation.groups.Default won't work so you have to include Default.class in groups:

class MyObject {      @NotNull(groups = {Default.class, CustomGroup.class})     private String id;      public interface CustomGroup extends Default {} } 
like image 36
dubious cyborg Avatar answered Sep 23 '22 19:09

dubious cyborg