From 7e26990eb94e5bc80a08a90267410afc77df92a6 Mon Sep 17 00:00:00 2001 From: Alejandro Gervasio Date: Fri, 1 Sep 2017 18:33:58 -0300 Subject: [PATCH] An Introduction to Vavr's Validation API - Alejandro Gervasio | alejandro.gervasio@gmail.com (#2526) * Initial Commit * Refactored Application class * Refactored Application class * Refactored Application class * Refactored User class * Added ValidationTest class * Reorganized imports in ValidatorTest class * Reformatted source code * Reformatted source code --- .../application/Application.java | 17 +++++ .../baeldung/vavrvalidation/model/User.java | 18 +++++ .../validator/UserValidator.java | 29 ++++++++ .../validator/UserValidatorTest.java | 23 +++++++ .../validator/ValidationTest.java | 68 +++++++++++++++++++ 5 files changed, 155 insertions(+) create mode 100644 vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/application/Application.java create mode 100644 vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/model/User.java create mode 100644 vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/validator/UserValidator.java create mode 100644 vavr/vavr-validation/src/test/java/com/baeldung/vavrvalidation/validator/UserValidatorTest.java create mode 100644 vavr/vavr-validation/src/test/java/com/baeldung/vavrvalidation/validator/ValidationTest.java diff --git a/vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/application/Application.java b/vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/application/Application.java new file mode 100644 index 0000000000..8acc4522af --- /dev/null +++ b/vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/application/Application.java @@ -0,0 +1,17 @@ +package com.baeldung.vavrvalidation.application; + +import com.baeldung.vavrvalidation.model.User; +import com.baeldung.vavrvalidation.validator.UserValidator; +import io.vavr.collection.Seq; +import io.vavr.control.Validation; + +public class Application { + + public static void main(String[] args) { + + UserValidator userValidator = new UserValidator(); + Validation, User> validation = userValidator.validateUser("John", "john@domain.com"); + + // process validation results here + } +} diff --git a/vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/model/User.java b/vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/model/User.java new file mode 100644 index 0000000000..f1477a1ed3 --- /dev/null +++ b/vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/model/User.java @@ -0,0 +1,18 @@ +package com.baeldung.vavrvalidation.model; + +public class User { + private String name; + private String email; + + public User(String name, String email) { + this.name = name; + this.email = email; + } + + @Override + public String toString() { + return "User [name=" + name + ", email=" + email + "]"; + } + + // standard setters and getters +} diff --git a/vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/validator/UserValidator.java b/vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/validator/UserValidator.java new file mode 100644 index 0000000000..1cec006816 --- /dev/null +++ b/vavr/vavr-validation/src/main/java/com/baeldung/vavrvalidation/validator/UserValidator.java @@ -0,0 +1,29 @@ +package com.baeldung.vavrvalidation.validator; + +import com.baeldung.vavrvalidation.model.User; +import io.vavr.collection.CharSeq; +import io.vavr.collection.Seq; +import io.vavr.control.Validation; + +public class UserValidator { + + private static final String NAME_PATTERN = "^[a-zA-Z0-9]+$"; + private static final String NAME_ERROR = "Name contains invalid characters"; + private static final String EMAIL_PATTERN = + "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; + private static final String EMAIL_ERROR = "Email must be a well-formed email address"; + + public Validation, User> validateUser(String name, String email) { + return Validation + .combine(validateField(name, NAME_PATTERN, NAME_ERROR) + ,validateField(email, EMAIL_PATTERN, EMAIL_ERROR)) + .ap(User::new); + } + + private Validation validateField(String field, String pattern, String error) { + return CharSeq.of(field).replaceAll(pattern, "").transform(seq -> seq.isEmpty() + ? Validation.valid(field) + : Validation.invalid(error)); + } +} diff --git a/vavr/vavr-validation/src/test/java/com/baeldung/vavrvalidation/validator/UserValidatorTest.java b/vavr/vavr-validation/src/test/java/com/baeldung/vavrvalidation/validator/UserValidatorTest.java new file mode 100644 index 0000000000..cb9557fa53 --- /dev/null +++ b/vavr/vavr-validation/src/test/java/com/baeldung/vavrvalidation/validator/UserValidatorTest.java @@ -0,0 +1,23 @@ +package com.baeldung.vavrvalidation.validator; + +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.instanceOf; +import org.junit.Test; +import com.baeldung.vavrvalidation.validator.UserValidator; +import io.vavr.control.Validation.Invalid; +import io.vavr.control.Validation.Valid; + +public class UserValidatorTest { + + @Test + public void givenValidUserParams_whenValidated_thenInstanceOfValid() { + UserValidator userValidator = new UserValidator(); + assertThat(userValidator.validateUser("John", "john@domain.com"), instanceOf(Valid.class)); + } + + @Test + public void givenInvalidUserParams_whenValidated_thenInstanceOfInvalid() { + UserValidator userValidator = new UserValidator(); + assertThat(userValidator.validateUser("John", "no-email"), instanceOf(Invalid.class)); + } +} diff --git a/vavr/vavr-validation/src/test/java/com/baeldung/vavrvalidation/validator/ValidationTest.java b/vavr/vavr-validation/src/test/java/com/baeldung/vavrvalidation/validator/ValidationTest.java new file mode 100644 index 0000000000..c89b43b5e3 --- /dev/null +++ b/vavr/vavr-validation/src/test/java/com/baeldung/vavrvalidation/validator/ValidationTest.java @@ -0,0 +1,68 @@ +package com.baeldung.vavrvalidation.validator; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import com.baeldung.vavrvalidation.model.User; +import io.vavr.collection.Seq; +import io.vavr.control.Either.Right; +import io.vavr.control.Validation.Invalid; +import io.vavr.control.Validation.Valid; + +public class ValidationTest { + + private static UserValidator userValidator; + + @BeforeClass + public static void setUpUserValidatorInstance() { + userValidator = new UserValidator(); + } + + @AfterClass + public static void teardownUserValidatorInstance() { + userValidator = null; + } + + @Test + public void givenInvalidUserParams_whenValidated_thenInvalidInstance() { + assertThat(userValidator.validateUser("John", "no-email"), instanceOf(Invalid.class)); + } + + @Test + public void givenValidUserParams_whenValidated_thenValidInstance() { + assertThat(userValidator.validateUser("John", "john@domain.com"), instanceOf(Valid.class)); + } + + @Test + public void givenInvalidUserParams_whenValidated_thenTrueWithIsInvalidMethod() { + assertTrue(userValidator.validateUser("John", "no-email").isInvalid()); + } + + @Test + public void givenValidUserParams_whenValidated_thenTrueWithIsValidMethod() { + assertTrue(userValidator.validateUser("John", "john@domain.com").isValid()); + } + + @Test + public void givenInValidUserParams_withGetErrorMethod_thenGetErrorMessages() { + assertEquals("Name contains invalid characters, Email must be a well-formed email address", userValidator.validateUser(" ", "no-email") + .getError().intersperse(", ").fold("", String::concat)); + } + + @Test + public void givenValidUserParams_withGetMethod_thenGetUserInstance() { + assertThat(userValidator.validateUser("John", "john@domain.com").get(), instanceOf(User.class)); + } + + @Test + public void givenValidUserParams_withtoEitherMethod_thenRightInstance() { + assertThat(userValidator.validateUser("John", "john@domain.com").toEither(), instanceOf(Right.class)); + } + + @Test + public void givenValidUserParams_withFoldMethodWithListlengthUserHashCode_thenEqualstoParamsLength() { + assertEquals(2, (int) userValidator.validateUser(" ", " ").fold(Seq::length, User::hashCode)); + } +}