Javax validation on nested objects - not working
Asked Answered
S

3

47

In my Spring Boot project I have two DTO's which I'm trying to validate, LocationDto and BuildingDto. The LocationDto has a nested object of type BuildingDto.

These are my DTO's:

LocationDto

public class LocationDto {

  @NotNull(groups = { Existing.class })
  @Null(groups = { New.class })
  @Getter
  @Setter
  private Integer id;

  @NotNull(groups = { New.class, Existing.class })
  @Getter
  @Setter
  private String name;

  @NotNull(groups = { New.class, Existing.class, LocationGroup.class })
  @Getter
  @Setter
  private BuildingDto building;

  @NotNull(groups = { Existing.class })
  @Getter
  @Setter
  private Integer lockVersion;

}

BuildingDto

public class BuildingDto {

  @NotNull(groups = { Existing.class, LocationGroup.class })
  @Null(groups = { New.class })
  @Getter
  @Setter
  private Integer id;

  @NotNull(groups = { New.class, Existing.class })
  @Getter
  @Setter
  private String name;

  @NotNull(groups = { Existing.class })
  @Getter
  @Setter
  private List<LocationDto> locations;

  @NotNull(groups = { Existing.class })
  @Getter
  @Setter
  private Integer lockVersion;

}

Currently, I can validate in my LocationDto that the properties name and building are not null, but I can't validate the presence of the property id which is inside building.

If I use the @Valid annotation on the building property, it would validate all of its fields, but for this case I only want to validate its id.

How could that be done using javax validation?

This is my controller:

@PostMapping
public LocationDto createLocation(@Validated({ New.class, LocationGroup.class }) @RequestBody LocationDto location) {
  // save entity here...
}

This is a correct request body: (should not throw validation errors)

{
  "name": "Room 44",
  "building": {
    "id": 1
  }
}

This is an incorrect request body: (must throw validation errors because the building id is missing)

{
  "name": "Room 44",
  "building": { }
}
Slope answered 1/1, 2019 at 21:51 Comment(1)
what is "ExistingClass" ?Politic
K
11

Use @ConvertGroup from Bean Validation 1.1 (JSR-349).

Introduce a new validation group say Pk.class. Add it to groups of BuildingDto:

public class BuildingDto {

    @NotNull(groups = {Pk.class, Existing.class, LocationGroup.class})
    // Other constraints
    private Integer id;

    //
}

And then in LocationDto cascade like following:

@Valid
@ConvertGroup.List( {
    @ConvertGroup(from=New.class, to=Pk.class),
    @ConvertGroup(from=LocationGroup.class, to=Pk.class)
} )
// Other constraints
private BuildingDto building;

Further Reading:

5.5. Group conversion from Hibernate Validator reference.

Keen answered 2/1, 2019 at 4:16 Comment(0)
L
88

Just try adding @valid to collection. it would be working as per reference hibernate

  @Getter
  @Setter
  @Valid
  @NotNull(groups = { Existing.class })
  private List<LocationDto> locations;
Lumpkin answered 2/1, 2019 at 2:54 Comment(1)
This is the simple yet accurate solution!Avlona
H
27

@Valid annotation must be added to cascade class attributes.

LocationDTO.class

public class LocationDto {

  @Valid
  private BuildingDto building;
   
  .........

}
Hayman answered 4/7, 2021 at 7:21 Comment(0)
K
11

Use @ConvertGroup from Bean Validation 1.1 (JSR-349).

Introduce a new validation group say Pk.class. Add it to groups of BuildingDto:

public class BuildingDto {

    @NotNull(groups = {Pk.class, Existing.class, LocationGroup.class})
    // Other constraints
    private Integer id;

    //
}

And then in LocationDto cascade like following:

@Valid
@ConvertGroup.List( {
    @ConvertGroup(from=New.class, to=Pk.class),
    @ConvertGroup(from=LocationGroup.class, to=Pk.class)
} )
// Other constraints
private BuildingDto building;

Further Reading:

5.5. Group conversion from Hibernate Validator reference.

Keen answered 2/1, 2019 at 4:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.