diff --git a/apache-bval/pom.xml b/apache-bval/pom.xml
new file mode 100644
index 0000000000..5d556af56f
--- /dev/null
+++ b/apache-bval/pom.xml
@@ -0,0 +1,51 @@
+
+ 4.0.0
+ apache-bval
+ apache-bval
+ 0.0.1-SNAPSHOT
+
+
+
+ org.apache.bval
+ bval-jsr
+ ${bval.version}
+
+
+ javax.validation
+ validation-api
+ 1.1.0.Final
+
+
+ org.apache.bval
+ bval-extras
+ ${bval.version}
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ 1.8
+ 1.8
+
+
+
+
+
+ 3.6.0
+ 4.12
+ 1.1.2
+
+
\ No newline at end of file
diff --git a/apache-bval/src/main/java/com/baeldung/model/User.java b/apache-bval/src/main/java/com/baeldung/model/User.java
new file mode 100644
index 0000000000..477136ddb4
--- /dev/null
+++ b/apache-bval/src/main/java/com/baeldung/model/User.java
@@ -0,0 +1,120 @@
+package com.baeldung.model;
+
+import java.io.File;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+import org.apache.bval.constraints.Email;
+import org.apache.bval.constraints.NotEmpty;
+import org.apache.bval.extras.constraints.checkdigit.IBAN;
+import org.apache.bval.extras.constraints.creditcard.Visa;
+import org.apache.bval.extras.constraints.file.Directory;
+import org.apache.bval.extras.constraints.net.InetAddress;
+
+import com.baeldung.validation.Password;
+
+public class User {
+ @NotNull
+ @Email
+ private String email;
+
+ @NotEmpty
+ @Password
+ private String password;
+
+ @Size(min = 1, max = 20)
+ private String name;
+
+ @Min(18)
+ private int age;
+
+ @Visa
+ private String cardNumber = "";
+
+ @IBAN
+ private String iban = "";
+
+ @InetAddress
+ private String website = "";
+
+ @Directory
+ private File mainDirectory=new File(".");
+
+ public User() {
+ }
+
+ public User(String email, String password, String name, int age) {
+ super();
+ this.email = email;
+ this.password = password;
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getCardNumber() {
+ return cardNumber;
+ }
+
+ public void setCardNumber(String cardNumber) {
+ this.cardNumber = cardNumber;
+ }
+
+ public String getIban() {
+ return iban;
+ }
+
+ public void setIban(String iban) {
+ this.iban = iban;
+ }
+
+ public String getWebsite() {
+ return website;
+ }
+
+ public void setWebsite(String website) {
+ this.website = website;
+ }
+
+ public File getMainDirectory() {
+ return mainDirectory;
+ }
+
+ public void setMainDirectory(File mainDirectory) {
+ this.mainDirectory = mainDirectory;
+ }
+
+}
diff --git a/apache-bval/src/main/java/com/baeldung/validation/Password.java b/apache-bval/src/main/java/com/baeldung/validation/Password.java
new file mode 100644
index 0000000000..4ae06b2fb0
--- /dev/null
+++ b/apache-bval/src/main/java/com/baeldung/validation/Password.java
@@ -0,0 +1,25 @@
+package com.baeldung.validation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+import static java.lang.annotation.ElementType.*;
+
+@Constraint(validatedBy = { PasswordValidator.class })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Password {
+ String message() default "Invalid password";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ int length() default 6;
+
+ int nonAlpha() default 1;
+}
diff --git a/apache-bval/src/main/java/com/baeldung/validation/PasswordValidator.java b/apache-bval/src/main/java/com/baeldung/validation/PasswordValidator.java
new file mode 100644
index 0000000000..19038d04d5
--- /dev/null
+++ b/apache-bval/src/main/java/com/baeldung/validation/PasswordValidator.java
@@ -0,0 +1,35 @@
+package com.baeldung.validation;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class PasswordValidator implements ConstraintValidator {
+
+ private int length;
+ private int nonAlpha;
+
+ @Override
+ public void initialize(Password password) {
+ this.length = password.length();
+ this.nonAlpha = password.nonAlpha();
+
+ }
+
+ @Override
+ public boolean isValid(String value, ConstraintValidatorContext context) {
+ if (value.length() < length) {
+ return false;
+ }
+ int nonAlphaNr = 0;
+ for (int i = 0; i < value.length(); i++) {
+ if (!Character.isLetterOrDigit(value.charAt(i))) {
+ nonAlphaNr++;
+ }
+ }
+ if (nonAlphaNr < nonAlpha) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/apache-bval/src/test/java/com/baeldung/validation/ValidationTest.java b/apache-bval/src/test/java/com/baeldung/validation/ValidationTest.java
new file mode 100644
index 0000000000..cd58d4460a
--- /dev/null
+++ b/apache-bval/src/test/java/com/baeldung/validation/ValidationTest.java
@@ -0,0 +1,97 @@
+package com.baeldung.validation;
+
+import java.io.File;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+import org.apache.bval.jsr.ApacheValidationProvider;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+import com.baeldung.model.User;
+
+public class ValidationTest {
+ private static ValidatorFactory validatorFactory;
+ private static Validator validator;
+
+ @BeforeClass
+ public static void setup() {
+ validatorFactory = Validation.byProvider(ApacheValidationProvider.class)
+ .configure()
+ .buildValidatorFactory();
+ validator = validatorFactory.getValidator();
+ }
+
+ @Test
+ public void givenUser_whenValidate_thenValidationViolations() {
+ User user = new User("ana@yahoo.com", "pass", "nameTooLong_______________", 15);
+
+ Set> violations = validator.validate(user);
+ assertTrue("no violations", violations.size() > 0);
+ }
+
+ @Test
+ public void givenInvalidAge_whenValidateProperty_thenConstraintViolation() {
+ User user = new User("ana@yahoo.com", "pass", "Ana", 12);
+
+ Set> propertyViolations = validator.validateProperty(user, "age");
+ assertEquals("size is not 1", 1, propertyViolations.size());
+ }
+
+ @Test
+ public void givenValidAge_whenValidateValue_thenNoConstraintViolation() {
+ User user = new User("ana@yahoo.com", "pass", "Ana", 18);
+
+ Set> valueViolations = validator.validateValue(User.class, "age", 20);
+ assertEquals("size is not 0", 0, valueViolations.size());
+ }
+
+ @Test
+ public void whenValidateNonJSR_thenCorrect() {
+ User user = new User("ana@yahoo.com", "pass", "Ana", 20);
+ user.setCardNumber("1234");
+ user.setIban("1234");
+ user.setWebsite("10.0.2.50");
+ user.setMainDirectory(new File("."));
+
+ Set> violations = validator.validateProperty(user, "iban");
+ assertEquals("size is not 1", 1, violations.size());
+
+ violations = validator.validateProperty(user, "website");
+ assertEquals("size is not 0", 0, violations.size());
+
+ violations = validator.validateProperty(user, "mainDirectory");
+ assertEquals("size is not 0", 0, violations.size());
+ }
+
+ @Test
+ public void givenInvalidPassword_whenValidatePassword_thenConstraintViolation() {
+ User user = new User("ana@yahoo.com", "password", "Ana", 20);
+ Set> violations = validator.validateProperty(user, "password");
+ assertEquals("message incorrect", "Invalid password", violations.iterator()
+ .next()
+ .getMessage());
+ }
+
+ @Test
+ public void givenValidPassword_whenValidatePassword_thenNoConstraintViolation() {
+ User user = new User("ana@yahoo.com", "password#", "Ana", 20);
+
+ Set> violations = validator.validateProperty(user, "password");
+ assertEquals("size is not 0", 0, violations.size());
+ }
+
+ @AfterClass
+ public static void close() {
+ if (validatorFactory != null) {
+ validatorFactory.close();
+ }
+ }
+}