Skip to content

Instantly share code, notes, and snippets.

@gabfssilva
Last active October 21, 2017 00:08
Show Gist options
  • Save gabfssilva/4795245c49272ede703afaf32b340e1c to your computer and use it in GitHub Desktop.
Save gabfssilva/4795245c49272ede703afaf32b340e1c to your computer and use it in GitHub Desktop.
java 8 based validator
package org.validation.java;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author Gabriel Francisco <[email protected]>
*/
public interface Result {
default boolean isFailure() {
return this instanceof Failure;
}
static <T> Stream<Validation> validations(Validator<T> validator, T bean) {
return validator.validator
.stream()
.flatMap(f -> f.apply(bean));
}
static <R extends Result, T> R of(Validator<T> validator, T bean) {
final Set<Violation> violations = validations(validator, bean)
.filter(v -> !v.getRequirement())
.map(Validation::<Failure>result)
.map(Failure::getViolations)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
if (violations.isEmpty()) return (R) new Success();
return (R) new Failure(violations);
}
}
class Success implements Result {
@Override
public String toString() {
return "Success{}";
}
}
class Failure implements Result {
private Set<Violation> violations;
public Failure(Violation violation) {
this.violations = Collections.singleton(violation);
}
public Failure(Set<Violation> violations) {
this.violations = violations;
}
public Set<Violation> getViolations() {
return violations;
}
@Override
public String toString() {
return "Failure{" +
"violations=" + violations +
'}';
}
}
--------------------------
package org.validation.java;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class Validation {
private String field;
private Boolean requirement;
private Supplier<String> message;
public static Stream<Validation> require(Boolean requirement, String message) {
return Stream.of(new Validation(requirement, message));
}
public Validation(String field, Boolean requirement, Supplier<String> message) {
this.field = field;
this.requirement = requirement;
this.message = message;
}
public Validation(String field, Boolean requirement, String message) {
this.field = field;
this.requirement = requirement;
this.message = () -> message;
}
public Validation(Boolean requirement, String message) {
this.requirement = requirement;
this.message = () -> message;
}
public Validation(Boolean requirement, Supplier<String> message) {
this.requirement = requirement;
this.message = message;
}
public Boolean getRequirement() {
return requirement;
}
public Supplier<String> getMessage() {
return message;
}
public String getField() {
return field;
}
public <T extends Result> T result() {
if (requirement) return (T) new Success();
return (T) new Failure(new Violation(field, message.get()));
}
}
-------------------------------------
package org.validation.java;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import static org.validation.java.Validation.require;
/**
* @author Gabriel Francisco <[email protected]>
*/
public class Validator<T> {
protected Set<Function<T, Stream<Validation>>> validator;
private Validator(Set<Function<T, Stream<Validation>>> validator) {
this.validator = validator;
}
public static <T> ValidatorBuilder<T> newValidator() {
return new ValidatorBuilder<>();
}
public Stream<Validation> validations(T bean) {
return Result.validations(this, bean);
}
public Result validate(T bean) {
return Result.of(this, bean);
}
public static class ValidatorBuilder<T> {
protected Set<Function<T, Stream<Validation>>> validators = new HashSet<>();
public ValidatorBuilder<T> withValidation(Function<T, Stream<Validation>> func) {
validators.add(func);
return this;
}
public Validator<T> build() {
return new Validator<>(validators);
}
}
}
@gabfssilva
Copy link
Author

gabfssilva commented Oct 16, 2017

Java:

class Test {
    static class Address {
        String address;

        public Address(String address) {
            this.address = address;
        }
    }

    static class User {
        Long id;
        String name;
        Address address;

        public User(Long id, String name, Address address) {
            this.id = id;
            this.name = name;
            this.address = address;
        }
    }

    public static void main(String[] args) {
        final Validator<Address> addressValidator = Validator.<Address>newValidator()
                .withValidation(a -> require(a.address != null, "address cannot be null"))
                .build();

        final Validator<User> userValidator =
                Validator.<User>newValidator()
                        .withValidation(u -> require(u.id != null, "id cannot be null"))
                        .withValidation(u -> require(u.name != null, "name cannot be null"))
                        .withValidation(u -> addressValidator.validations(u.address))
                        .build();

        final Result result = userValidator.validate(new User(1l, null, new Address(null)));
        System.out.println(result);
    }
}

@gabfssilva
Copy link
Author

Kotlin:

data class User(val id: Long, val name: String)

val userValidator =
  Validator
    .newValidator<User>()
    .withValidation { require(it.name.isNotEmpty(), "name cannot be empty") }
    .withValidation { require(it.id > 0, "id cannot be lower than 1")}

object Exec {
    @JvmStatic
    fun main(args: Array<String>) {
        println(userValidator.validate(User(1L, "")))
    }
}

@gabfssilva
Copy link
Author

gabfssilva commented Oct 16, 2017

Scala:

case class AddressScala(address: String)

case class UserScala(id: Long, name: String, address: AddressScala)


object SampleScala extends App {
  val addressValidator =
    Validator.newValidator[AddressScala]()
      .withValidation { a => require(a.address != null, "address cannot be empty") }
      .build()

  val userValidator =
    Validator.newValidator[UserScala]()
      .withValidation { u => require(u.name.nonEmpty, "name cannot be empty") }
      .withValidation { u => require(u.id > 0, "id cannot be lower than 1") }
      .withValidation { u => addressValidator.validations(u.address) }
      .build()

  println(
    userValidator.validate(UserScala(1l, "", AddressScala(null)))
  )
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment