From b6869c1b17c65594f65c3ad5e53461082e5c3088 Mon Sep 17 00:00:00 2001
From: pacien
Date: Fri, 29 Mar 2019 01:31:15 +0100
Subject: initial impl
---
.../lemonad/validation/ValidationResult.java | 129 +++++++++++++++++++++
.../validation/ValidationResultContainer.java | 40 +++++++
.../org/pacien/lemonad/validation/Validator.java | 80 +++++++++++++
3 files changed, 249 insertions(+)
create mode 100644 src/main/java/org/pacien/lemonad/validation/ValidationResult.java
create mode 100644 src/main/java/org/pacien/lemonad/validation/ValidationResultContainer.java
create mode 100644 src/main/java/org/pacien/lemonad/validation/Validator.java
(limited to 'src/main/java/org/pacien/lemonad/validation')
diff --git a/src/main/java/org/pacien/lemonad/validation/ValidationResult.java b/src/main/java/org/pacien/lemonad/validation/ValidationResult.java
new file mode 100644
index 0000000..65bb389
--- /dev/null
+++ b/src/main/java/org/pacien/lemonad/validation/ValidationResult.java
@@ -0,0 +1,129 @@
+/*
+ * lemonad - Some functional sweetness for Java
+ * Copyright (C) 2019 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.lemonad.validation;
+
+import org.pacien.lemonad.attempt.Attempt;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import lombok.NonNull;
+
+import static java.util.stream.Collectors.toUnmodifiableList;
+import static org.pacien.lemonad.attempt.Attempt.failure;
+import static org.pacien.lemonad.attempt.Attempt.success;
+
+/**
+ * Wraps the result of the validation of a subject.
+ *
+ * @param the subject type,
+ * @param the error type.
+ * @author pacien
+ */
+public interface ValidationResult {
+ /**
+ * @return whether no error have been reported during the validation.
+ */
+ boolean isValid();
+
+ /**
+ * @return whether some error have been reported during the validation.
+ */
+ boolean isInvalid();
+
+ /**
+ * @return the subject of the validation.
+ */
+ S getSubject();
+
+ /**
+ * @return the potentially empty list of reported validation errors.
+ */
+ List getErrors();
+
+ /**
+ * @param consumer a subject consumer called if the validation is successful.
+ * @return the current object.
+ */
+ default ValidationResult ifValid(@NonNull Consumer super S> consumer) {
+ if (isValid()) consumer.accept(getSubject());
+ return this;
+ }
+
+ /**
+ * @param consumer the consumer called with the validation subject and reported errors if the validation is failed.
+ * @return the current object.
+ */
+ default ValidationResult ifInvalid(@NonNull BiConsumer super S, ? super List super E>> consumer) {
+ if (!isValid()) consumer.accept(getSubject(), getErrors());
+ return this;
+ }
+
+ /**
+ * @return an {@link Attempt} with a state corresponding to the one of the validation.
+ */
+ default Attempt> toAttempt() {
+ return isValid() ? success(getSubject()) : failure(getErrors());
+ }
+
+ /**
+ * @param mapper a function transforming a {@link ValidationResult}.
+ * @return the transformed {@link ValidationResult}.
+ */
+ default ValidationResult flatMap(@NonNull Function super ValidationResult super S, ? super E>, ? extends ValidationResult extends SS, ? extends EE>> mapper) {
+ //noinspection unchecked
+ return (ValidationResult) mapper.apply(this);
+ }
+
+ /**
+ * @param subject an overriding subject.
+ * @param validationResults a {@link Stream} of {@link ValidationResult}s to merge.
+ * @return the merged {@link ValidationResult} containing all errors from the supplied ones.
+ */
+ static ValidationResult merge(S subject, @NonNull Stream extends ValidationResult, ? extends E>> validationResults) {
+ return new ValidationResultContainer<>(
+ subject,
+ validationResults.flatMap(res -> res.getErrors().stream()).collect(toUnmodifiableList()));
+ }
+
+ /**
+ * @param subject the suject of the validation.
+ * @return a successful {@link ValidationResult}.
+ */
+ static ValidationResult valid(S subject) {
+ return new ValidationResultContainer<>(subject, List.of());
+ }
+
+ /**
+ * @param subject the suject of the validation.
+ * @param error a validation error.
+ * @param errors additional validation errors.
+ * @return a failed {@link ValidationResult} for the supplied subject.
+ */
+ @SafeVarargs static ValidationResult invalid(S subject, E error, E... errors) {
+ return new ValidationResultContainer<>(
+ subject,
+ Stream.concat(Stream.of(error), Arrays.stream(errors)).map(Objects::requireNonNull).collect(toUnmodifiableList()));
+ }
+}
diff --git a/src/main/java/org/pacien/lemonad/validation/ValidationResultContainer.java b/src/main/java/org/pacien/lemonad/validation/ValidationResultContainer.java
new file mode 100644
index 0000000..2c752f6
--- /dev/null
+++ b/src/main/java/org/pacien/lemonad/validation/ValidationResultContainer.java
@@ -0,0 +1,40 @@
+/*
+ * lemonad - Some functional sweetness for Java
+ * Copyright (C) 2019 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.lemonad.validation;
+
+import java.util.List;
+
+import lombok.NonNull;
+import lombok.Value;
+
+/**
+ * @author pacien
+ */
+@Value class ValidationResultContainer implements ValidationResult {
+ S subject;
+ @NonNull List errors;
+
+ @Override public boolean isValid() {
+ return errors.isEmpty();
+ }
+
+ @Override public boolean isInvalid() {
+ return !isValid();
+ }
+}
diff --git a/src/main/java/org/pacien/lemonad/validation/Validator.java b/src/main/java/org/pacien/lemonad/validation/Validator.java
new file mode 100644
index 0000000..a8a9e3f
--- /dev/null
+++ b/src/main/java/org/pacien/lemonad/validation/Validator.java
@@ -0,0 +1,80 @@
+/*
+ * lemonad - Some functional sweetness for Java
+ * Copyright (C) 2019 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.lemonad.validation;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import lombok.NonNull;
+import lombok.val;
+
+import static java.util.stream.Collectors.toUnmodifiableList;
+import static org.pacien.lemonad.validation.ValidationResult.invalid;
+import static org.pacien.lemonad.validation.ValidationResult.valid;
+
+/**
+ * A function which applies validation rules on a subject and reports possible errors.
+ *
+ * @param the subject type
+ * @param the error type
+ * @author pacien
+ */
+@FunctionalInterface public interface Validator {
+ /**
+ * @param subject the subject to validate, which can potentially be null.
+ * @return the non-null result of the validation of the supplied subject.
+ */
+ ValidationResult validate(S subject);
+
+ /**
+ * @param predicate the validation predicate testing the validity of a subject.
+ * @param negativeError an error to return if the subject does not pass the test.
+ * @return a {@link Validator} based on the supplied predicate and error.
+ */
+ static Validator ensuringPredicate(@NonNull Predicate super S> predicate, @NonNull E negativeError) {
+ return subject -> predicate.test(subject) ? valid(subject) : invalid(subject, negativeError);
+ }
+
+ /**
+ * @param validators the {@link Validator}s to combine, to be evaluated in order of listing.
+ * @return a {@link Validator} based on the supplied ones.
+ */
+ @SafeVarargs static Validator validatingAll(@NonNull Validator super S, ? extends E>... validators) {
+ val validatorList = Arrays.stream(validators).map(Objects::requireNonNull).collect(toUnmodifiableList());
+ return subject -> new ValidationResultContainer<>(
+ subject,
+ validatorList.stream()
+ .flatMap(validator -> validator.validate(subject).getErrors().stream())
+ .collect(toUnmodifiableList()));
+ }
+
+ /**
+ * @param getter the field getter mapping the validation subject.
+ * @param validator the {@link Validator} validating the field.
+ * @return a {@link Validator} validating the parent object.
+ */
+ static Validator validatingField(@NonNull Function super S, ? extends F> getter,
+ @NonNull Validator super F, ? extends E> validator) {
+ //noinspection unchecked
+ return subject -> new ValidationResultContainer<>(subject, (List) validator.validate(getter.apply(subject)).getErrors());
+ }
+}
--
cgit v1.2.3