/*
* Copyright 2004-2014 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.binding.expression.spel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.convert.service.DefaultConversionService;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.ExpressionVariable;
import org.springframework.binding.expression.ParserContext;
import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.support.NullParserContext;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.Assert;
/**
* Adapt the Spring EL {@link SpelExpressionParser} to the Spring Binding
* {@link ExpressionParser} contract.
*
* @author Rossen Stoyanchev
* @since 2.1.0
*/
public class SpringELExpressionParser implements ExpressionParser {
private final SpelExpressionParser expressionParser;
private final ConversionService conversionService;
private final List<PropertyAccessor> propertyAccessors = new ArrayList<PropertyAccessor>();
public SpringELExpressionParser(SpelExpressionParser expressionParser) {
this(expressionParser, new DefaultConversionService());
}
public SpringELExpressionParser(SpelExpressionParser expressionParser, ConversionService conversionService) {
this.expressionParser = expressionParser;
this.propertyAccessors.add(new MapAccessor());
this.conversionService = conversionService;
}
public ConversionService getConversionService() {
return conversionService;
}
public void addPropertyAccessor(PropertyAccessor propertyAccessor) {
propertyAccessors.add(propertyAccessor);
}
public Expression parseExpression(String expression, ParserContext context) throws ParserException {
Assert.hasText(expression, "The expression string to parse is required and must not be empty");
context = (context == null) ? NullParserContext.INSTANCE : context;
Map<String, Expression> expressionVars = parseSpelExpressionVariables(context.getExpressionVariables());
org.springframework.expression.Expression spelExpression = parseSpelExpression(expression, context);
Class<?> expectedResultType = context.getExpectedEvaluationResultType();
org.springframework.core.convert.ConversionService cs = conversionService.getDelegateConversionService();
return createSpringELExpression(expressionVars, spelExpression, expectedResultType, cs);
}
/**
* Create the {@link SpringELExpression}.
*/
protected SpringELExpression createSpringELExpression(Map<String, Expression> expressionVars,
org.springframework.expression.Expression spelExpression, Class<?> expectedResultType,
org.springframework.core.convert.ConversionService conversionService) {
return new SpringELExpression(spelExpression, expressionVars,
expectedResultType, conversionService, propertyAccessors);
}
private org.springframework.expression.Expression parseSpelExpression(String expression, ParserContext context) {
return expressionParser.parseExpression(expression, getSpelParserContext(context));
}
private org.springframework.expression.ParserContext getSpelParserContext(ParserContext context) {
return context.isTemplate() ? org.springframework.expression.ParserContext.TEMPLATE_EXPRESSION : null;
}
/**
* Turn {@link ExpressionVariable}'s (pairs of variable names and string expressions)
* into a map of variable names and parsed Spring EL expressions. The map will be saved
* in a Spring EL {@link EvaluationContext} for later use at evaluation time.
*
* @param expressionVars an array of ExpressionVariable instances.
* @return a Map or null if the input array is empty.
*/
private Map<String, Expression> parseSpelExpressionVariables(ExpressionVariable[] expressionVars) {
if (expressionVars == null || expressionVars.length == 0) {
return null;
}
Map<String, Expression> result = new HashMap<String, Expression>(expressionVars.length);
for (ExpressionVariable var : expressionVars) {
result.put(var.getName(), parseExpression(var.getValueExpression(), var.getParserContext()));
}
return result;
}
}