Java custom validation with predicate annotation

Published: Fri, 14 Oct 2016

Just two small classes I wrote to be able to do some easy validation when you need to have more contextual information when validating an entity. This will allow you to do that easily while preventing the rewriting of boilerplate code.

The annotation:

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

import java.lang.annotation.Repeatable;
import javax.validation.Constraint;
import javax.validation.Payload;

@Target({TYPE})
@Retention(RUNTIME)
@Repeatable(Predicate.List.class)
@Constraint(validatedBy = PredicateValidator.class)
@Documented
public @interface Predicate {

	String message() default "{predicate.invalid}";

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};

	String name();

	@Target({TYPE})
	@Retention(RUNTIME)
	@Documented
	public @interface List {
		Predicate[] value();
	}
}

The validator:

import java.util.HashMap;
import java.util.Map;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PredicateValidator implements ConstraintValidator<Predicate, Object> {

	private static final Map<String, java.util.function.Predicate> PREDICATES = new HashMap<>();

	private java.util.function.Predicate predicate;

	@Override
	public void initialize(Predicate predicate) {
		if (!PREDICATES.containsKey(predicate.name())) {
			throw new IllegalArgumentException("No predicate with name " + predicate.name() + " found");
		}
		this.predicate = PREDICATES.get(predicate.name());
	}

	@Override
	public boolean isValid(Object value, ConstraintValidatorContext context) {
		return predicate.test(value);
	}

	public static void addPredicate(String name, java.util.function.Predicate p) {
		PREDICATES.put(name, p);
	}
}

And a small example:

import java.util.Objects;

@Predicate(name = "myPredicate")
@Predicate(name = "myPredicate2")
public class Pojo {

	static {
		PredicateValidator.addPredicate("myPredicate", obj -> {
			Pojo p = (Pojo) obj;
			System.out.println("Test 1");
			return Objects.equals(p.getValueOne(), p.getValueTwo());
		});

		PredicateValidator.addPredicate("myPredicate2", obj -> {
			Pojo p = (Pojo) obj;
			System.out.println("Test 2");
			return Objects.equals(p.getValueOne(), p.getValueTwo());
		});
	}

	private String valueOne;
	private String valueTwo;

	public String getValueOne() {
		return valueOne;
	}

	public void setValueOne(String valueOne) {
		this.valueOne = valueOne;
	}

	public String getValueTwo() {
		return valueTwo;
	}

	public void setValueTwo(String valueTwo) {
		this.valueTwo = valueTwo;
	}

}