0

I'm struggling to get the validation work on simple web form in spring boot + thymeleaf project.

I've got these dependencies in my pom:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>2.0.1.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.1.5.Final</version>
    </dependency>

That's my DTO with @NotEmpty and @Pattern annotated fields:

package com.example.randomtext.web;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;

@Getter
@Setter
@ToString
public class MainPageForm {
    @NotEmpty(message = "choose the source file")
    private SourceFile sourceFile;
    private String sourceText;
    private boolean sourceTextSet;
    private String generatedText;
    @Pattern(regexp = "[0-9]+", message = "input the whole number")
    private String lengthOfOutput;

    @RequiredArgsConstructor
    @Getter
    public enum SourceFile {
        ALICE("alice.txt"),
        CONFUCIUS("confucius.txt"),
        private static final SourceFile[] ALL_VALUES = SourceFile.values();
        private final String fileName;
    }
}

that's my main.html form

<html>
<head><title>RandomText</title></head>
<body>
<h3>Random text generator</h3>
<pre th:if="${!mainPageForm.sourceTextSet}" th:style="'color:red;'">
    source text not set. Have you chosen the source file?</pre>
<form action="#" th:action="@{/random_text}" th:object="${mainPageForm}"
      method="post">
    <label>source file</label><br>
    <div th:each="sourceFile : ${T(com.example.randomtext.web.MainPageForm.SourceFile).values()}">
        <input type="radio" th:field="*{sourceFile}" th:value="${sourceFile}">
        <label th:text="${sourceFile.getFileName()}">source file</label>
        <pre th:style="'color:red;'"
            th:if="${#fields.hasErrors('sourceFile')}"
        th:errors="*{sourceFile}"></pre>
        <br>
    </div>
    <label>length of string to be generated<br>
        <input type="text" width="200" th:field="*{lengthOfOutput}">
        <pre th:style="'color:red;'"
           th:if="${#fields.hasErrors('lengthOfOutput')}"
           th:errors="*{lengthOfOutput}"></pre>
    </label><br><br>
    <br><input type="submit" value="Submit"/><input type="reset" value="Reset"/>
</form>
<pre th:text="${mainPageForm.sourceText}" th:style="'color:black;'">
    source text</pre>
</body>
</html>

my controller looks like

package com.example.randomtext.web;

import com.example.randomtext.RandomTextService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import javax.validation.Valid;
import java.net.URISyntaxException;

import static com.example.randomtext.Constants.BASE_PATH;
import static com.example.randomtext.Constants.MAIN_TEMPLATE;

@Controller
@RequiredArgsConstructor
@Slf4j
public class MainPageController {
    private final RandomTextService service;

    @GetMapping(BASE_PATH)
    public String doGet(MainPageForm form) {
        return MAIN_TEMPLATE;
    }

    @PostMapping(BASE_PATH)
    public String doPost(@Valid MainPageForm mainPageForm, BindingResult bindingResult) throws URISyntaxException {
        log.info("got form data {}", mainPageForm.toString());
        if (!bindingResult.hasErrors()) {
            log.info("see no errors :E");
            log.info(bindingResult.toString());
            log.info("sourceFile {}", mainPageForm.getSourceFile().getFileName());
            mainPageForm.setSourceText(service.readSourceString(mainPageForm.getSourceFile().getFileName()));
        } else {
            log.info("got errors");
            bindingResult.getFieldErrors()
                         .forEach(e -> log.error("got validation error {} for field {}",
                                                 e.getDefaultMessage(),
                                                 e.getField()));
        }
        return MAIN_TEMPLATE;
    }
}

and when I submitting the empty form the log output is:

2025-08-05T20:22:49.481+03:00  INFO 5464 --- [p-nio-80-exec-6] c.e.randomtext.web.MainPageController    : got form data MainPageForm(sourceFile=null, sourceText=null, sourceTextSet=false, generatedText=null, lengthOfOutput=)
2025-08-05T20:22:49.481+03:00  INFO 5464 --- [p-nio-80-exec-6] c.e.randomtext.web.MainPageController    : see no errors :E
2025-08-05T20:22:49.481+03:00  INFO 5464 --- [p-nio-80-exec-6] c.e.randomtext.web.MainPageController    : org.springframework.validation.BeanPropertyBindingResult: 0 errors
2025-08-05T20:22:49.483+03:00 ERROR 5464 --- [p-nio-80-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.NullPointerException: Cannot invoke "com.example.randomtext.web.MainPageForm$SourceFile.getFileName()" because the return value of "com.example.randomtext.web.MainPageForm.getSourceFile()" is null] with root cause

I've looked trough similar questions: Spring boot validation doesn't work Spring boot validation annotations @Valid and @NotBlank not working Validation form in Spring using @Valid not work DTO validation in Spring Boot not working

played with javax and hibernate validation dependencies versions, tried maven-clean but nothing of these helped

I'd appreciate any hint

3
  • stackoverflow.com/questions/64266061/… Commented Feb 1, 2023 at 23:51
  • Could try that since your stacktrace shows the value is null Commented Feb 1, 2023 at 23:52
  • the issue is not in enum itself, cuz even the String lengthOfOutput attribute annotated with @Pattern(regexp = "[0-9]+", message = "input the whole number") does not affect the bindingResult.hasErrors()
    – Ignat
    Commented Feb 2, 2023 at 13:29

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.