javaspringspring-boot

Is Spring Boot emptying "password" fields in the request?


Is Spring by default filtering out a field called "password" from the request? it is always null. I think I read something about that before. But how can I disable it for this specific endpoint?

The screenshot shows the request on the right and the debugger output on the left for the SingUpRequest. password is always empty and I don't understand why. I'm just starting with Spring, trying to get out of the PHP world.

enter image description here

Controller Signature:

@PostMapping("/sign-up")
public String SignUp(
    @RequestBody SignUpRequest signUp
)
public class SignUpRequest {
    public Account account;
    public Organization organization;
    public UserProfile userProfile;

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public Organization getOrganization() {
        return organization;
    }

    public void setOrganization(Organization organization) {
        this.organization = organization;
    }

    public UserProfile getUserProfile() {
        return userProfile;
    }

    public void setUserProfile(UserProfile userProfile) {
        this.userProfile = userProfile;
    }
}

Account Entity:

@Entity
@Table(name = "accounts")
public class Account {

    @Id()
    public String accountId;

    @NotBlank(message = "Email is required")
    public String email;

    @NotBlank(message = "A password is required")
    public String password;

    public String confirmPassword;

    public String test;

    public String emailVerificationToken;

    public LocalDateTime emailVerificationTokenExpiresAt;

    public void setEmail(String email) {
        this.email = email;
    }

    public String getEmail() {
        return email;
    }

    public String setPassword(String password) {
        return password;
    }

    public String getPassword() {
        return password;
    }

    public void setEmailVerificationToken(String emailVerificationToken) {
        this.emailVerificationToken = emailVerificationToken;
    }

    public String getEmailVerificationToken() {
        return emailVerificationToken;
    }

    public void setEmailVerificationTokenExpiresAt(LocalDateTime emailVerificationTokenExpiresAt) {
        this.emailVerificationTokenExpiresAt = emailVerificationTokenExpiresAt;
    }

    public LocalDateTime getEmailVerificationTokenExpiresAt() {
        return emailVerificationTokenExpiresAt;
    }

    public boolean checkIfEmailVerificationTokenIsExpired() {
        return LocalDateTime.now().isAfter(emailVerificationTokenExpiresAt);
    }

    @Override
    public String toString() {
        return "Account{" +
                "accountId='" + accountId + '\'' +
                ", email='" + email + '\'' +
                ", password='" + password + '\'' +
                ", emailVerificationToken='" + emailVerificationToken + '\'' +
                ", emailVerificationTokenExpiresAt=" + emailVerificationTokenExpiresAt +
                '}';
    }
}

The JSON I'm sending via Postman:

{
    "account": {
        "email": "fk@kreative-design.net",
        "password": "password",
        "confirmPassword": "password",
        "test": "test"
    },
    "organization": {
        "name": "Phauthentic"
    },
    "userProfile": {
        "firstName": "Florian",
        "lastName": "Krämer"
    }
}

Solution

  • Well, a Getter is a Getter, and a Setter should act like a Setter. Try this:

    @Entity
    @Table(name = "accounts")
    public class Account {
    
        @Id()
        public String accountId;
    
        @NotBlank(message = "Email is required")
        public String email;
    
        @NotBlank(message = "A password is required")
        public String password;
    
        public String confirmPassword;
    
        public String test;
    
        public String emailVerificationToken;
    
        public LocalDateTime emailVerificationTokenExpiresAt;
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setEmailVerificationToken(String emailVerificationToken) {
            this.emailVerificationToken = emailVerificationToken;
        }
    
        public String getEmailVerificationToken() {
            return emailVerificationToken;
        }
    
        public void setEmailVerificationTokenExpiresAt(LocalDateTime emailVerificationTokenExpiresAt) {
            this.emailVerificationTokenExpiresAt = emailVerificationTokenExpiresAt;
        }
    
        public LocalDateTime getEmailVerificationTokenExpiresAt() {
            return emailVerificationTokenExpiresAt;
        }
    
        public boolean checkIfEmailVerificationTokenIsExpired() {
            return LocalDateTime.now().isAfter(emailVerificationTokenExpiresAt);
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "accountId='" + accountId + '\'' +
                    ", email='" + email + '\'' +
                    ", password='" + password + '\'' +
                    ", emailVerificationToken='" + emailVerificationToken + '\'' +
                    ", emailVerificationTokenExpiresAt=" + emailVerificationTokenExpiresAt +
                    '}';
        }
    }
    

    Note the difference in the setPassword method.

    Also, you're mixing up the access types of the related fields. Eg. for confirmPassword there are no Getter/Setter in place, so the ORM falls back to direct field reflection settlement. Use either the one or the other. When there is no specific reason to go with Getter/setter, add @Access(AccessType.FIELD) to the class. Otherwise provide Getter/Setter for all fields. Anyhow, try to stay consistent.