|
| 1 | +package com.iluwatar.monad; |
| 2 | + |
| 3 | +import java.util.ArrayList; |
| 4 | +import java.util.List; |
| 5 | +import java.util.Objects; |
| 6 | +import java.util.function.Function; |
| 7 | +import java.util.function.Predicate; |
| 8 | + |
| 9 | +/** |
| 10 | + * Class representing Monad design pattern. Monad is a way of chaining operations on the |
| 11 | + * given object together step by step. In Validator each step results in either success or |
| 12 | + * failure indicator, giving a way of receiving each of them easily and finally getting |
| 13 | + * validated object or list of exceptions. |
| 14 | + * @param <T> Placeholder for an object. |
| 15 | + */ |
| 16 | +public class Validator<T> { |
| 17 | + private final T t; |
| 18 | + private final List<Throwable> exceptions = new ArrayList<>(); |
| 19 | + |
| 20 | + /** |
| 21 | + * @param t object to be validated |
| 22 | + */ |
| 23 | + private Validator(T t) { |
| 24 | + this.t = t; |
| 25 | + } |
| 26 | + |
| 27 | + /** |
| 28 | + * Creates validator against given object |
| 29 | + * |
| 30 | + * @param t object to be validated |
| 31 | + * @param <T> object's type |
| 32 | + * @return new instance of a validator |
| 33 | + */ |
| 34 | + public static <T> Validator<T> of(T t) { |
| 35 | + return new Validator<>(Objects.requireNonNull(t)); |
| 36 | + } |
| 37 | + |
| 38 | + /** |
| 39 | + * @param validation one argument boolean-valued function that |
| 40 | + * represents one step of validation. Adds exception to main validation exception |
| 41 | + * list when single step validation ends with failure. |
| 42 | + * @param message error message when object is invalid |
| 43 | + * @return this |
| 44 | + */ |
| 45 | + public Validator<T> validate(Predicate<T> validation, String message) { |
| 46 | + if (!validation.test(t)) { |
| 47 | + exceptions.add(new IllegalStateException(message)); |
| 48 | + } |
| 49 | + return this; |
| 50 | + } |
| 51 | + |
| 52 | + /** |
| 53 | + * Extension for the {@link Validator#validate(Function, Predicate, String)} method, |
| 54 | + * dedicated for objects, that need to be projected before requested validation. |
| 55 | + * @param projection function that gets an objects, and returns projection representing |
| 56 | + * element to be validated. |
| 57 | + * @param validation see {@link Validator#validate(Function, Predicate, String)} |
| 58 | + * @param message see {@link Validator#validate(Function, Predicate, String)} |
| 59 | + * @param <U> see {@link Validator#validate(Function, Predicate, String)} |
| 60 | + * @return this |
| 61 | + */ |
| 62 | + public <U> Validator<T> validate(Function<T, U> projection, Predicate<U> validation, |
| 63 | + String message) { |
| 64 | + return validate(projection.andThen(validation::test)::apply, message); |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * To receive validated object. |
| 69 | + * |
| 70 | + * @return object that was validated |
| 71 | + * @throws IllegalStateException when any validation step results with failure |
| 72 | + */ |
| 73 | + public T get() throws IllegalStateException { |
| 74 | + if (exceptions.isEmpty()) { |
| 75 | + return t; |
| 76 | + } |
| 77 | + IllegalStateException e = new IllegalStateException(); |
| 78 | + exceptions.forEach(e::addSuppressed); |
| 79 | + throw e; |
| 80 | + } |
| 81 | +} |
0 commit comments