2

I am writing a controller with the annotation @RequestBody in order to map to a Java object. The method that uses the annotation is:

@PostMapping("/users")
public ResponseEntity<Object> createUserForProject(@Valid @RequestBody User user) {
        log.info("Creating a user " + user.getEmail());
}

This is the User class:

@Getter
@AllArgsConstructor
@Slf4j
@EqualsAndHashCode
@ToString
public class User {
    @NotEmpty
    @Email
    private String email;

    @NotEmpty
    private String firstName;

    @NotEmpty
    private String lastName;

    @JsonIgnore
    private Optional<LocalDate> lastLogonDate = Optional.empty();

    @JsonIgnore
    private Optional<LocalDate> lastModificationDate = Optional.empty();

    @JsonIgnore
    private Optional<LocalDate> creationDate = Optional.empty();

    @JsonIgnore
    private Optional<LocalDate> mfaWarningDate = Optional.empty();

    @JsonIgnore
    private Optional<LocalDate> auditStartNotificationDate = Optional.empty();

    @JsonIgnore
    private boolean enabled = true;

    public User() {
        log.info("HI");
    }

    (More code without explicit setters)

So when I make a POST call with the body

{
   "email":"test@test.com",
   "firstName":"testName",
   "lastName":"testLastName"
}

Outputs HI and the log with the Creating a user test@test.com message, so the object is created. My point here is... why does this really work? The HttpMessageConverter is calling the no-args constructor and there are no setters to call after create the object with the constructor. How do the object attributes get their values without any setter? What am I missing here?

Fran Moya
  • 89
  • 9
  • Setters are for humans, the computer has no need for them. Even a `final` variable is just a state of mind, you can change its value when you reflect upon yourself. Modifying `private` variables is not even worth mentioning. – Kayaman Feb 02 '22 at 13:00
  • 2
    Your class `User` is annotated with `@AllArgsConstructor` not `@NoArgsConstructor`. Therefore it does not have a no-args constructor, but a constructor with all your fields as argument. It might work due to constructor injection. – Karsten Gabriel Feb 02 '22 at 13:05
  • There is a no-args constructor `public User() {log.info("HI");}` created by me, that is why I don't use the annotation `@NoArgsConstructor`. In fact it is called to create the object. – Fran Moya Feb 02 '22 at 14:54

1 Answers1

3

Spring boot uses Jackson for Object <-> JSON conversion, and Jackson does not need setters, it sets fields via reflection.

Here is a relevant question about Jackson and why it doesn't need setters How does jackson set private properties without setters?

Igor Flakiewicz
  • 694
  • 4
  • 15