diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml
index 1c4b2bb38f..e0afbbddaf 100644
--- a/spring-boot-modules/pom.xml
+++ b/spring-boot-modules/pom.xml
@@ -104,6 +104,7 @@
spring-boot-springdoc-2
spring-boot-documentation
spring-boot-3-url-matching
+ spring-boot-validations
diff --git a/spring-boot-modules/spring-boot-validations/pom.xml b/spring-boot-modules/spring-boot-validations/pom.xml
new file mode 100644
index 0000000000..e89c7f997b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/pom.xml
@@ -0,0 +1,38 @@
+
+ 4.0.0
+
+ com.baeldung.spring-boot-modules
+ spring-boot-modules
+ 1.0.0-SNAPSHOT
+
+ spring-boot-validations
+ spring-boot-validations
+ Demo of Validations in Spring Boot
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/Application.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/Application.java
new file mode 100644
index 0000000000..c0490d50c6
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/Application.java
@@ -0,0 +1,12 @@
+package com.baeldung;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controller/ValidationController.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controller/ValidationController.java
new file mode 100644
index 0000000000..8597c9617c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controller/ValidationController.java
@@ -0,0 +1,19 @@
+package com.baeldung.controller;
+
+import javax.validation.Valid;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.dto.BooleanObject;
+
+@RestController
+public class ValidationController {
+
+ @PostMapping("/validateBoolean")
+ public ResponseEntity addUser(@RequestBody @Valid BooleanObject booleanObj) {
+ return ResponseEntity.ok("BooleanObject is valid");
+ }
+}
diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controlleradvice/GlobalExceptionHandler.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controlleradvice/GlobalExceptionHandler.java
new file mode 100644
index 0000000000..601da40e23
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/controlleradvice/GlobalExceptionHandler.java
@@ -0,0 +1,37 @@
+package com.baeldung.controlleradvice;
+
+import java.util.stream.Collectors;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import com.fasterxml.jackson.databind.exc.InvalidFormatException;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ @ResponseStatus(value = HttpStatus.BAD_REQUEST)
+ public String handleValidationException(MethodArgumentNotValidException ex) {
+ return ex.getBindingResult()
+ .getFieldErrors()
+ .stream()
+ .map(e -> e.getDefaultMessage())
+ .collect(Collectors.joining(","));
+ }
+
+ @ExceptionHandler(IllegalArgumentException.class)
+ @ResponseStatus(value = HttpStatus.BAD_REQUEST)
+ public String handleIllegalArugmentException(IllegalArgumentException ex) {
+ return ex.getMessage();
+ }
+
+ @ExceptionHandler(InvalidFormatException.class)
+ @ResponseStatus(value = HttpStatus.BAD_REQUEST)
+ public String handleInvalidFormatException(InvalidFormatException ex) {
+ return ex.getOriginalMessage();
+ }
+}
diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/deserializer/BooleanDeserializer.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/deserializer/BooleanDeserializer.java
new file mode 100644
index 0000000000..c9f30dc6e3
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/deserializer/BooleanDeserializer.java
@@ -0,0 +1,18 @@
+package com.baeldung.deserializer;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
+public class BooleanDeserializer extends JsonDeserializer {
+ @Override
+ public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ String value = p.getText();
+ if (value != null && !value.equals("TRUE") && !value.equals("FALSE")) {
+ throw new IllegalArgumentException("Boolean value must come as Capital TRUE or FALSE");
+ }
+ return Boolean.valueOf(value);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/dto/BooleanObject.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/dto/BooleanObject.java
new file mode 100644
index 0000000000..77ca18b02c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/dto/BooleanObject.java
@@ -0,0 +1,26 @@
+package com.baeldung.dto;
+
+import javax.validation.constraints.AssertFalse;
+import javax.validation.constraints.AssertTrue;
+import javax.validation.constraints.NotNull;
+
+import com.baeldung.deserializer.BooleanDeserializer;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+import lombok.Data;
+
+@Data
+public class BooleanObject {
+
+ @NotNull(message = "boolField cannot be null")
+ Boolean boolField;
+
+ @AssertTrue(message = "trueField must have true value")
+ Boolean trueField;
+
+ @AssertFalse(message = "falseField must have false value")
+ Boolean falseField;
+
+ @JsonDeserialize(using = BooleanDeserializer.class)
+ Boolean boolStringVar;
+}
diff --git a/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/service/ValidationService.java b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/service/ValidationService.java
new file mode 100644
index 0000000000..5b96344e46
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/src/main/java/com/baeldung/service/ValidationService.java
@@ -0,0 +1,17 @@
+package com.baeldung.service;
+
+import javax.validation.Valid;
+
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import com.baeldung.dto.BooleanObject;
+
+@Service
+@Validated
+public class ValidationService {
+
+ public void validateBoolean(@Valid BooleanObject booleanObj) {
+ // further processing
+ }
+}
diff --git a/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/controller/ValidationControllerUnitTest.java b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/controller/ValidationControllerUnitTest.java
new file mode 100644
index 0000000000..78950e4c0e
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/controller/ValidationControllerUnitTest.java
@@ -0,0 +1,104 @@
+package com.baeldung.controller;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+
+import com.baeldung.dto.BooleanObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@ExtendWith(SpringExtension.class)
+@WebMvcTest(controllers = ValidationController.class)
+class ValidationControllerUnitTest {
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ void testNullBoolean() throws Exception {
+ BooleanObject boolObj = new BooleanObject();
+ boolObj.setBoolField(null);
+ String postBody = objectMapper.writeValueAsString(boolObj);
+
+ mockMvc.perform(post("/validateBoolean").contentType("application/json")
+ .content(postBody))
+ .andExpect(status().isBadRequest());
+
+ }
+
+ @Test
+ void testTrueBoolean() throws Exception {
+ BooleanObject boolObj = new BooleanObject();
+ boolObj.setBoolField(Boolean.TRUE);
+ boolObj.setTrueField(Boolean.FALSE);
+ String postBody = objectMapper.writeValueAsString(boolObj);
+
+ String output = mockMvc.perform(post("/validateBoolean").contentType("application/json")
+ .content(postBody))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ assertEquals("trueField must have true value", output);
+ }
+
+ @Test
+ void testFalseBoolean() throws Exception {
+ BooleanObject boolObj = new BooleanObject();
+ boolObj.setBoolField(Boolean.TRUE);
+ boolObj.setTrueField(Boolean.TRUE);
+ boolObj.setFalseField(Boolean.TRUE);
+ String postBody = objectMapper.writeValueAsString(boolObj);
+
+ String output = mockMvc.perform(post("/validateBoolean").contentType("application/json")
+ .content(postBody))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ assertEquals("falseField must have false value", output);
+ }
+
+ @Test
+ void testBooleanFromString() throws Exception {
+ BooleanObject boolObj = new BooleanObject();
+ boolObj.setBoolField(Boolean.TRUE);
+ boolObj.setTrueField(Boolean.TRUE);
+ boolObj.setFalseField(Boolean.FALSE);
+ boolObj.setBoolStringVar(true);
+ String postBody = objectMapper.writeValueAsString(boolObj);
+
+ String output = mockMvc.perform(post("/validateBoolean").contentType("application/json")
+ .content(postBody))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ assertEquals("Boolean value must come as Capital TRUE or FALSE", output);
+ }
+
+ @Test
+ void testValidBean() throws Exception {
+
+ String postBody = "{\"boolField\":true,\"trueField\":true,\"falseField\":false,\"boolStringVar\":\"TRUE\"}";
+
+ String output = mockMvc.perform(post("/validateBoolean").contentType("application/json")
+ .content(postBody))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ assertEquals("BooleanObject is valid", output);
+
+ }
+}
diff --git a/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/dto/BooleanUnitTest.java b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/dto/BooleanUnitTest.java
new file mode 100644
index 0000000000..8c9375e72f
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/dto/BooleanUnitTest.java
@@ -0,0 +1,28 @@
+package com.baeldung.dto;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class BooleanUnitTest {
+
+ @Test
+ void testBooleanFromString() {
+ Boolean trueVar = Boolean.valueOf("TRUE");
+ Boolean falseVar = Boolean.valueOf("false");
+ Boolean parsedVar = Boolean.parseBoolean("True");
+
+ assertEquals(Boolean.TRUE, trueVar);
+ assertEquals(Boolean.FALSE, falseVar);
+ assertEquals(Boolean.TRUE, parsedVar);
+ }
+
+ @Test
+ void testBoolean() {
+ Boolean trueVar = Boolean.valueOf(true);
+ Boolean falseVar = Boolean.valueOf(false);
+
+ assertEquals(Boolean.TRUE, trueVar);
+ assertEquals(Boolean.FALSE, falseVar);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/service/ValidationServiceUnitTest.java b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/service/ValidationServiceUnitTest.java
new file mode 100644
index 0000000000..c67acea13d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validations/src/test/java/com/baeldung/service/ValidationServiceUnitTest.java
@@ -0,0 +1,35 @@
+package com.baeldung.service;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import javax.validation.ConstraintViolationException;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import com.baeldung.dto.BooleanObject;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+class ValidationServiceUnitTest {
+
+ @Autowired
+ ValidationService service;
+
+ @Test
+ void validateBoolean() {
+ BooleanObject boolObj = new BooleanObject();
+ boolObj.setBoolField(Boolean.valueOf(true));
+ boolObj.setTrueField(Boolean.FALSE);
+ Throwable throwableError = assertThrows(ConstraintViolationException.class, () -> {
+ service.validateBoolean(boolObj);
+ });
+ assertTrue(throwableError.getLocalizedMessage()
+ .endsWith("trueField must have true value"));
+ }
+
+}