0

So I have an endpoint to register a user, that takes a RegisterDto with validations as RequestBody. I sadly don't know since when the validation stopped working, but at the moment even with every field filled out it returns a bad request and logs the following: 2023-04-10T12:50:57.981+02:00 WARN 1836 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public org.springframework.http.ResponseEntity<java.lang.Object> app.dcuobroker.backend.boundary.v1.api.auth.AuthApiImpl.registerUser(app.dcuobroker.backend.boundary.v1.dto.auth.RegisterDto,jakarta.servlet.http.HttpServletRequest,java.util.Locale) with 6 errors: [Field error in object 'registerDto' on field 'username': rejected value [null]; codes [NotNull.registerDto.username,NotNull.username,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [registerDto.username,username]; arguments []; default message [username]]; default message [darf nicht null sein]] [Field error in object 'registerDto' on field 'password': rejected value [null]; codes [NotBlank.registerDto.password,NotBlank.password,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [registerDto.password,password]; arguments []; default message [password]]; default message [darf nicht leer sein]] [Field error in object 'registerDto' on field 'username': rejected value [null]; codes [NotBlank.registerDto.username,NotBlank.username,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [registerDto.username,username]; arguments []; default message [username]]; default message [darf nicht leer sein]] [Field error in object 'registerDto' on field 'email': rejected value [null]; codes [NotNull.registerDto.email,NotNull.email,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [registerDto.email,email]; arguments []; default message [email]]; default message [darf nicht null sein]] [Field error in object 'registerDto' on field 'password': rejected value [null]; codes [NotNull.registerDto.password,NotNull.password,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [registerDto.password,password]; arguments []; default message [password]]; default message [darf nicht null sein]] [Field error in object 'registerDto' on field 'email': rejected value [null]; codes [NotBlank.registerDto.email,NotBlank.email,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [registerDto.email,email]; arguments []; default message [email]]; default message [darf nicht leer sein]] ]

The RegisterDto:

@Data
public class RegisterDto {
    @NotNull
    @NotBlank
    @Size(min = 3, max = 20)
    @Pattern(regexp = "^(?=.{3,20}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(?<![_.])$")
    private String username;

    @NotNull
    @NotBlank
    @Email
    @Size(max = 50)
    private String email;

    @NotNull
    @NotBlank
    @Size(min = 8, max = 50)
    @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$")
    private String password;

    @JsonProperty("first_name")
    @Size(min = 1, max = 50)
    @Pattern(regexp = "/^[a-z ,.'-]+$/i")
    private String firstName;

    @JsonProperty("last_name")
    @Size(min = 1, max = 50)
    @Pattern(regexp = "/^[a-z ,.'-]+$/i")
    private String lastName;
}

This is the request body:

{
    "email": "test.user@example.com",
    "username": "testuser",
    "password": "TestPw1!",
    "first_name": "Some",
    "last_name": "Name"
}

And this is the endpoint:

@Operation(summary = "Register a user using the details of the provided dto")
@ApiResponse(responseCode = "200", description = "User was registered successfully",
        content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                schema = @Schema(implementation = UserDto.class))})
@ApiResponse(responseCode = "400", description = "Invalid request body",
        content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                schema = @Schema(implementation = ErrorDto.class))})
@ApiResponse(responseCode = "409", description = "Username or email is already in use",
        content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                schema = @Schema(implementation = ErrorDto.class))})
@PostMapping(value = "/register", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<Object> registerUser(
        @RequestBody(description = "Dto used to register the user", required = true,
                content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                        schema = @Schema(implementation = RegisterDto.class)))
        @Valid RegisterDto register,
        HttpServletRequest request,
        Locale locale);

EDIT: Apparently the request body is not being set at all, since removing the @Valid annotation from it returns an internal server error on the http request, as all of the request body's fields are null. I've tried using Spring's RequestBody annotation instead of Swagger's requestbody, doesn't work either.

I also tried writing getters setters and NoArgs/AllArgs constructors myself instead of using Lombok but that doesn't fix the issue.

Michael
  • 51
  • 1
  • 12

2 Answers2

0

Based on stacktrace bean validation didn't stopped working. It works, but all fields in dto are null.

That's because wrong annotation used on method parameters. Using correct annotation will solve the problem

// use this annotation to specify @RequestBody
import org.springframework.web.bind.annotation.RequestBody;

ResponseEntity<Object> registerUser(
        @RequestBody @Valid RegisterDto register,
        HttpServletRequest request,
        Locale locale);
zforgo
  • 2,508
  • 2
  • 14
  • 22
0

Okay so... I had to remove Lombok's @Data annotation and use only @Getter and @Setter annotations instead, and I also had to add Spring's @RequestBody in addition to Swagger's @RequestBody...

Some articles said that the Data annotation also generates hashCode and toString methods, which might not work well with Jacksons Serialization

Michael
  • 51
  • 1
  • 12
  • 1
    I've never seen `@Data` causing this. You can use `delombok` to investigate further, if you want to understand the problem in more detail. It replaces the `@Data` annotation by the actual source code. Starting from this, you could analyze the actual root cause by setting breakpoints or removing more and more generated code until it works. – Hero Wanders Apr 10 '23 at 13:03