Skip to content

Instantly share code, notes, and snippets.

@talhaHavadar
Last active October 28, 2022 13:18
Show Gist options
  • Save talhaHavadar/0b0db2755e57e2427713285fc5107804 to your computer and use it in GitHub Desktop.
Save talhaHavadar/0b0db2755e57e2427713285fc5107804 to your computer and use it in GitHub Desktop.
Java validation structure by using combinator pattern #java #validation #combinator #designpatterns
package com.talhahavadar.exceptions;
/**
* Created by talhahavadar on 13.03.2018.
*/
public class InvalidPlateException extends RuntimeException {
private static final String message = "Plate information is not valid.";
public InvalidPlateException() {
this(message);
}
public InvalidPlateException(String message) {
super(message);
}
}
package com.talhahavadar;
import com.talhahavadar.models.Plate;
import com.talhahavadar.validation.PlateValidation;
import com.talhahavadar.validation.ValidationResult;
public class Main {
public static void main(String[] args) {
// write your code here
Plate istanbulPlate = new Plate(34, "AB", 3241);
System.out.println("First Validation check starts");
PlateValidation.validateThat()
.validCityCode()
.fromBalikesir()
.validPlateCode()
.apply(istanbulPlate).getReason().ifPresent(e -> System.out.println(e.getMessage()));
System.out.println("\nSecond Validation check starts");
ValidationResult result = PlateValidation.validateThat()
.validCityCode()
.fromIstanbul()
.validPlateCode()
.apply(istanbulPlate);
System.out.println(result.isValid());
result.getReason().ifPresent(e -> System.out.println(e.getMessage()));
}
}
package com.talhahavadar.models;
/**
* Created by talhahavadar on 13.03.2018.
*/
public class Plate {
private int cityCode;
private String plateText;
private int plateCode;
public Plate(int cityCode, String plateText, int plateCode) {
this.cityCode = cityCode;
this.plateText = plateText;
this.plateCode = plateCode;
}
public int getCityCode() {
return cityCode;
}
public void setCityCode(int cityCode) {
this.cityCode = cityCode;
}
public String getPlateText() {
return plateText;
}
public void setPlateText(String plateText) {
this.plateText = plateText;
}
public int getPlateCode() {
return plateCode;
}
public void setPlateCode(int plateCode) {
this.plateCode = plateCode;
}
}
package com.talhahavadar.validation;
import com.talhahavadar.exceptions.InvalidPlateException;
import com.talhahavadar.models.Plate;
import java.util.function.Predicate;
/**
* Created by talhahavadar on 13.03.2018.
*/
public interface PlateValidation extends Validation<Plate> {
default PlateValidation validCityCode() {
return and(validate(plate -> {
if (plate.getCityCode() > 0 && plate.getCityCode() <= 81) {
return ResultHolder.<Plate>hold().that(plate).withResult(true).build();
}
return ResultHolder.<Plate>hold().withException(new InvalidPlateException()).withResult(false).build();
}));
}
default PlateValidation validPlateCode() {
return and(validate(plate -> {
if (plate.getCityCode() > 0 && plate.getCityCode() <= 9999) {
return ResultHolder.<Plate>hold().that(plate).withResult(true).build();
}
return ResultHolder.<Plate>hold().withException(new InvalidPlateException()).withResult(false).build();
}));
}
default PlateValidation fromBalikesir() {
return and(validate(plate -> plate.getCityCode() == 10 ?
ResultHolder.<Plate>hold().that(plate).withResult(true).build() :
ResultHolder.<Plate>hold().withException(new InvalidPlateException()).withResult(false).build()));
}
default PlateValidation fromIstanbul() {
return and(validate(plate -> plate.getCityCode() == 34 ?
ResultHolder.<Plate>hold().that(plate).withResult(true).build() :
ResultHolder.<Plate>hold().withException(new InvalidPlateException()).withResult(false).build()));
}
static PlateValidation validateThat() {
return validate(plate -> ResultHolder.<Plate>hold().withResult(true).build());
}
static PlateValidation validate(Validate<Plate, Plate> validate) {
return plate -> {
ResultHolder<Plate> resultHolder = validate.doThat(plate);
return resultHolder.getException().isPresent() ? ValidationResult.invalid(resultHolder.getException().get()):
ValidationResult.valid();
};
}
default PlateValidation and(PlateValidation other) {
return plate -> {
ValidationResult validationResult = this.apply(plate);
return validationResult.isValid() ? other.apply(plate) : validationResult;
};
}
}
package com.talhahavadar.validation;
import java.util.Optional;
/**
* Created by talhahavadar on 13.03.2018.
*/
public class ResultHolder<T> {
private T value;
private boolean result;
private Exception exception;
private ResultHolder() {
}
public ResultHolder(T value, boolean result) {
this.value = value;
this.result = result;
}
public ResultHolder(T value, boolean result, Exception exception) {
this(value, result);
this.exception = exception;
}
public static <R> ResultHolderBuilder<R> hold() {
return new ResultHolderBuilder<>();
}
public T getValue() {
return value;
}
public boolean isValid() {
return result;
}
public Optional<Exception> getException() {
return Optional.ofNullable(exception);
}
public static class ResultHolderBuilder<T> {
private T value;
private boolean result;
private Exception exception;
private ResultHolderBuilder() {
}
public ResultHolderBuilder<T> that(T obj) {
this.value = obj;
return this;
}
public ResultHolderBuilder<T> withResult(boolean result) {
this.result = result;
return this;
}
public ResultHolderBuilder<T> withException(Exception exception) {
this.exception = exception;
return this;
}
public ResultHolder<T> build() {
return new ResultHolder<T>(value, result, exception);
}
}
}
package com.talhahavadar.validation;
/**
* Created by talhahavadar on 13.03.2018.
*/
@FunctionalInterface
public interface Validate<T, R> {
ResultHolder<R> doThat(T t);
}
package com.talhahavadar.validation;
import java.util.function.Function;
/**
* Created by talhahavadar on 6.03.2018.
*/
public interface Validation<T> extends Function<T, ValidationResult> {
}
package com.talhahavadar.validation;
import java.util.Optional;
/**
* Created by talhahavadar on 6.03.2018.
*/
public interface ValidationResult {
static ValidationResult valid() {
return new ValidationResult() {
@Override
public boolean isValid() {
return true;
}
@Override
public Optional<Exception> getReason() {
return Optional.empty();
}
};
}
static ValidationResult invalid(Exception message) {
return new ValidationResult() {
@Override
public boolean isValid() {
return false;
}
@Override
public Optional<Exception> getReason() {
return Optional.of(message);
}
};
}
boolean isValid();
Optional<Exception> getReason();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment