Skip to content

Commit

Permalink
HV-1497 Extend the ConstraintValidator contract with a new initialize…
Browse files Browse the repository at this point in the history
…() method

Allows to pass an initialization context when initializing a constraint
validator.
Subsequent cleanups around script assert validators.
  • Loading branch information
marko-bekhta authored and gsmet committed Oct 31, 2017
1 parent d9ed413 commit ddb5219
Show file tree
Hide file tree
Showing 17 changed files with 306 additions and 127 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.constraintvalidation;

import java.lang.annotation.Annotation;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.metadata.ConstraintDescriptor;

import org.hibernate.validator.Incubating;

/**
* Hibernate Validator specific extension to the {@link ConstraintValidator} contract.
*
* @author Marko Bekhta
* @since 6.0.5
*/
@Incubating
public interface HibernateConstraintValidator<A extends Annotation, T> extends ConstraintValidator<A, T> {

/**
* Initializes the validator in preparation for {@link #isValid(Object, ConstraintValidatorContext)} calls.
* It is an alternative to {@link #initialize(Annotation)} method. Should be used if any additional information
* except annotation is needed to initialize a validator.
* Note, when using {@link HibernateConstraintValidator} user should only override one of the methods, either
* {@link #initialize(Annotation)} or {@link #initialize(ConstraintDescriptor, HibernateConstraintValidatorInitializationContext)}.
* It is guaranteed that in a case of the {@link HibernateConstraintValidator}, only the
* {@link #initialize(ConstraintDescriptor, HibernateConstraintValidatorInitializationContext)} will be called during initialization.
*
* @param constraintDescriptor a constraint descriptor for a given constraint declaration
* @param initializationContext an initialization context for a current {@link ConstraintValidatorFactory}
*/
default void initialize(ConstraintDescriptor<A> constraintDescriptor, HibernateConstraintValidatorInitializationContext initializationContext) {
initialize( constraintDescriptor.getAnnotation() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@

import javax.validation.ConstraintValidatorContext;

import org.hibernate.validator.Incubating;
import org.hibernate.validator.spi.scripting.ScriptEvaluator;
import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory;
import org.hibernate.validator.spi.scripting.ScriptEvaluatorNotFoundException;

/**
* A custom {@link ConstraintValidatorContext} which allows to set additional message parameters for
* interpolation.
Expand Down Expand Up @@ -112,19 +107,4 @@ public interface HibernateConstraintValidatorContext extends ConstraintValidator
*/
HibernateConstraintValidatorContext withDynamicPayload(Object payload);

/**
* Returns a {@link ScriptEvaluator} created based on the {@link ScriptEvaluatorFactory}
* passed at bootstrap.
*
* @param languageName the name of the scripting language
*
* @return a script executor for the given language. Never null.
*
* @throws ScriptEvaluatorNotFoundException in case no {@link ScriptEvaluator} was
* found for a given {@code languageName}
*
* @since 6.0.3
*/
@Incubating
ScriptEvaluator getScriptEvaluatorForLanguage(String languageName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.constraintvalidation;

import org.hibernate.validator.Incubating;
import org.hibernate.validator.spi.scripting.ScriptEvaluator;
import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory;
import org.hibernate.validator.spi.scripting.ScriptEvaluatorNotFoundException;

/**
* Provides contextual data and operations when initializing a constraint validator.
*
* @author Marko Bekhta
* @since 6.0.5
*/
@Incubating
public interface HibernateConstraintValidatorInitializationContext {

/**
* Returns a {@link ScriptEvaluator} created by the {@link ScriptEvaluatorFactory}
* passed at bootstrap.
*
* @param languageName the name of the scripting language
*
* @return a script executor for the given language. Never null.
*
* @throws ScriptEvaluatorNotFoundException in case no {@link ScriptEvaluator} was
* found for a given {@code languageName}
*/
ScriptEvaluator getScriptEvaluatorForLanguage(String languageName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandles;

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

import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidator;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorInitializationContext;
import org.hibernate.validator.internal.engine.messageinterpolation.util.InterpolationHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.spi.scripting.ScriptEvaluator;
Expand All @@ -21,33 +20,28 @@
/**
* @author Marko Bekhta
*/
public abstract class AbstractScriptAssertValidator<A extends Annotation, T> implements ConstraintValidator<A, T> {
public abstract class AbstractScriptAssertValidator<A extends Annotation, T> implements HibernateConstraintValidator<A, T> {

private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );

protected String languageName;
protected String script;
protected String escapedScript;
protected volatile ScriptAssertContext scriptAssertContext;
protected ScriptAssertContext scriptAssertContext;

protected void initialize(
String languageName, String script,
HibernateConstraintValidatorInitializationContext initializationContext) {
this.script = script;
this.languageName = languageName;
this.escapedScript = InterpolationHelper.escapeMessageParameter( script );

protected ScriptAssertContext getScriptAssertContext(ConstraintValidatorContext constraintValidatorContext) {
if ( scriptAssertContext == null ) {
synchronized ( this ) {
if ( scriptAssertContext == null ) {
ScriptEvaluator scriptEvaluator = null;
if ( constraintValidatorContext instanceof HibernateConstraintValidatorContext ) {
try {
scriptEvaluator = constraintValidatorContext.unwrap( HibernateConstraintValidatorContext.class )
.getScriptEvaluatorForLanguage( languageName );
}
catch (ScriptEvaluatorNotFoundException e) {
throw LOG.getCreationOfScriptExecutorFailedException( languageName, e );
}
}
scriptAssertContext = new ScriptAssertContext( script, scriptEvaluator );
}
}
try {
ScriptEvaluator scriptEvaluator = initializationContext.getScriptEvaluatorForLanguage( languageName );
scriptAssertContext = new ScriptAssertContext( script, scriptEvaluator );
}
catch (ScriptEvaluatorNotFoundException e) {
throw LOG.getCreationOfScriptExecutorFailedException( languageName, e );
}
return scriptAssertContext;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
import javax.validation.ConstraintValidatorContext;
import javax.validation.constraintvalidation.SupportedValidationTarget;
import javax.validation.constraintvalidation.ValidationTarget;
import javax.validation.metadata.ConstraintDescriptor;

import org.hibernate.validator.constraints.ParameterScriptAssert;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorInitializationContext;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.hibernate.validator.internal.engine.messageinterpolation.util.InterpolationHelper;
import org.hibernate.validator.internal.util.Contracts;

/**
Expand All @@ -33,11 +34,10 @@
public class ParameterScriptAssertValidator extends AbstractScriptAssertValidator<ParameterScriptAssert, Object[]> {

@Override
public void initialize(ParameterScriptAssert constraintAnnotation) {
public void initialize(ConstraintDescriptor<ParameterScriptAssert> constraintDescriptor, HibernateConstraintValidatorInitializationContext initializationContext) {
ParameterScriptAssert constraintAnnotation = constraintDescriptor.getAnnotation();
validateParameters( constraintAnnotation );
this.languageName = constraintAnnotation.lang();
this.script = constraintAnnotation.script();
this.escapedScript = InterpolationHelper.escapeMessageParameter( constraintAnnotation.script() );
initialize( constraintAnnotation.lang(), constraintAnnotation.script(), initializationContext );
}

@Override
Expand All @@ -51,7 +51,7 @@ public boolean isValid(Object[] arguments, ConstraintValidatorContext constraint

Map<String, Object> bindings = getBindings( arguments, parameterNames );

return getScriptAssertContext( constraintValidatorContext ).evaluateScriptAssertExpression( bindings );
return scriptAssertContext.evaluateScriptAssertExpression( bindings );
}

private Map<String, Object> getBindings(Object[] arguments, List<String> parameterNames) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;

import javax.validation.ConstraintValidatorContext;
import javax.validation.metadata.ConstraintDescriptor;

import org.hibernate.validator.constraints.ScriptAssert;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
import org.hibernate.validator.internal.engine.messageinterpolation.util.InterpolationHelper;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorInitializationContext;
import org.hibernate.validator.internal.util.Contracts;

/**
Expand All @@ -23,7 +24,6 @@
* @author Kevin Pollet &lt;kevin.pollet@serli.com&gt; (C) 2011 SERLI
* @author Marko Bekhta
* @author Guillaume Smet
* @author Marko Bekhta
*/
public class ScriptAssertValidator extends AbstractScriptAssertValidator<ScriptAssert, Object> {

Expand All @@ -32,15 +32,14 @@ public class ScriptAssertValidator extends AbstractScriptAssertValidator<ScriptA
private String message;

@Override
public void initialize(ScriptAssert constraintAnnotation) {
public void initialize(ConstraintDescriptor<ScriptAssert> constraintDescriptor, HibernateConstraintValidatorInitializationContext initializationContext) {
ScriptAssert constraintAnnotation = constraintDescriptor.getAnnotation();
validateParameters( constraintAnnotation );
initialize( constraintAnnotation.lang(), constraintAnnotation.script(), initializationContext );

this.alias = constraintAnnotation.alias();
this.reportOn = constraintAnnotation.reportOn();
this.message = constraintAnnotation.message();
this.languageName = constraintAnnotation.lang();
this.script = constraintAnnotation.script();
this.escapedScript = InterpolationHelper.escapeMessageParameter( constraintAnnotation.script() );
}

@Override
Expand All @@ -49,7 +48,7 @@ public boolean isValid(Object value, ConstraintValidatorContext constraintValida
constraintValidatorContext.unwrap( HibernateConstraintValidatorContext.class ).addMessageParameter( "script", escapedScript );
}

boolean validationResult = getScriptAssertContext( constraintValidatorContext ).evaluateScriptAssertExpression( value, alias );
boolean validationResult = scriptAssertContext.evaluateScriptAssertExpression( value, alias );

if ( !validationResult && !reportOn.isEmpty() ) {
constraintValidatorContext.disableDefaultConstraintViolation();
Expand Down
Loading

0 comments on commit ddb5219

Please sign in to comment.