Last active
December 18, 2015 05:09
-
-
Save bmchild/5730620 to your computer and use it in GitHub Desktop.
JSR303 @ScriptAssert with field error
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
*/ | |
package com.bmchild.validation.constraints; | |
import static java.lang.annotation.ElementType.TYPE; | |
import static java.lang.annotation.RetentionPolicy.RUNTIME; | |
import java.lang.annotation.Documented; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.Target; | |
import javax.validation.Constraint; | |
import javax.validation.Payload; | |
import org.hibernate.validator.constraints.ScriptAssert; | |
/** | |
* Uses {@link ScriptAssert} logic to validate the class and allows field error definitions | |
* | |
* @see ScriptAssert | |
* @author bchild | |
* | |
*/ | |
@Target({ TYPE }) | |
@Retention(RUNTIME) | |
@Constraint(validatedBy = {ScriptAssertFieldErrorValidator.class }) | |
@Documented | |
public @interface ScriptAssertFieldError { | |
String message() default "{org.hibernate.validator.constraints.ScriptAssert.message}"; | |
Class<?>[] groups() default { }; | |
Class<? extends Payload>[] payload() default { }; | |
/** | |
* @return The name of the script language used by this constraint as | |
* expected by the JSR 223 {@link javax.script.ScriptEngineManager}. A | |
* {@link javax.validation.ConstraintDeclarationException} will be thrown upon script | |
* evaluation, if no engine for the given language could be found. | |
*/ | |
String lang(); | |
/** | |
* @return The script to be executed. The script must return | |
* <code>Boolean.TRUE</code>, if the annotated element could | |
* successfully be validated, otherwise <code>Boolean.FALSE</code>. | |
* Returning null or any type other than Boolean will cause a | |
* {@link javax.validation.ConstraintDeclarationException} upon validation. Any | |
* exception occurring during script evaluation will be wrapped into | |
* a ConstraintDeclarationException, too. Within the script, the | |
* validated object can be accessed from the {@link javax.script.ScriptContext | |
* script context} using the name specified in the | |
* <code>alias</code> attribute. | |
*/ | |
String script(); | |
/** | |
* @return The name, under which the annotated element shall be registered | |
* within the script context. Defaults to "_this". | |
*/ | |
String alias() default "_this"; | |
String fieldName(); | |
/** | |
* Defines several {@code @ScriptAssert} annotations on the same element. | |
*/ | |
@Target({ TYPE }) | |
@Retention(RUNTIME) | |
@Documented | |
public @interface List { | |
ScriptAssertFieldError[] value(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
*/ | |
package com.crengland.validation.constraints; | |
import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES; | |
import javax.script.ScriptException; | |
import javax.validation.ConstraintDeclarationException; | |
import javax.validation.ConstraintValidator; | |
import javax.validation.ConstraintValidatorContext; | |
import org.apache.commons.lang.StringUtils; | |
import org.hibernate.validator.internal.constraintvalidators.ScriptAssertValidator; | |
import org.hibernate.validator.internal.util.Contracts; | |
import org.hibernate.validator.internal.util.scriptengine.ScriptEvaluator; | |
import org.hibernate.validator.internal.util.scriptengine.ScriptEvaluatorFactory; | |
import com.bmchild.common.validation.ConstraintValidatorUtils; | |
/** | |
* Validator for {@link ScriptAssertFieldError} | |
* @see ScriptAssertValidator | |
* @author bchild | |
* | |
*/ | |
public class ScriptAssertFieldErrorValidator implements ConstraintValidator<ScriptAssertFieldError, Object> { | |
private static final String TRUE_OR_FALSE_EXCEPTION = "script must return true or false"; | |
private String script; | |
private String languageName; | |
private String alias; | |
private String fieldName; | |
private String errorMessage; | |
@Override | |
public void initialize(ScriptAssertFieldError constraintAnnotation) { | |
validateParameters( constraintAnnotation ); | |
this.script = constraintAnnotation.script(); | |
this.languageName = constraintAnnotation.lang(); | |
this.alias = constraintAnnotation.alias(); | |
this.fieldName = constraintAnnotation.fieldName(); | |
this.errorMessage = constraintAnnotation.message(); | |
} | |
/* (non-Javadoc) | |
* @see javax.validation.ConstraintValidator#isValid(java.lang.Object, javax.validation.ConstraintValidatorContext) | |
*/ | |
@Override | |
public boolean isValid(Object value, ConstraintValidatorContext context) { | |
Object evaluationResult; | |
ScriptEvaluator scriptEvaluator; | |
try { | |
ScriptEvaluatorFactory evaluatorFactory = ScriptEvaluatorFactory.getInstance(); | |
scriptEvaluator = evaluatorFactory.getScriptEvaluatorByLanguageName( languageName ); | |
} | |
catch ( ScriptException e ) { | |
throw new ConstraintDeclarationException( e ); | |
} | |
try { | |
evaluationResult = scriptEvaluator.evaluate( script, value, alias ); | |
} | |
catch ( ScriptException e ) { | |
throw new ConstraintDeclarationException("An error occurred during script execution", e); | |
} | |
if ( evaluationResult == null ) { | |
throw new ConstraintDeclarationException(TRUE_OR_FALSE_EXCEPTION); | |
} | |
if ( !( evaluationResult instanceof Boolean ) ) { | |
throw new ConstraintDeclarationException(TRUE_OR_FALSE_EXCEPTION); | |
} | |
Boolean result = Boolean.TRUE.equals( evaluationResult ); | |
if(!result && StringUtils.isNotEmpty(fieldName)) { | |
ConstraintValidatorUtils.addConstraintViolation(context, errorMessage, fieldName); | |
} | |
return result; | |
} | |
private void validateParameters(ScriptAssertFieldError constraintAnnotation) { | |
Contracts.assertNotEmpty( constraintAnnotation.script(), MESSAGES.parameterMustNotBeEmpty( "script" ) ); | |
Contracts.assertNotEmpty( constraintAnnotation.lang(), MESSAGES.parameterMustNotBeEmpty( "lang" ) ); | |
Contracts.assertNotEmpty( constraintAnnotation.alias(), MESSAGES.parameterMustNotBeEmpty( "alias" ) ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment