Skip to main content
Advertisement

6.2 Validating Collections and Nested Objects with @Valid

Standard primitive or plain string field validation inside a flat DTO is effortlessly handled using standard @NotBlank or @NotNull. However, validating Collections (like a list of addresses inside a user payload) or complex Nested Objects demands a slightly different hierarchical approach.

1. Validating Nested Internal Objects

When your incoming JSON payload has a hierarchical structure such as:

{
"name": "John Doe",
"age": 25,
"address": {
"city": "New York",
"zipcode": "10001"
}
}

To enforce validation on the fields of the encapsulated AddressDto, you MUST explicitly append the @Valid annotation onto the parent field wrapper. This delegates (cascades) the validation chain downward.

public class UserCreateRequest {

@NotBlank(message = "Name is mandatory.")
private String name;

@Min(value = 14, message = "Must be at least 14 years old.")
private int age;

@NotNull(message = "Address information cannot be null.")
@Valid // ★ Without this, the inner fields of AddressDto will bypass validation completely
private AddressDto address;
}

public class AddressDto {
@NotBlank
private String city;

@Size(min = 5, max = 5)
private String zipcode;
}

2. Validating Internal Elements of Collections (List, Set)

When mapping bulk items, such as an array of Skills or Hobbies, you simultaneously need to validate the structure of the list itself and every discrete element residing recursively inside that list.

public class UserCreateRequest {

// Validates the primitive constraints of the List
@Size(min = 1, max = 5, message = "You must provide between 1 and 5 hobbies.")
@Valid // Recursively cascades validation across all internal loop elements
private List<HobbyDto> hobbies;
}

public class HobbyDto {
@NotBlank(message = "Hobby name cannot be blank.")
private String hobbyName;
}

The golden rule here is affixing @Valid upon custom generic List or Set type fields, which automatically instructs the underlying framework to execute loop iteration constraint testing across all mapped descendant instances.

Advertisement