// CustomConstraints.java
package constraints;
import com.avaje.ebean.ExpressionList;
import play.data.validation.Constraints;
import play.db.ebean.Model;
import play.libs.F.Tuple;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static play.libs.F.Tuple;
public class CustomConstraints extends Constraints {
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueValidator.class)
@play.data.Form.Display(name = "constraint.unique")
public static @interface Unique {
String message() default UniqueValidator.message;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<?> idClass() default Long.class;
Class<? extends Model> modelClass();
String[] fields();
}
public static class UniqueValidator extends Validator<Object> implements ConstraintValidator<Unique, Object> {
final static public String message = "error.unique";
private Class<? extends Model> modelClass;
private Class<?> idClass;
private String[] fields;
public void initialize(Unique constraintAnnotation) {
this.modelClass = constraintAnnotation.modelClass();
this.idClass = constraintAnnotation.idClass();
this.fields = constraintAnnotation.fields();
}
@Override
public boolean isValid(Object o) {
Model.Finder<?, ? extends Model> find = new Model.Finder(idClass, modelClass);
ExpressionList el = find.where();
for (String f : fields) {
el.eq(f, o);
}
return el.findRowCount() == 0;
}
public Tuple<String, Object[]> getErrorMessageKey() {
return Tuple(message, new Object[]{});
}
}
}
This code works correctly only if we add a new record in the database (notupdating). In the Play Framework 1.x, I used the previous values to build a correct validation. Now the constraints do not know anything about the previous values of the field.
package validation;
import net.sf.oval.configuration.annotation.Constraint;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Constraint(checkWith = UniqueCheck.class)
public @interface Unique {
String message() default UniqueCheck.mes;
}
// UniqueCheck.java
public class UniqueCheck extends AbstractAnnotationCheck<Unique> {
final static String mes = "validation.unique";
@Override
public void configure(Unique unique) {
setMessage(unique.message());
}
@Override
public boolean isSatisfied(Object validatedObject, Object value, OValContext context, Validator validator) {
String uniqueValue = (String) value;
if ("".equals(uniqueValue)) {
return true;
}
Model object = (Model) validatedObject;
Class cls = validatedObject.getClass();
try {
Method countMethod = cls.getDeclaredMethod("count", String.class, Object[].class);
String fieldName = ((FieldContext) context).getField().getName();
Long count;
count = (Long) countMethod.invoke(null, fieldName + " = ?1", new Object[]{uniqueValue});
} else {
count = (Long) countMethod.invoke(null, fieldName + " = ?1 and id != ?2", new Object[]{uniqueValue,
object.id});
}
return count == 0;
} catch (Exception e) {
return false;
}
}
}