package fr.acxio.tools.agia.expression; /* * Copyright 2014 Acxio * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.ParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** * <p> * Standard expression resolver. * </p> * <p> * This resolver uses the prefix "@{" and the suffix "}" by default. * </p> * <p> * It caches the expressions to prevent systematic recompilation of them. * </p> * <p> * If the result of the evaluation cannot be cast to the given class, an * exception is thrown. * </p> * * @author pcollardez * */ public class StandardDataExpressionResolver implements DataExpressionResolver { /** Default expression prefix: "@{" */ public static final String DEFAULT_EXPRESSION_PREFIX = "@{"; /** Default expression suffix: "}" */ public static final String DEFAULT_EXPRESSION_SUFFIX = "}"; private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX; private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX; private ExpressionParser expressionParser = new SpelExpressionParser(); private final Map<String, Expression> expressionCache = new ConcurrentHashMap<String, Expression>(); private final ParserContext expressionParserContext = new ParserContext() { public boolean isTemplate() { return true; } public String getExpressionPrefix() { return expressionPrefix; } public String getExpressionSuffix() { return expressionSuffix; } }; /** * Set the prefix that an expression string starts with. The default is * "@{". * * @see #DEFAULT_EXPRESSION_PREFIX */ public void setExpressionPrefix(String expressionPrefix) { Assert.hasText(expressionPrefix, "Expression prefix must not be empty"); this.expressionPrefix = expressionPrefix; } /** * Set the suffix that an expression string ends with. The default is "}". * * @see #DEFAULT_EXPRESSION_SUFFIX */ public void setExpressionSuffix(String expressionSuffix) { Assert.hasText(expressionSuffix, "Expression suffix must not be empty"); this.expressionSuffix = expressionSuffix; } /** * <p> * Specify the EL parser to use for expression parsing. * </p> * <p> * Default is a * {@link org.springframework.expression.spel.standard.SpelExpressionParser * SpelExpressionParser}, compatible with standard Unified EL style * expression syntax. * </p> */ public void setExpressionParser(ExpressionParser expressionParser) { Assert.notNull(expressionParser, "ExpressionParser must not be null"); this.expressionParser = expressionParser; } @Override public <T> T evaluate(String sExpression, EvaluationContext sEvalContext, Class<T> sTargetType) { if (!StringUtils.hasLength(sExpression)) { if (sTargetType == null || ClassUtils.isAssignableValue(sTargetType, sExpression)) { return (T) sExpression; } throw new EvaluationException("Cannot convert value '" + sExpression + "' to type '" + sTargetType.getName() + "'"); } try { Expression expr = this.expressionCache.get(sExpression); if (expr == null) { expr = this.expressionParser.parseExpression(sExpression, expressionParserContext); this.expressionCache.put(sExpression, expr); } return expr.getValue(sEvalContext, sTargetType); } catch (Exception ex) { throw new EvaluationException("Expression parsing failed", ex); } } }