(Spring Boot) Fields of a record in a record (annotated by @RequestBody) are not being validated

I’m building a Spring Boot application and am working on testing my controller with @WebMvcTest.

I have a controller method that takes in @Validated @RequestBody UpdateFoodReqBody (record) which has a field @Validated @NotNull UpdateProductReqBody (record) in it that I also want to validate.

The test works when the product object is null but not when the product is present but its fields are invalid.

@PostMapping("/update-food/{foodId}")
public GetFoodResponse updateFood(
        @PathVariable @NotNull Long foodId,
        @Validated @RequestBody UpdateFoodReqBody updatedFood) {
    return foodService.updateFood(foodId, updatedFood);
}
public record UpdateFoodReqBody(
        String dietaryRestrictions,
        @Validated @NotNull UpdateProductReqBody product
) {
}
@Validated
public record UpdateProductReqBody(
        @NotBlank String name,
        String description,
        @NotNull @Positive BigDecimal price,
        @NotNull Date pickupTime
) {
}

Successful test:

@Test
public void testUpdateFood_invalidInput_forStackOverflow() throws Exception {
    mockMvc.perform(MockMvcRequestBuilders
                    .post(controllerPath + "/update-food/1")
                    .accept(MediaType.APPLICATION_JSON)
                    .content(objectMapper.writeValueAsString(
                            new UpdateFoodReqBody("Restrictions", null)))
                    .contentType("application/json"))
            .andExpect(result -> assertTrue(result.getResolvedException() instanceof MethodArgumentNotValidException))
            .andExpect(status().isBadRequest());
}


Test succesful!

Failing test (… Resolved Exceptin: Type = null …):

@Test
public void testUpdateFood_invalidInput_forStackOverflow() throws Exception {
    mockMvc.perform(MockMvcRequestBuilders
                    .post(controllerPath + "/update-food/1")
                    .accept(MediaType.APPLICATION_JSON)
                    .content(objectMapper.writeValueAsString(
                            new UpdateFoodReqBody(
                                    "Restrictions",
                                    new UpdateProductReqBody(null, "Description", null, new Date()))
                    ))
                    .contentType("application/json"))
            .andExpect(result -> assertTrue(result.getResolvedException() instanceof MethodArgumentNotValidException))
            .andExpect(status().isBadRequest());
}


Causes:
Resolved Exception:
             Type = null

At first I had @Validated annotation only in the controller class. Had the problem so also added @Validated to the records themselves, no difference.

Can someone please advise. Thank you!

  • take a look at stackoverflow.com/questions/36173332/…

    – 




Okay, I solved it myself. I’ll say what I did but someone smarter might chip in with more explanation because I have no idea WHY it worked.

Solution:

In the UpdateProductReqBody record I replaced

import org.springframework.validation.annotation.Validated

public record UpdateFoodReqBody(
    String dietaryRestrictions,
    @Validated @NotNull UpdateProductReqBody product
){}

with

import jakarta.validation.Valid

public record UpdateFoodReqBody(
    String dietaryRestrictions,
    @Valid @NotNull UpdateProductReqBody product
){}

It worked but I don’t know why. Isn’t @Validated just a Spring implementation of JSR-303’s jakarta.validation.Valid?

Leave a Comment