package nl.ipo.cds.validation; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import nl.ipo.cds.validation.execute.Compiler; import nl.ipo.cds.validation.execute.CompilerException; import nl.ipo.cds.validation.execute.ExpressionExecutor; /** * Unary tests must be deterministic (for the same input they should yield the same result). * * @author erik * * @param <K> * @param <T> */ public abstract class AbstractUnaryTestExpression<K extends Enum<K> & ValidationMessage<K, C>, C extends ValidatorContext<K, C>, T> extends AbstractExpression<K, C, Boolean> implements UnaryExpression<K, C, Boolean, T> { public final String name; public final Expression<K, C, T> input; public AbstractUnaryTestExpression (final Expression<K, C, T> input, final String name) { if (input == null) { throw new NullPointerException ("input cannot be null"); } if (name == null) { throw new NullPointerException ("name cannot be null"); } this.name = name; this.input = input; } @Override public Class<Boolean> getResultType () { return Boolean.class; } public Boolean evaluate (final C context, final T input) { return test (input, context); } @Override public Class<T> getInputType () { return input.getResultType (); } @Override public String toString () { return String.format ("%s(%s)", name, input.toString ()); } public abstract boolean test (T value, C context); private final static MethodHandle evaluateHandle = Compiler .findMethod ( AbstractUnaryTestExpression.class, "evaluate", MethodType.methodType (Boolean.class, ValidatorContext.class, Object.class) ); @Override public ExpressionExecutor<C> getExecutor (final Compiler<C> compiler) throws CompilerException { return ExpressionExecutor.create ( this, input, false, true, evaluateHandle.bindTo (this), false ); } @Override public boolean equals (final Object o) { if (o == null || !o.getClass ().equals (getClass ())) { return false; } final AbstractUnaryTestExpression<?, ?, ?> other = (AbstractUnaryTestExpression<?, ?, ?>)o; return name.equals (other.name) && input.equals (other.input); } @Override public int hashCode () { return name.hashCode () ^ input.hashCode (); } }