Version 4

    This page is obsolete and is not maintained anymore.

     

    As of Hibernate Validator 4.2.x we are offering a MessageInterpolator which is able to interpolate the validated value. The interpolator officially included in the distribution is ValueFormatterMessageInterpolator. You can interpolate the validated value by including ${validatedValue} into the message template. Using the ValueFormatterMessageInterpolator you can also format the value by using the formatter syntax offered by String.format, eg ${validatedValue:%1$ty}.

     

    While developing ValueFormatterMessageInterpolator we also tried an additional approach using the Java Scripting API (JSR 223) to allow the formatting of the validated value. This approach is currently not part of the distribution, but we thought we post it here as another example of a custom message interpolator:

     

    package org.hibernate.validator.messageinterpolation;
    
    import java.util.IllegalFormatException;
    import java.util.Locale;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import javax.validation.MessageInterpolator;
    import javax.validation.ValidationException;
     
    import javax.script.ScriptException;
     
    import org.hibernate.validator.util.scriptengine.ScriptEvaluator;
    import org.hibernate.validator.util.scriptengine.ScriptEvaluatorFactory;
     
    /**
     * A message interpolator which can interpolate the validated value and format this value using the Java Scripting
     * API as defined by JSR 223
     * ("Scripting for the Java

    TM

     Platform"). Therefore an
     * implementation of that API must part of the class path. This is automatically
     * the case when running on Java 6. For older Java versions, the JSR 223 RI can
     * be added manually to the class path.
     *
     *  If no formatting script is specified {@code String.valueOf(validatedValue)} is called.
     * 
    
     *
     * To interpolate the validated Value add {@code ${validatedValue}} into the message template. To specify
     * a format script use {@code ${validatedValue:[script]}}, eg {@code ${validatedValue:_.toString()}}.
     * The {@code _} is used to reference the validated value.
     *
     * @author Kevin Pollet - SERLI - (kevin.pollet@serli.com)
     */
    public class ValueScriptingMessageInterpolator implements MessageInterpolator {
        public static final String VALIDATED_VALUE_KEYWORD = "validatedValue";
        public static final String VALIDATED_VALUE_FORMAT_SEPARATOR = ":";
    
        private static final Pattern VALIDATED_VALUE_START_PATTERN = Pattern.compile( "\\$\\{" + VALIDATED_VALUE_KEYWORD );
        private final MessageInterpolator delegate;
        private final Locale defaultLocale;
    
        public ValueScriptingMessageInterpolator() {
            this( null );
        }
    
        public ValueScriptingMessageInterpolator(MessageInterpolator userMessageInterpolator) {
            defaultLocale = Locale.getDefault();
            if ( userMessageInterpolator == null ) {
                this.delegate = new ResourceBundleMessageInterpolator();
            }
            else {
                this.delegate = userMessageInterpolator;
            }
        }
    
        public String interpolate(String message, Context context) {
            return interpolate( message, context, defaultLocale );
        }
    
        public String interpolate(String message, Context context, Locale locale) {
            String tmp = delegate.interpolate( message, context, locale );
            return interpolateMessage( tmp, context.getValidatedValue(), locale );
        }
    
        /**
         * Interpolate the validated value in the given message.
         *
         * @param message the message where validated value have to be interpolated
         * @param validatedValue the value of the object being validated
         * @param locale the {@code Locale} to use for message interpolation
         *
         * @return the interpolated message
         */
        private String interpolateMessage(String message, Object validatedValue, Locale locale) {
            String interpolatedMessage = message;
            Matcher matcher = VALIDATED_VALUE_START_PATTERN.matcher( message );
    
            while ( matcher.find() ) {
                int nbOpenCurlyBrace = 1;
                boolean isDoubleQuoteBloc = false;
                boolean isSimpleQuoteBloc = false;
                int lastIndex = matcher.end();
    
                do {
                    char current = message.charAt( lastIndex );
    
                    if ( current == '\'' ) {
                        if ( !isDoubleQuoteBloc && !isEscaped( message, lastIndex ) ) {
                            isSimpleQuoteBloc = !isSimpleQuoteBloc;
                        }
                    }
                    else if ( current == '"' ) {
                        if ( !isSimpleQuoteBloc && !isEscaped( message, lastIndex ) ) {
                            isDoubleQuoteBloc = !isDoubleQuoteBloc;
                        }
                    }
                    else if ( !isDoubleQuoteBloc && !isSimpleQuoteBloc ) {
                        if ( current == '{' ) {
                            nbOpenCurlyBrace++;
                        }
                        else if ( current == '}' ) {
                            nbOpenCurlyBrace--;
                        }
                    }
    
                    lastIndex++;
    
                } while ( nbOpenCurlyBrace > 0 && lastIndex < message.length() );
    
                // The validated value expression seems correct
                if ( nbOpenCurlyBrace == 0 ) {
                    String expression = message.substring( matcher.start(), lastIndex );
                    String expressionValue = interpolateValidatedValue( expression, validatedValue, locale );
                    interpolatedMessage = interpolatedMessage.replaceFirst(
                            Pattern.quote( expression ), Matcher.quoteReplacement( expressionValue )
                    );
                }
            }
    
            return interpolatedMessage;
        }
    
        /**
         * Returns if the character at the given index in the String
         * is an escaped character (preceded by a backslash character).
         *
         * @param enclosingString the string which contain the given character
         * @param charIndex the index of the character
         *
         * @return true if the given character is escaped false otherwise
         */
        private boolean isEscaped(String enclosingString, int charIndex) {
            if ( charIndex < 0 || charIndex > enclosingString.length() ) {
                throw new IndexOutOfBoundsException( "The given index must be between 0 and enclosingString.length() - 1" );
            }
            return charIndex > 0 && enclosingString.charAt( charIndex - 1 ) == '\\';
        }
    
        private String interpolateValidatedValue(String expression, Object validatedValue, Locale locale) {
            String interpolatedValue;
            int separatorIndex = expression.indexOf( VALIDATED_VALUE_FORMAT_SEPARATOR );
     
            if ( separatorIndex == -1 ) { //Use validated object toString method
                interpolatedValue = String.valueOf( validatedValue );
            }
            else { //Use evaluation of toString script
                String toStringScript = expression.substring( separatorIndex + 1, expression.length() - 1 );
                interpolatedValue = doToStringScriptEval( toStringScript, validatedValue, scriptLang );
            }
     
            return interpolatedValue;
        }
     
        /**
         * Evaluate the toString script with JSR 223 and returns
         * the String representation of the result.
         *
         * @param script the script to be evaluated
         * @param validatedValue the value of the object being validated
         * @param scriptLang the script language
         *
         * @return the string result of the script evaluation
         *
         * @throws ValidationException If no JSR-223 engine exists for the given script language
         * or if any errors occur during the script execution
         */
        private String doToStringScriptEval(String script, Object validatedValue, String scriptLang) {
            Object evaluationResult;
            ScriptEvaluator scriptEvaluator;
     
            try {
                ScriptEvaluatorFactory scriptEvaluatorFactory = ScriptEvaluatorFactory.getInstance();
                scriptEvaluator = scriptEvaluatorFactory.getScriptEvaluatorByLanguageName( scriptLang );
            }
            catch ( ScriptException e ) {
                throw new ValidationException( e );
            }
     
            try {
                evaluationResult = scriptEvaluator.evaluate( script, validatedValue, VALIDATED_VALUE_ALIAS );
            }
            catch ( ScriptException e ) {
                throw new ValidationException( "Error during execution of script \"" + script + "\" occured.", e );
            }
     
            if ( evaluationResult == null ) {
                throw new ValidationException( "Script \"" + script + "\" returned null, but must return a string representation of the object being validated." );
            }
     
            if ( !( evaluationResult instanceof String ) ) {
                throw new ValidationException(
                        "Script \"" + script + "\" returned a result of type " + evaluationResult.getClass()
                                .getCanonicalName() + " but must return a string representation of the object being validated."
                );
            }
     
            return String.valueOf( evaluationResult );
        }
    }

     

    Also have a look at "How to interpolate messages using the client Locale"