001/* 002 * Copyright 2013 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.springframework.batch.core.jsr.configuration.support; 017 018import java.util.regex.Matcher; 019import java.util.regex.Pattern; 020import org.springframework.beans.factory.config.BeanExpressionContext; 021import org.springframework.beans.factory.config.BeanExpressionResolver; 022import org.springframework.util.StringUtils; 023 024/** 025 * <p> 026 * Support class for parsing JSR-352 expressions. The JSR-352 expression syntax, for 027 * example conditional/elvis statements need to be transformed a bit to be valid SPeL expressions. 028 * </p> 029 * 030 * @author Chris Schaefer 031 * @since 3.0 032 */ 033public class JsrExpressionParser { 034 private static final String QUOTE = "'"; 035 private static final String NULL = "null"; 036 private static final String ELVIS_RHS = ":"; 037 private static final String ELVIS_LHS = "\\?"; 038 private static final String ELVIS_OPERATOR = "?:"; 039 private static final String EXPRESSION_SUFFIX = "}"; 040 private static final String EXPRESSION_PREFIX = "#{"; 041 private static final String DEFAULT_VALUE_SEPARATOR = ";"; 042 private static final Pattern CONDITIONAL_EXPRESSION = Pattern.compile("(((\\bnull\\b)|(#\\{\\w))[^;]+)"); 043 044 private BeanExpressionContext beanExpressionContext; 045 private BeanExpressionResolver beanExpressionResolver; 046 047 /** 048 * <p> 049 * Creates a new instance of this expression parser without and expression resolver. Creating 050 * an instance via this constructor will still parse expressions but no resolution of operators 051 * will occur as its expected the caller will. 052 * </p> 053 */ 054 public JsrExpressionParser() { } 055 056 /** 057 * <p> 058 * Creates a new instances of this expression parser with the provided expression resolver and context to evaluate 059 * against. 060 * </p> 061 * 062 * @param beanExpressionResolver the expression resolver to use when resolving expressions 063 * @param beanExpressionContext the expression context to resolve expressions against 064 */ 065 public JsrExpressionParser(BeanExpressionResolver beanExpressionResolver, BeanExpressionContext beanExpressionContext) { 066 this.beanExpressionContext = beanExpressionContext; 067 this.beanExpressionResolver = beanExpressionResolver; 068 } 069 070 /** 071 * <p> 072 * Parses the provided expression, applying any transformations needed to evaluate as a SPeL expression. 073 * </p> 074 * 075 * @param expression the expression to parse and transform 076 * @return a JSR-352 transformed expression that can be evaluated by a SPeL parser 077 */ 078 public String parseExpression(String expression) { 079 String expressionToParse = expression; 080 081 if (StringUtils.countOccurrencesOf(expressionToParse, ELVIS_OPERATOR) > 0) { 082 expressionToParse = parseConditionalExpressions(expressionToParse); 083 } 084 085 return evaluateExpression(expressionToParse); 086 } 087 088 private String parseConditionalExpressions(String expression) { 089 String expressionToParse = expression; 090 091 Matcher conditionalExpressionMatcher = CONDITIONAL_EXPRESSION.matcher(expressionToParse); 092 093 while (conditionalExpressionMatcher.find()) { 094 String conditionalExpression = conditionalExpressionMatcher.group(1); 095 096 String value = conditionalExpression.split(ELVIS_LHS)[0]; 097 String defaultValue = conditionalExpression.split(ELVIS_RHS)[1]; 098 099 StringBuilder parsedExpression = new StringBuilder(); 100 101 if(beanExpressionResolver != null) { 102 parsedExpression.append(EXPRESSION_PREFIX) 103 .append(evaluateExpression(value)) 104 .append(ELVIS_OPERATOR) 105 .append(QUOTE) 106 .append(evaluateExpression(defaultValue)) 107 .append(QUOTE) 108 .append(EXPRESSION_SUFFIX); 109 } else { 110 if(NULL.equals(value)) { 111 parsedExpression.append(defaultValue); 112 } else { 113 parsedExpression.append(value); 114 } 115 } 116 117 expressionToParse = expressionToParse.replace(conditionalExpression, parsedExpression); 118 } 119 120 return expressionToParse.replace(DEFAULT_VALUE_SEPARATOR, ""); 121 } 122 123 private String evaluateExpression(String expression) { 124 if(beanExpressionResolver != null) { 125 return (String) beanExpressionResolver.evaluate(expression, beanExpressionContext); 126 } 127 128 return expression; 129 } 130}