diff --git a/javax-validation-advanced/.gitignore b/javax-validation-advanced/.gitignore
new file mode 100644
index 0000000000..8027134ae9
--- /dev/null
+++ b/javax-validation-advanced/.gitignore
@@ -0,0 +1,6 @@
+.classpath
+.project
+.settings/
+target/
+bin/
+
diff --git a/javax-validation-advanced/README.md b/javax-validation-advanced/README.md
new file mode 100644
index 0000000000..8f03107330
--- /dev/null
+++ b/javax-validation-advanced/README.md
@@ -0,0 +1,5 @@
+## Java Bean Validation Examples
+
+This module contains articles about Bean Validation.
+
+### Relevant Articles:
diff --git a/javax-validation-advanced/pom.xml b/javax-validation-advanced/pom.xml
new file mode 100644
index 0000000000..39da166071
--- /dev/null
+++ b/javax-validation-advanced/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+ javax-validation-advanced
+ 0.1-SNAPSHOT
+ javax-validation-advanced
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+ ${spring.boot.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.databind.version}
+
+
+
+
+ 2.7.5
+ 2.14.0
+
+
+
\ No newline at end of file
diff --git a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java b/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java
new file mode 100644
index 0000000000..3e20ebad6b
--- /dev/null
+++ b/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java
@@ -0,0 +1,20 @@
+package com.baeldung.javaxval.afterdeserialization;
+
+import com.fasterxml.jackson.databind.BeanDescription;
+import com.fasterxml.jackson.databind.DeserializationConfig;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.deser.BeanDeserializer;
+import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
+
+public class BeanDeserializerModifierWithValidation extends BeanDeserializerModifier {
+
+ @Override
+ public JsonDeserializer> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer> deserializer) {
+ if (deserializer instanceof BeanDeserializer) {
+ return new BeanDeserializerWithValidation((BeanDeserializer) deserializer);
+ }
+
+ return deserializer;
+ }
+
+}
diff --git a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java b/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java
new file mode 100644
index 0000000000..332c83010d
--- /dev/null
+++ b/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java
@@ -0,0 +1,40 @@
+package com.baeldung.javaxval.afterdeserialization;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.BeanDeserializer;
+import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
+
+public class BeanDeserializerWithValidation extends BeanDeserializer {
+
+ private static final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+ private static final Validator validator = factory.getValidator();
+
+ protected BeanDeserializerWithValidation(BeanDeserializerBase src) {
+ super(src);
+ }
+
+ @Override
+ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ Object instance = super.deserialize(p, ctxt);
+ validate(instance);
+ return instance;
+ }
+
+ public void validate(T t) {
+ Set> violations = validator.validate(t);
+ if (!violations.isEmpty()) {
+ throw new ConstraintViolationException(violations);
+ }
+ }
+
+}
diff --git a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java b/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java
new file mode 100644
index 0000000000..c1923de265
--- /dev/null
+++ b/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java
@@ -0,0 +1,14 @@
+package com.baeldung.javaxval.afterdeserialization;
+
+import javax.validation.constraints.Size;
+
+public class Student {
+
+ @Size(min = 5, max = 10, message = "Student's name must be between 5 and 10 characters")
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+}
diff --git a/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java b/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java
new file mode 100644
index 0000000000..e652a43ccb
--- /dev/null
+++ b/javax-validation-advanced/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java
@@ -0,0 +1,24 @@
+package com.baeldung.javaxval.afterdeserialization;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+public class StudentDeserializerWithValidation {
+
+ public static Student readStudent(InputStream inputStream) throws IOException {
+ ObjectMapper mapper = getObjectMapperWithValidation();
+ return mapper.readValue(inputStream, Student.class);
+ }
+
+ private static ObjectMapper getObjectMapperWithValidation() {
+ SimpleModule validationModule = new SimpleModule();
+ validationModule.setDeserializerModifier(new BeanDeserializerModifierWithValidation());
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.registerModule(validationModule);
+ return mapper;
+ }
+
+}
diff --git a/javax-validation-advanced/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java b/javax-validation-advanced/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java
new file mode 100644
index 0000000000..edbe85ecfe
--- /dev/null
+++ b/javax-validation-advanced/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java
@@ -0,0 +1,51 @@
+package com.baeldung.javaxval;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.validation.ConstraintViolationException;
+
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.javaxval.afterdeserialization.Student;
+import com.baeldung.javaxval.afterdeserialization.StudentDeserializerWithValidation;
+
+public class StudentDeserializerWithValidationUnitTest {
+
+ private final String EXPECTED_ERROR_MESSAGE = "name: Student's name must be between 5 and 10 characters";
+ private final String EXPECTED_STUDENT_NAME = "Daniel";
+ private final String NAME_TOO_LONG_STUDENT_FILE = "nameTooLongStudent.json";
+ private final String NAME_TOO_SHORT_STUDENT_FILE = "nameTooShortStudent.json";
+ private final String SUBDIRECTORY = "afterdeserialization/";
+ private final String VALID_STUDENT_FILE = "validStudent.json";
+
+ @Test
+ void givenValidStudent_WhenReadStudent_ThenReturnStudent() throws IOException {
+ InputStream inputStream = getInputStream(VALID_STUDENT_FILE);
+ Student result = StudentDeserializerWithValidation.readStudent(inputStream);
+ assertEquals(EXPECTED_STUDENT_NAME, result.getName());
+ }
+
+ @Test
+ void givenStudentWithTooShortName_WhenReadStudent_ThenThrows() {
+ InputStream inputStream = getInputStream(NAME_TOO_SHORT_STUDENT_FILE);
+ ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream));
+ assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage());
+ }
+
+ @Test
+ void givenStudentWithTooLongName_WhenReadStudent_ThenThrows() {
+ InputStream inputStream = getInputStream(NAME_TOO_LONG_STUDENT_FILE);
+ ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream));
+ assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage());
+ }
+
+ private InputStream getInputStream(String fileName) {
+ return getClass().getClassLoader()
+ .getResourceAsStream(SUBDIRECTORY + fileName);
+ }
+
+}
diff --git a/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooLongStudent.json b/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooLongStudent.json
new file mode 100644
index 0000000000..e537ecb25d
--- /dev/null
+++ b/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooLongStudent.json
@@ -0,0 +1,3 @@
+{
+ "name": "Constantine"
+}
\ No newline at end of file
diff --git a/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooShortStudent.json b/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooShortStudent.json
new file mode 100644
index 0000000000..79ab10cb80
--- /dev/null
+++ b/javax-validation-advanced/src/test/resources/afterdeserialization/nameTooShortStudent.json
@@ -0,0 +1,3 @@
+{
+ "name": "Max"
+}
\ No newline at end of file
diff --git a/javax-validation-advanced/src/test/resources/afterdeserialization/validStudent.json b/javax-validation-advanced/src/test/resources/afterdeserialization/validStudent.json
new file mode 100644
index 0000000000..938002ea51
--- /dev/null
+++ b/javax-validation-advanced/src/test/resources/afterdeserialization/validStudent.json
@@ -0,0 +1,3 @@
+{
+ "name": "Daniel"
+}
\ No newline at end of file
diff --git a/javaxval2/.gitignore b/javaxval2/.gitignore
new file mode 100644
index 0000000000..8027134ae9
--- /dev/null
+++ b/javaxval2/.gitignore
@@ -0,0 +1,6 @@
+.classpath
+.project
+.settings/
+target/
+bin/
+
diff --git a/javaxval2/README.md b/javaxval2/README.md
new file mode 100644
index 0000000000..8f03107330
--- /dev/null
+++ b/javaxval2/README.md
@@ -0,0 +1,5 @@
+## Java Bean Validation Examples
+
+This module contains articles about Bean Validation.
+
+### Relevant Articles:
diff --git a/javaxval2/pom.xml b/javaxval2/pom.xml
new file mode 100644
index 0000000000..2e0ed0a281
--- /dev/null
+++ b/javaxval2/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+ javaxval2
+ 0.1-SNAPSHOT
+ javaxval2
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+ ${spring.boot.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.databind.version}
+
+
+
+
+ 2.7.5
+ 2.14.0
+
+
+
\ No newline at end of file
diff --git a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java
new file mode 100644
index 0000000000..3e20ebad6b
--- /dev/null
+++ b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerModifierWithValidation.java
@@ -0,0 +1,20 @@
+package com.baeldung.javaxval.afterdeserialization;
+
+import com.fasterxml.jackson.databind.BeanDescription;
+import com.fasterxml.jackson.databind.DeserializationConfig;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.deser.BeanDeserializer;
+import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
+
+public class BeanDeserializerModifierWithValidation extends BeanDeserializerModifier {
+
+ @Override
+ public JsonDeserializer> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer> deserializer) {
+ if (deserializer instanceof BeanDeserializer) {
+ return new BeanDeserializerWithValidation((BeanDeserializer) deserializer);
+ }
+
+ return deserializer;
+ }
+
+}
diff --git a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java
new file mode 100644
index 0000000000..332c83010d
--- /dev/null
+++ b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/BeanDeserializerWithValidation.java
@@ -0,0 +1,40 @@
+package com.baeldung.javaxval.afterdeserialization;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.BeanDeserializer;
+import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
+
+public class BeanDeserializerWithValidation extends BeanDeserializer {
+
+ private static final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+ private static final Validator validator = factory.getValidator();
+
+ protected BeanDeserializerWithValidation(BeanDeserializerBase src) {
+ super(src);
+ }
+
+ @Override
+ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ Object instance = super.deserialize(p, ctxt);
+ validate(instance);
+ return instance;
+ }
+
+ public void validate(T t) {
+ Set> violations = validator.validate(t);
+ if (!violations.isEmpty()) {
+ throw new ConstraintViolationException(violations);
+ }
+ }
+
+}
diff --git a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java
new file mode 100644
index 0000000000..c1923de265
--- /dev/null
+++ b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/Student.java
@@ -0,0 +1,14 @@
+package com.baeldung.javaxval.afterdeserialization;
+
+import javax.validation.constraints.Size;
+
+public class Student {
+
+ @Size(min = 5, max = 10, message = "Student's name must be between 5 and 10 characters")
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+}
diff --git a/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java
new file mode 100644
index 0000000000..e652a43ccb
--- /dev/null
+++ b/javaxval2/src/main/java/com/baeldung/javaxval/afterdeserialization/StudentDeserializerWithValidation.java
@@ -0,0 +1,24 @@
+package com.baeldung.javaxval.afterdeserialization;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+public class StudentDeserializerWithValidation {
+
+ public static Student readStudent(InputStream inputStream) throws IOException {
+ ObjectMapper mapper = getObjectMapperWithValidation();
+ return mapper.readValue(inputStream, Student.class);
+ }
+
+ private static ObjectMapper getObjectMapperWithValidation() {
+ SimpleModule validationModule = new SimpleModule();
+ validationModule.setDeserializerModifier(new BeanDeserializerModifierWithValidation());
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.registerModule(validationModule);
+ return mapper;
+ }
+
+}
diff --git a/javaxval2/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java b/javaxval2/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java
new file mode 100644
index 0000000000..edbe85ecfe
--- /dev/null
+++ b/javaxval2/src/test/java/com/baeldung/javaxval/StudentDeserializerWithValidationUnitTest.java
@@ -0,0 +1,51 @@
+package com.baeldung.javaxval;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.validation.ConstraintViolationException;
+
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.javaxval.afterdeserialization.Student;
+import com.baeldung.javaxval.afterdeserialization.StudentDeserializerWithValidation;
+
+public class StudentDeserializerWithValidationUnitTest {
+
+ private final String EXPECTED_ERROR_MESSAGE = "name: Student's name must be between 5 and 10 characters";
+ private final String EXPECTED_STUDENT_NAME = "Daniel";
+ private final String NAME_TOO_LONG_STUDENT_FILE = "nameTooLongStudent.json";
+ private final String NAME_TOO_SHORT_STUDENT_FILE = "nameTooShortStudent.json";
+ private final String SUBDIRECTORY = "afterdeserialization/";
+ private final String VALID_STUDENT_FILE = "validStudent.json";
+
+ @Test
+ void givenValidStudent_WhenReadStudent_ThenReturnStudent() throws IOException {
+ InputStream inputStream = getInputStream(VALID_STUDENT_FILE);
+ Student result = StudentDeserializerWithValidation.readStudent(inputStream);
+ assertEquals(EXPECTED_STUDENT_NAME, result.getName());
+ }
+
+ @Test
+ void givenStudentWithTooShortName_WhenReadStudent_ThenThrows() {
+ InputStream inputStream = getInputStream(NAME_TOO_SHORT_STUDENT_FILE);
+ ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream));
+ assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage());
+ }
+
+ @Test
+ void givenStudentWithTooLongName_WhenReadStudent_ThenThrows() {
+ InputStream inputStream = getInputStream(NAME_TOO_LONG_STUDENT_FILE);
+ ConstraintViolationException constraintViolationException = assertThrows(ConstraintViolationException.class, () -> StudentDeserializerWithValidation.readStudent(inputStream));
+ assertEquals(EXPECTED_ERROR_MESSAGE, constraintViolationException.getMessage());
+ }
+
+ private InputStream getInputStream(String fileName) {
+ return getClass().getClassLoader()
+ .getResourceAsStream(SUBDIRECTORY + fileName);
+ }
+
+}
diff --git a/javaxval2/src/test/resources/afterdeserialization/nameTooLongStudent.json b/javaxval2/src/test/resources/afterdeserialization/nameTooLongStudent.json
new file mode 100644
index 0000000000..e537ecb25d
--- /dev/null
+++ b/javaxval2/src/test/resources/afterdeserialization/nameTooLongStudent.json
@@ -0,0 +1,3 @@
+{
+ "name": "Constantine"
+}
\ No newline at end of file
diff --git a/javaxval2/src/test/resources/afterdeserialization/nameTooShortStudent.json b/javaxval2/src/test/resources/afterdeserialization/nameTooShortStudent.json
new file mode 100644
index 0000000000..79ab10cb80
--- /dev/null
+++ b/javaxval2/src/test/resources/afterdeserialization/nameTooShortStudent.json
@@ -0,0 +1,3 @@
+{
+ "name": "Max"
+}
\ No newline at end of file
diff --git a/javaxval2/src/test/resources/afterdeserialization/validStudent.json b/javaxval2/src/test/resources/afterdeserialization/validStudent.json
new file mode 100644
index 0000000000..938002ea51
--- /dev/null
+++ b/javaxval2/src/test/resources/afterdeserialization/validStudent.json
@@ -0,0 +1,3 @@
+{
+ "name": "Daniel"
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index be097f308d..feb9357bda 100644
--- a/pom.xml
+++ b/pom.xml
@@ -415,6 +415,7 @@
javax-sound
javaxval
javaxval-2
+ javax-validation-advanced
jaxb
jersey
jgit
@@ -820,6 +821,7 @@
javax-sound
javaxval
javaxval-2
+ javax-validation-advanced
jaxb
jersey
jgit