Reputation: 119
This code is creating a hmtl form where you can select some chekcboxes and design a Taco. I am trying to perform model fields validation but it is not working. This code for example is supposed to return an error if the input field box of the name is empty or if no checkboxes are selected at all. The error variable in the controller though never catches any errors. What could possibly be happening. This code a copy paste example from the Spring in Action book so I'm not sure why it's not working.
Model
@Data
public class Taco {
@NotNull
@Size(min=5, message = "Name must be at least 5 characters long")
private String name;
@Size(min=1, message = "You must choose at least 1 ingredient")
private List<String> ingredients;
}
Controller
@Slf4j
@Controller
@RequestMapping("/design")
public class DesignTacoController {
@GetMapping
public String showDesignFromModel(Model model){
List<Ingredient> ingredients = Arrays.asList(
new Ingredient("FLTO","Flour Tortilla", WRAP),
new Ingredient("COTO","Corn Tortilla", WRAP),
new Ingredient("GRBF","Ground Beef", PROTEIN),
new Ingredient("CARN","Carnitas", PROTEIN),
new Ingredient("TMTP","Diced Tomatoes", VEGGIES),
new Ingredient("LETC","Lettuce", VEGGIES),
new Ingredient("CHED","Cheddar", CHEESE),
new Ingredient("JACK","Monterrey Jack", CHEESE),
new Ingredient("SLSA","Salsa", SAUCE),
new Ingredient("SRCR","Sour Cream", SAUCE)
);
Type[] types = Ingredient.Type.values();
for (Type type : types){
model.addAttribute(type.toString().toLowerCase(),
ingredients.stream()
.filter(e -> e.getType() == type)
.collect(Collectors.toList()));
}
model.addAttribute("design",new Taco());
return "design";
}
@PostMapping
public String processDesign(@Valid Taco design , Errors errors){
if(errors.hasErrors()){
System.out.println("Many errors " + errors);
return "design";
}
System.out.println("Process design: " + design);
System.out.println("No errors " + errors);
log.info("Process design: " + design);
return "redirect:/orders/current";
}
}
View
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Taco Cloud</title>
<link rel="stylesheet" th:href="@{/styles.css}" />
</head>
<body>
<h1>Design your taco!</h1>
<img th:src="@{/images/TacoCloud.png}" alt="Taco Cloud Logo"/>
<form method="POST" th:object="${design}">
<div class="grid">
<div class="ingredient-group" id="wraps">
<h3>Designate your wrap:</h3>
<div th:each="ingredient : ${wrap}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
<span th:text="${ingredient.name}">INGREDIENT</span><br/>
</div>
</div>
<div class="ingredient-group" id="proteins">
<h3>Pick your protein:</h3>
<div th:each="ingredient : ${protein}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
<span th:text="${ingredient.name}">INGREDIENT</span><br/>
</div>
</div>
<div class="ingredient-group" id="cheeses">
<h3>Choose your cheese:</h3>
<div th:each="ingredient : ${cheese}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
<span th:text="${ingredient.name}">INGREDIENT</span><br/>
</div>
</div>
<div class="ingredient-group" id="veggies">
<h3>Determine your veggies:</h3>
<div th:each="ingredient : ${veggies}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
<span th:text="${ingredient.name}">INGREDIENT</span><br/>
</div>
</div>
<div class="ingredient-group" id="sauces">
<h3>Select your sauce:</h3>
<div th:each="ingredient : ${sauce}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
<span th:text="${ingredient.name}">INGREDIENT</span><br/>
</div>
</div>
</div>
<div>
<h3>Name your taco creation:</h3>
<input type="text" th:field="*{name}"/>
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Error</span>
<br/>
<button>Submit your taco</button>
</div>
</form>
</body>
</html>
Upvotes: 1
Views: 3255
Reputation: 41
I was also tortured by this problem for a while
Reason:
If you dont select any CheckBox, ingredients=null ,@Size min dont validate the null result.So, we need combine @NotNull.
@NotNull(message = "You must choose at least 1 ingredient")
@Size(min = 1, message = "You must choose at least 1 ingredient")
private List<String> ingredients;
Upvotes: 1
Reputation: 125292
When validation isn't working there is generally one thing that isn't right. There is no implementation for the javax.validation
API on the classpath. Only adding a dependency to the validation-api
from javax.validation
will do nothing as that is only the API not an actual implementation.
You will need to add an implementation, like hibernate-validator
, as well.
Now in earlier versions of Spring Boot (prior to 2.3) the validation was automatically included when adding spring-boot-starter-web
as a dependency. However in newer version (2.3+) this has been removed. You now need to explicitly include the spring-boot-starter-validation
starter dependency. This includes the API and an implementation.
That being said it could also be that instead of the Java Validation API you have the Jakarta Validation API on the classpath as well as an implementation of that (like hibernate-validator
version 7 or up). The Jakarata Validation API (or most of the JakartaEE APIs) aren't support (yet) by Spring or Spring Boot. So even if you have that on your classpath it won't work, you need the Java Validation API one.
Upvotes: 6