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:

2023-01-30T20: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=)
2023-01-30T20:22:49.481+03:00  INFO 5464 --- [p-nio-80-exec-6] c.e.randomtext.web.MainPageController    : see no errors :E
2023-01-30T20:22:49.481+03:00  INFO 5464 --- [p-nio-80-exec-6] c.e.randomtext.web.MainPageController    : org.springframework.validation.BeanPropertyBindingResult: 0 errors
2023-01-30T20: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

Ignat
  • 88
  • 6
  • https://stackoverflow.com/questions/64266061/using-an-enum-within-a-nested-class-with-thymeleaf-and-spring-boot – riddle_me_this Feb 01 '23 at 23:51
  • Could try that since your stacktrace shows the value is null – riddle_me_this Feb 01 '23 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 Feb 02 '23 at 13:29

0 Answers0