Search code examples
javaspring-bootthymeleaf

Why is Thymeleaf failing to bind form inputs to object fields?


I am using Thymeleaf to create a registration form with Spring Boot (following this tutorial from Baeldung). The form is submitting, but it's not binding the inputs to the relevant object fields. This is my object:

@PasswordMatches
public class UserDto {

    @NotNull
    @NotEmpty
    private String username;
    @NotNull
    @NotEmpty
    @Email
    private String email;
    @NotNull
    @NotEmpty
    @Password
    private String password;
    @NotNull
    @NotEmpty
    @Password
    private String confirmPassword;
    @AssertTrue
    private boolean agreementAccepted;
    private boolean thirteen;

    public String getUsername() {
        return username;
    }

    public String getEmail() {
        return email;
    }

    public String getPassword() {
        return password;
    }

    public String getConfirmPassword() {
        return confirmPassword;
    }

    public boolean isAgreementAccepted() {
        return agreementAccepted;
    }

    public boolean isThirteen() {
        return thirteen;
    }

}

And this is the Thymeleaf template I am using:

<form class="form-signin" method="post" th:object="${user}"
    th:action="@{''}">
    <input type="hidden" th:name="${_csrf.parameterName}"
        th:value="${_csrf.token}" />
    <h2 class="form-signin-heading">Create New Account</h2>
    <p>
        <label for="email" class="sr-only"></label> <input type="email"
            id="email" name="email" class="form-control" placeholder="Email"
            required="" autofocus="" th:field="*{email}">
    </p>
    <p>
        <label for="username" class="sr-only"></label> <input type="text"
            id="username" name="username" class="form-control"
            placeholder="Username" required="" autofocus=""
            th:field="*{username}">
    </p>
    <p>
        <label for="password" class="sr-only"></label> <input type="password"
            id="password" name="password" class="form-control"
            placeholder="Password" required="" th:field="*{password}">
    </p>
    <p>
        <label for="confirmPassword" class="sr-only"></label> <input
            type="password" id="confirmPassword" name="confirmPassword"
            class="form-control" placeholder="Confirm Password" required=""
            th:field="*{confirmPassword}">
    </p>
    <p class="form-control">
        <input required="" type="checkbox" id="accepted-agreement"
            name="terms" placeholder="I agree to the terms of service"
            th:field="*{agreementAccepted}" class="pointer"> <label
            for="accepted-agreement" class="pointer">I agree to the terms
            of service</label>

    </p>
    <p class="form-control">
        <input type="checkbox" id="is-thirteen" name="terms"
            placeholder="I am 13 years or older" th:field="*{thirteen}"
            class="pointer"> <label data-toggle="tooltip"
            data-placement="bottom"
            title="You must be at least 13 years old to access this site's social media features."
            class="pointer" for="is-thirteen">I am 13 years or older</label> <a
            id="thirteen-info" class="info" href="#" data-toggle="tooltip"
            data-bs-toggle="tooltip" data-bs-placement="bottom"
            title="You must be at least 13 years old to access this site's social media features (<a target='_blank' href='../terms#coppa'>Learn More</a>).">?</a>
    </p>
    <button class="btn btn-lg btn-primary btn-block" type="submit">Sign
        Up</button>
</form>

I double checked that the form is submitting the correct data using Chrome Dev Tools:

Dev Tools Screenshot

But the object fields are still not binding properly (screenshot from my debugger):

Debugger Screenshot

Why is this not working?


Solution

  • You need to have setters on UserDto for the binding to work.