/* * Copyright 2013 the original author or authors. * * 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. */ package org.springframework.batch.core.jsr.configuration.support; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.springframework.beans.factory.config.BeanExpressionContext; import org.springframework.beans.factory.config.BeanExpressionResolver; import org.springframework.util.StringUtils; /** * <p> * Support class for parsing JSR-352 expressions. The JSR-352 expression syntax, for * example conditional/elvis statements need to be transformed a bit to be valid SPeL expressions. * </p> * * @author Chris Schaefer * @since 3.0 */ public class JsrExpressionParser { private static final String QUOTE = "'"; private static final String NULL = "null"; private static final String ELVIS_RHS = ":"; private static final String ELVIS_LHS = "\\?"; private static final String ELVIS_OPERATOR = "?:"; private static final String EXPRESSION_SUFFIX = "}"; private static final String EXPRESSION_PREFIX = "#{"; private static final String DEFAULT_VALUE_SEPARATOR = ";"; private static final Pattern CONDITIONAL_EXPRESSION = Pattern.compile("(((\\bnull\\b)|(#\\{\\w))[^;]+)"); private BeanExpressionContext beanExpressionContext; private BeanExpressionResolver beanExpressionResolver; /** * <p> * Creates a new instance of this expression parser without and expression resolver. Creating * an instance via this constructor will still parse expressions but no resolution of operators * will occur as its expected the caller will. * </p> */ public JsrExpressionParser() { } /** * <p> * Creates a new instances of this expression parser with the provided expression resolver and context to evaluate * against. * </p> * * @param beanExpressionResolver the expression resolver to use when resolving expressions * @param beanExpressionContext the expression context to resolve expressions against */ public JsrExpressionParser(BeanExpressionResolver beanExpressionResolver, BeanExpressionContext beanExpressionContext) { this.beanExpressionContext = beanExpressionContext; this.beanExpressionResolver = beanExpressionResolver; } /** * <p> * Parses the provided expression, applying any transformations needed to evaluate as a SPeL expression. * </p> * * @param expression the expression to parse and transform * @return a JSR-352 transformed expression that can be evaluated by a SPeL parser */ public String parseExpression(String expression) { String expressionToParse = expression; if (StringUtils.countOccurrencesOf(expressionToParse, ELVIS_OPERATOR) > 0) { expressionToParse = parseConditionalExpressions(expressionToParse); } return evaluateExpression(expressionToParse); } private String parseConditionalExpressions(String expression) { String expressionToParse = expression; Matcher conditionalExpressionMatcher = CONDITIONAL_EXPRESSION.matcher(expressionToParse); while (conditionalExpressionMatcher.find()) { String conditionalExpression = conditionalExpressionMatcher.group(1); String value = conditionalExpression.split(ELVIS_LHS)[0]; String defaultValue = conditionalExpression.split(ELVIS_RHS)[1]; StringBuilder parsedExpression = new StringBuilder(); if(beanExpressionResolver != null) { parsedExpression.append(EXPRESSION_PREFIX) .append(evaluateExpression(value)) .append(ELVIS_OPERATOR) .append(QUOTE) .append(evaluateExpression(defaultValue)) .append(QUOTE) .append(EXPRESSION_SUFFIX); } else { if(NULL.equals(value)) { parsedExpression.append(defaultValue); } else { parsedExpression.append(value); } } expressionToParse = expressionToParse.replace(conditionalExpression, parsedExpression); } return expressionToParse.replace(DEFAULT_VALUE_SEPARATOR, ""); } private String evaluateExpression(String expression) { if(beanExpressionResolver != null) { return (String) beanExpressionResolver.evaluate(expression, beanExpressionContext); } return expression; } }