INT-3210: JDBC & JPA: Optimize SpEL Parsing

JIRA: https://jira.springsource.org/browse/INT-3210

* Parse `Expression` parameters only once at creation phase
* There is still tiny case, when configured parameters don't have
provided parameter, in this case an `input` determines as JavaBean and the
`name` will be populated as bean property via SpEL.

INT-3210: Add params to maps and collections

* If configured parameters don't contain provide param,
parse his expressions and add to parameters of current
`ParameterSource` and enclosing `ParameterSourceFactory`
* Move JPA `ExpressionEvaluatingParameterSource` to inner class
of `ExpressionEvaluatingParameterSourceFactory`, similar to `ExpressionEvaluatingSqlParameterSourceFactory`
This commit is contained in:
Artem Bilan
2013-11-19 17:34:53 +02:00
committed by Gary Russell
parent 5bb6e550aa
commit 6b50c49efe
5 changed files with 234 additions and 201 deletions

View File

@@ -21,7 +21,10 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionException;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.integration.util.AbstractExpressionEvaluator;
import org.springframework.jdbc.core.namedparam.AbstractSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
@@ -33,6 +36,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
* @author Dave Syer
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
* @since 2.0
*/
public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpressionEvaluator implements
@@ -40,15 +44,23 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
private final static Log logger = LogFactory.getLog(ExpressionEvaluatingSqlParameterSourceFactory.class);
private static final ExpressionParser PARSER = new SpelExpressionParser();
private static final Object ERROR = new Object();
private volatile Map<String, ?> staticParameters;
private volatile Map<String, String> parameterExpressions;
/**
* The {@link Map} of parameters with expressions.
* {@code key} - parameter name; {@code value} - array of two {@link Expression}s:
* first element - direct {@link Expression}, second - collection projection {@link Expression}.
* Used in case of root object of evaluation is {@link Collection}.
*/
private volatile Map<String, Expression[]> parameterExpressions;
public ExpressionEvaluatingSqlParameterSourceFactory() {
this.staticParameters = Collections.unmodifiableMap(new HashMap<String, Object>());
this.parameterExpressions = Collections.unmodifiableMap(new HashMap<String, String>());
this.parameterExpressions = new HashMap<String, Expression[]>();
}
/**
@@ -98,13 +110,21 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
* @param parameterExpressions the parameter expressions to set
*/
public void setParameterExpressions(Map<String, String> parameterExpressions) {
this.parameterExpressions = parameterExpressions;
Map<String, Expression[]> paramExpressions = new HashMap<String, Expression[]>(parameterExpressions.size());
for (Map.Entry<String, String> entry : parameterExpressions.entrySet()) {
String key = entry.getKey();
String expression = entry.getValue();
Expression[] expressions = new Expression[] {
PARSER.parseExpression(expression),
PARSER.parseExpression("#root.![" + expression + "]")
};
paramExpressions.put(key, expressions);
}
this.parameterExpressions = paramExpressions;
}
public SqlParameterSource createParameterSource(final Object input) {
SqlParameterSource toReturn = new ExpressionEvaluatingSqlParameterSource(input, staticParameters,
parameterExpressions);
return toReturn;
return new ExpressionEvaluatingSqlParameterSource(input, this.staticParameters, this.parameterExpressions);
}
@Override
@@ -119,10 +139,10 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
private volatile Map<String, Object> values = new HashMap<String, Object>();
private final Map<String, String> parameterExpressions;
private final Map<String, Expression[]> parameterExpressions;
private ExpressionEvaluatingSqlParameterSource(Object input, Map<String, ?> staticParameters,
Map<String, String> parameterExpressions) {
Map<String, Expression[]> parameterExpressions) {
this.input = input;
this.parameterExpressions = parameterExpressions;
this.values.putAll(staticParameters);
@@ -132,13 +152,25 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
if (values.containsKey(paramName)) {
return values.get(paramName);
}
String expression = paramName;
if (parameterExpressions.containsKey(expression)) {
expression = parameterExpressions.get(expression);
if (!parameterExpressions.containsKey(paramName)) {
Expression[] expressions = new Expression[] {
PARSER.parseExpression(paramName),
PARSER.parseExpression("#root.![" + paramName + "]")
};
ExpressionEvaluatingSqlParameterSourceFactory.this.parameterExpressions.put(paramName, expressions);
this.parameterExpressions.put(paramName, expressions);
}
Expression expression = null;
if (input instanceof Collection<?>) {
expression = "#root.![" + expression + "]";
expression = parameterExpressions.get(paramName)[1];
}
else {
expression = parameterExpressions.get(paramName)[0];
}
Object value = evaluateExpression(expression, input);
values.put(paramName, value);
if (logger.isDebugEnabled()) {