diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/Expression.java b/org.springframework.expression/src/main/java/org/springframework/expression/Expression.java index d92238bd61f..7f4f1fe54f8 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/Expression.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/Expression.java @@ -16,6 +16,8 @@ package org.springframework.expression; +import org.springframework.core.convert.TypeDescriptor; + /** * An expression capable of evaluating itself against context objects. Encapsulates the details of a previously parsed * expression string. Provides a common abstraction for expression evaluation independent of any language like OGNL or @@ -94,6 +96,26 @@ public interface Expression { */ public Class getValueType() throws EvaluationException; + /** + * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)} method for + * the given context. + * + * @param context the context in which to evaluate the expression + * @return a type descriptor for the most general type of value that can be set on this context + * @throws EvaluationException if there is a problem determining the type + */ + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException; + + /** + * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)} method using + * the default context. + * + * @return a type descriptor for the most general type of value that can be set on this context + * @throws EvaluationException if there is a problem determining the type + */ + public TypeDescriptor getValueTypeDescriptor() throws EvaluationException; + + /** * Returns the original string used to create this expression, unmodified. * diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java b/org.springframework.expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java index bda68e6feca..f78c8b13e9a 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java @@ -16,6 +16,7 @@ package org.springframework.expression.common; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; @@ -78,6 +79,14 @@ public class CompositeStringExpression implements Expression { return String.class; } + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) { + return TypeDescriptor.valueOf(String.class); + } + + public TypeDescriptor getValueTypeDescriptor() { + return TypeDescriptor.valueOf(String.class); + } + public void setValue(EvaluationContext context, Object value) throws EvaluationException { throw new EvaluationException(this.expressionString, "Cannot call setValue on a composite expression"); } diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/common/LiteralExpression.java b/org.springframework.expression/src/main/java/org/springframework/expression/common/LiteralExpression.java index 815b03fb96d..dda45b663df 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/common/LiteralExpression.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/common/LiteralExpression.java @@ -16,6 +16,7 @@ package org.springframework.expression.common; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; @@ -55,6 +56,14 @@ public class LiteralExpression implements Expression { return String.class; } + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) { + return TypeDescriptor.valueOf(String.class); + } + + public TypeDescriptor getValueTypeDescriptor() { + return TypeDescriptor.valueOf(String.class); + } + public void setValue(EvaluationContext context, Object value) throws EvaluationException { throw new EvaluationException(literalValue, "Cannot call setValue() on a LiteralExpression"); } diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelExpression.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelExpression.java index a668010d7e9..f4af8165504 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelExpression.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelExpression.java @@ -15,10 +15,12 @@ */ package org.springframework.expression.spel; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; import org.springframework.expression.common.ExpressionUtils; +import org.springframework.expression.spel.ast.SpelNodeImpl; import org.springframework.expression.spel.support.StandardEvaluationContext; /** @@ -33,13 +35,13 @@ public class SpelExpression implements Expression { private final String expression; - public final SpelNode ast; + public final SpelNodeImpl ast; /** * Construct an expression, only used by the parser. */ - public SpelExpression(String expression, SpelNode ast) { + public SpelExpression(String expression, SpelNodeImpl ast) { this.expression = expression; this.ast = ast; } @@ -119,19 +121,35 @@ public class SpelExpression implements Expression { * {@inheritDoc} */ public Class getValueType(EvaluationContext context) throws EvaluationException { - // TODO both getValueType() methods could use getValueInternal and return a type descriptor from the resultant TypedValue - Object value = getValue(context); - return (value != null ? value.getClass() : null); + ExpressionState eState = new ExpressionState(context); + TypeDescriptor typeDescriptor = this.ast.getValueInternal(eState).getTypeDescriptor(); + return typeDescriptor.getType(); } + /** + * {@inheritDoc} + */ + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException { + ExpressionState eState = new ExpressionState(context); + TypeDescriptor typeDescriptor = this.ast.getValueInternal(eState).getTypeDescriptor(); + return typeDescriptor; + } + /** * {@inheritDoc} */ public Class getValueType() throws EvaluationException { - Object value = getValue(); - return (value != null ? value.getClass() : null); + return this.ast.getValueInternal(new ExpressionState(new StandardEvaluationContext())).getTypeDescriptor().getType(); } + /** + * {@inheritDoc} + */ + public TypeDescriptor getValueTypeDescriptor() throws EvaluationException { + return this.ast.getValueInternal(new ExpressionState(new StandardEvaluationContext())).getTypeDescriptor(); + } + + /** * {@inheritDoc} */ diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java index 50893d28cfd..de1b9353e7e 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java @@ -24,7 +24,6 @@ import org.springframework.expression.ParserContext; import org.springframework.expression.common.TemplateAwareExpressionParser; import org.springframework.expression.spel.SpelExpression; import org.springframework.expression.spel.SpelMessages; -import org.springframework.expression.spel.SpelNode; import org.springframework.expression.spel.SpelParseException; import org.springframework.expression.spel.ast.Assign; import org.springframework.expression.spel.ast.BooleanLiteral; @@ -104,7 +103,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { tokenStreamLength = tokenStream.size(); tokenStreamPointer = 0; constructedNodes.clear(); - SpelNode ast = eatExpression(); + SpelNodeImpl ast = eatExpression(); if (moreTokens()) { throw new SpelParseException(peekToken().startpos,SpelMessages.MORE_INPUT,toString(nextToken())); }