Hand written SpEL parser. Removed antlr dependency. tests upgraded to JUnit4 - 93% coverage.

This commit is contained in:
Andy Clement 2009-05-27 04:20:18 +00:00
parent e5b553c16a
commit 886739f1d8
105 changed files with 3629 additions and 8643 deletions

View File

@ -7,7 +7,6 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.5.0/com.springsource.org.junit-4.5.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.junit/3.8.2/com.springsource.junit-sources-3.8.2.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.5.0/com.springsource.org.junit-4.5.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.junit/3.8.2/com.springsource.junit-sources-3.8.2.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.antlr/com.springsource.org.antlr/3.0.1/com.springsource.org.antlr-3.0.1.jar" sourcepath="/IVY_CACHE/org.antlr/com.springsource.org.antlr/3.0.1/com.springsource.org.antlr-sources-3.0.1.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/> <classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="output" path="target/classes"/>
</classpath> </classpath>

View File

@ -22,7 +22,6 @@
<!-- compile dependencies --> <!-- compile dependencies -->
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile->runtime" /> <dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile->runtime" />
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->runtime" /> <dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->runtime" />
<dependency org="org.antlr" name="com.springsource.org.antlr" rev="3.0.1" conf="compile->runtime"/>
<!-- test dependencies --> <!-- test dependencies -->
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="test->runtime"/> <dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="test->runtime"/>
<dependency org="org.junit" name="com.springsource.org.junit" rev="4.5.0" conf="test->runtime"/> <dependency org="org.junit" name="com.springsource.org.junit" rev="4.5.0" conf="test->runtime"/>

View File

@ -17,66 +17,51 @@
package org.springframework.expression; package org.springframework.expression;
/** /**
* Base class for exceptions occurring during expression parsing and evaluation. * Represent an exception that occurs during expression evaluation.
* *
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class EvaluationException extends Exception { public class EvaluationException extends ExpressionException {
private String expressionString;
/** /**
* Creates a new expression exception. * Creates a new expression evaluation exception.
* @param cause the underlying cause of this exception * @param position the position in the expression where the problem occurred
* @param message description of the problem that occurred
*/ */
public EvaluationException(Throwable cause) { public EvaluationException(int position, String message) {
super(cause); super(position, message);
} }
/** /**
* Creates a new expression parsing exception. * Creates a new expression evaluation exception.
* @param expressionString the expression string that could not be parsed * @param expressionString the expression that could not be evaluated
* @param cause the underlying cause of this exception * @param message description of the problem that occurred
*/
public EvaluationException(String expressionString, Throwable cause) {
this(expressionString, "Exception occurred whilst handling '" + expressionString + "'", cause);
}
/**
* Creates a new expression exception.
* @param expressionString the expression string
* @param message a descriptive message
* @param cause the underlying cause of this exception
*/
public EvaluationException(String expressionString, String message, Throwable cause) {
super(message, cause);
this.expressionString = expressionString;
}
/**
* Creates a new expression exception.
* @param expressionString the expression string
* @param message a descriptive message
*/ */
public EvaluationException(String expressionString, String message) { public EvaluationException(String expressionString, String message) {
super(message); super(expressionString, message);
this.expressionString = expressionString;
} }
/** /**
* Creates a new expression exception. The expressionString field should be set by a later call to * Creates a new expression evaluation exception.
* setExpressionString(). * @param position the position in the expression where the problem occurred
* @param message a descriptive message * @param message description of the problem that occurred
* @param cause the underlying cause of this exception
*/
public EvaluationException(int position, String message, Throwable cause) {
super(position, message, cause);
}
/**
* Creates a new expression evaluation exception.
* @param message description of the problem that occurred
*/ */
public EvaluationException(String message) { public EvaluationException(String message) {
super(message); super(message);
} }
public EvaluationException(String message, Throwable cause) {
public final String getExpressionString() { super(message,cause);
return this.expressionString;
} }
} }

View File

@ -0,0 +1,111 @@
/*
* Copyright 2002-2009 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.expression;
/**
* Super class for exceptions that can occur whilst processing expressions
*
* @author Andy Clement
* @since 3.0
*/
public class ExpressionException extends Exception {
protected String expressionString;
protected int position; // -1 if not known - but should be known in all reasonable cases
/**
* Creates a new expression exception.
* @param expressionString the expression string
* @param message a descriptive message
*/
public ExpressionException(String expressionString, String message) {
super(message);
this.position = -1;
this.expressionString = expressionString;
}
/**
* Creates a new expression exception.
* @param expressionString the expression string
* @param position the position in the expression string where the problem occurred
* @param message a descriptive message
*/
public ExpressionException(String expressionString, int position, String message) {
super(message);
this.position = position;
this.expressionString = expressionString;
}
/**
* Creates a new expression exception.
* @param position the position in the expression string where the problem occurred
* @param message a descriptive message
*/
public ExpressionException(int position, String message) {
super(message);
this.position = position;
}
/**
* Creates a new expression exception.
* @param position the position in the expression string where the problem occurred
* @param message a descriptive message
* @param cause the underlying cause of this exception
*/
public ExpressionException(int position, String message, Throwable cause) {
super(message,cause);
this.position = position;
}
/**
* Creates a new expression exception.
* @param message a descriptive message
*/
public ExpressionException(String message) {
super(message);
}
public ExpressionException(String message, Throwable cause) {
super(message,cause);
}
public String toDetailedString() {
StringBuilder output = new StringBuilder();
if (expressionString!=null) {
output.append("Expression '");
output.append(expressionString);
output.append("'");
if (position!=-1) {
output.append(" @ ");
output.append(position);
}
output.append(": ");
}
output.append(getMessage());
return output.toString();
}
public final String getExpressionString() {
return this.expressionString;
}
public final int getPosition() {
return position;
}
}

View File

@ -25,9 +25,6 @@ package org.springframework.expression;
*/ */
public interface OperatorOverloader { public interface OperatorOverloader {
// TODO does type OperatorOverloader need a better name?
// TODO Operator overloading needs some testing!
/** /**
* Return true if the operator overloader supports the specified operation * Return true if the operator overloader supports the specified operation
* between the two operands and so should be invoked to handle it. * between the two operands and so should be invoked to handle it.

View File

@ -17,57 +17,40 @@
package org.springframework.expression; package org.springframework.expression;
/** /**
* Base class for exceptions occurring during expression parsing and evaluation. * Represent an exception that occurs during expression parsing.
* *
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class ParseException extends Exception { public class ParseException extends ExpressionException {
private String expressionString;
/**
* Creates a new expression exception.
* @param cause the underlying cause of this exception
*/
public ParseException(Throwable cause) {
super(cause);
}
/** /**
* Creates a new expression parsing exception. * Creates a new expression parsing exception.
* @param expressionString the expression string that could not be parsed * @param expressionString the expression string that could not be parsed
* @param cause the underlying cause of this exception * @param position the position in the expression string where the problem occurred
* @param message description of the problem that occurred
*/ */
public ParseException(String expressionString, Throwable cause) { public ParseException(String expressionString, int position, String message) {
this(expressionString, "Exception occurred whilst handling '" + expressionString + "'", cause); super(expressionString, position, message);
} }
/** /**
* Creates a new expression exception. * Creates a new expression parsing exception.
* @param expressionString the expression string * @param position the position in the expression string where the problem occurred
* @param message a descriptive message * @param message description of the problem that occurred
* @param cause the underlying cause of this exception * @param cause the underlying cause of this exception
*/ */
public ParseException(String expressionString, String message, Throwable cause) { public ParseException(int position, String message, Throwable cause) {
super(message, cause);
this.expressionString = expressionString;
}
/**
* Creates a new expression exception.
* @param expressionString the expression string
* @param message a descriptive message
*/
public ParseException(String expressionString, String message) {
super(message); super(message);
this.expressionString = expressionString;
} }
/**
public final String getExpressionString() { * Creates a new expression parsing exception.
return this.expressionString; * @param position the position in the expression string where the problem occurred
* @param message description of the problem that occurred
*/
public ParseException(int position, String message) {
super(message);
} }
} }

View File

@ -158,7 +158,7 @@ public class ExpressionState {
else { else {
String leftType = (left==null?"null":left.getClass().getName()); String leftType = (left==null?"null":left.getClass().getName());
String rightType = (right==null?"null":right.getClass().getName()); String rightType = (right==null?"null":right.getClass().getName());
throw new SpelException(SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES, op, leftType, rightType); throw new SpelEvaluationException(SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES, op, leftType, rightType);
} }
} }
@ -170,7 +170,6 @@ public class ExpressionState {
return this.relatedContext; return this.relatedContext;
} }
/** /**
* A new scope is entered when a function is called and it is used to hold the parameters to the function call. If the names * A new scope is entered when a function is called and it is used to hold the parameters to the function call. If the names
* of the parameters clash with those in a higher level scope, those in the higher level scope will not be accessible whilst * of the parameters clash with those in a higher level scope, those in the higher level scope will not be accessible whilst

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2008 the original author or authors. * Copyright 2004-2009 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,41 +25,32 @@ import org.springframework.expression.EvaluationException;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class SpelException extends EvaluationException { public class SpelEvaluationException extends EvaluationException {
private SpelMessages message; private SpelMessages message;
private int position = -1;
private Object[] inserts; private Object[] inserts;
public SpelException(int position, Throwable cause, SpelMessages message, Object... inserts) { public SpelEvaluationException(SpelMessages message, Object... inserts) {
super(cause); super(message.formatMessage(0, inserts)); // TODO poor position information, can the callers not really supply something?
this.position = position;
this.message = message; this.message = message;
this.inserts = inserts; this.inserts = inserts;
} }
public SpelException(Throwable cause, SpelMessages message, Object... inserts) { public SpelEvaluationException(int position, SpelMessages message, Object... inserts) {
super(cause); super(position, message.formatMessage(position, inserts));
this.message = message; this.message = message;
this.inserts = inserts; this.inserts = inserts;
} }
public SpelException(int position, SpelMessages message, Object... inserts) { public SpelEvaluationException(int position, Throwable cause,
super((Throwable)null); SpelMessages message, Object... inserts) {
this.position = position; super(position,message.formatMessage(position,inserts),cause);
this.message = message; this.message = message;
this.inserts = inserts; this.inserts = inserts;
} }
public SpelException(SpelMessages message, Object... inserts) { public SpelEvaluationException(Throwable cause, SpelMessages message, Object... inserts) {
super((Throwable)null); super(message.formatMessage(0,inserts),cause);
this.message = message;
this.inserts = inserts;
}
public SpelException(String expressionString, int position, Throwable cause, SpelMessages message, Object... inserts) {
super(expressionString, cause);
this.position = position;
this.message = message; this.message = message;
this.inserts = inserts; this.inserts = inserts;
} }
@ -75,13 +66,6 @@ public class SpelException extends EvaluationException {
return super.getMessage(); return super.getMessage();
} }
/**
* @return the position within the expression that gave rise to the exception (or -1 if unknown)
*/
public int getPosition() {
return this.position;
}
/** /**
* @return the unformatted message * @return the unformatted message
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2008 the original author or authors. * Copyright 2002-2009 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,21 +15,17 @@
*/ */
package org.springframework.expression.spel; package org.springframework.expression.spel;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
/** /**
* Wrap a checked SpelException temporarily so that it can be passed through some infrastructure code
* (for example Antlr) before being unwrapped at the top level.
*
* @author Andy Clement * @author Andy Clement
* @since 3.0
*/ */
public class WrappedSpelException extends RuntimeException { public class SpelExpressionParserFactory {
public WrappedSpelException(SpelException e) { public static ExpressionParser getParser() {
super(e); return new SpelExpressionParser();
} }
@Override
public SpelException getCause() {
return (SpelException) super.getCause();
}
} }

View File

@ -36,69 +36,58 @@ import java.text.MessageFormat;
* @since 3.0 * @since 3.0
*/ */
public enum SpelMessages { public enum SpelMessages {
// TODO put keys and messages into bundles for easy NLS
// TODO review if any messages are not used
// TODO sort messages into better groups if possible, sharing a name prefix perhaps
TYPE_CONVERSION_ERROR(Kind.ERROR, 1001, "Type conversion problem, cannot convert from {0} to {1}"), // TYPE_CONVERSION_ERROR(Kind.ERROR, 1001, "Type conversion problem, cannot convert from {0} to {1}"), //
CONSTRUCTOR_NOT_FOUND(Kind.ERROR, 1002, "Constructor call: No suitable constructor found on type {0} for arguments {1}"), // CONSTRUCTOR_NOT_FOUND(Kind.ERROR, 1002, "Constructor call: No suitable constructor found on type {0} for arguments {1}"), //
METHOD_NOT_FOUND(Kind.ERROR, 1003, "Method call: Method {0} cannot be found on {1} type"), // CONSTRUCTOR_INVOCATION_PROBLEM(Kind.ERROR, 1003, "A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"), //
TYPE_NOT_FOUND(Kind.ERROR, 1004, "Type cannot be found ''{0}''"), // METHOD_NOT_FOUND(Kind.ERROR, 1004, "Method call: Method {0} cannot be found on {1} type"), //
VARIABLE_NOT_FOUND(Kind.ERROR, 1005, "Variable named ''{0}'' cannot be found"), // TYPE_NOT_FOUND(Kind.ERROR, 1005, "Type cannot be found ''{0}''"), //
LOCAL_VARIABLE_NOT_DEFINED(Kind.ERROR, 1006, "Local variable named ''{0}'' could not be found"), // FUNCTION_NOT_DEFINED(Kind.ERROR, 1006, "The function ''{0}'' could not be found"), //
FUNCTION_NOT_DEFINED(Kind.ERROR, 1007, "The function ''{0}'' could not be found"), // PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1007, "Field or property ''{0}'' cannot be found on null"), //
PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1008, "Field or property ''{0}'' cannot be found on null"), // PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1008, "Field or property ''{0}'' cannot be found on object of type ''{1}''"), //
PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1009, "Field or property ''{0}'' cannot be found on object of type ''{1}''"), // PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1009, "Field or property ''{0}'' cannot be set on null"), //
PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1010, "Field or property ''{0}'' cannot be set on null"), //
PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010, "Field or property ''{0}'' cannot be set on object of type ''{1}''"), // PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010, "Field or property ''{0}'' cannot be set on object of type ''{1}''"), //
METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1011, "Method call: Attempted to call method {0} on null context object"), // METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1011, "Method call: Attempted to call method {0} on null context object"), //
PROPERTY_OR_FIELD_ACCESS_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1012, "Field or property reference: Attempted to refer to field or property ''{0}'' on null context object"), // CANNOT_INDEX_INTO_NULL_VALUE(Kind.ERROR, 1012, "Cannot index into a null value"),
CANNOT_INDEX_INTO_NULL_VALUE(Kind.ERROR, 1013, "Cannot index into a null value"), NOT_COMPARABLE(Kind.ERROR, 1013, "Cannot compare instances of {0} and {1}"), //
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1014, "Incorrect number of arguments for function, {0} supplied but function takes {1}"), //
NOT_COMPARABLE(Kind.ERROR, 1014, "Cannot compare instances of {0} and {1}"), // INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1015, "Cannot perform selection on input data of type ''{0}''"), //
NOT_COMPARABLE_CANNOT_COERCE(Kind.ERROR, 1015, "Cannot compare instances of {0} and {1} because they cannot be coerced to the same type"), // RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1016, "Result of selection criteria is not boolean"), //
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1016, "Incorrect number of arguments for function, {0} supplied but function takes {1}"), // BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST(Kind.ERROR, 1017, "Right operand for the 'between' operator has to be a two-element list"), //
INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1017, "Cannot perform selection on input data of type ''{0}''"), // INVALID_PATTERN(Kind.ERROR, 1018, "Pattern is not valid ''{0}''"), //
RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1018, "Result of selection criteria is not boolean"), // PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1019, "Projection is not supported on the type ''{0}''"), //
NULL_OPERAND_TO_OPERATOR(Kind.ERROR, 1019, "Operand evaluated to null and that is not supported for this operator"), // ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1020, "The argument list of a lambda expression should never have getValue() called upon it"), //
BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST(Kind.ERROR, 1020, "Right operand for the 'between' operator has to be a two-element list"), // EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1021, "A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"), //
UNABLE_TO_ACCESS_FIELD(Kind.ERROR, 1021, "Unable to access field ''{0}'' on type ''{1}''"), // FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1022, "The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"), //
UNABLE_TO_ACCESS_PROPERTY_THROUGH_GETTER(Kind.ERROR, 1022, "Unable to access property ''{0}'' through getter on type ''{1}''"), // EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1023, "A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"), //
UNABLE_TO_ACCESS_PROPERTY_THROUGH_SETTER(Kind.ERROR, 1023, "Unable to access property ''{0}'' through setter on type ''{1}''"), // ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1024, "The array has ''{0}'' elements, index ''{1}'' is invalid"), //
INVALID_PATTERN(Kind.ERROR, 1024, "Pattern is not valid ''{0}''"), // COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1025, "The collection has ''{0}'' elements, index ''{1}'' is invalid"), //
RECOGNITION_ERROR(Kind.ERROR, 1025, "Recognition error: {0}"), // TODO poor message when a recognition exception occurs STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1026, "The string has ''{0}'' characters, index ''{1}'' is invalid"), //
PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1026, "Projection is not supported on the type ''{0}''"), // INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1027, "Indexing into type ''{0}'' is not supported"), //
ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1027, "The argument list of a lambda expression should never have getValue() called upon it"), // INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1028, "The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"), //
MAPENTRY_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1028, "A map entry should never have getValue() called upon it"), // EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1029, "A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"), //
EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1029, "A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"), // OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1030, "The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"), //
EXCEPTION_DURING_CONSTRUCTOR_INVOCATION(Kind.ERROR, 1030, "A problem occurred whilst attempting to construct ''{0}'': ''{1}''"), // PROBLEM_LOCATING_METHOD(Kind.ERROR, 1031, "Problem locating method {0} cannot on type {1}"),
DATE_CANNOT_BE_PARSED(Kind.ERROR, 1031, "Unable to parse date ''{0}'' using format ''{1}''"), // SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1032, "setValue(ExpressionState, Object) not supported for ''{0}''"), //
FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1032, "The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"), // MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1033, "Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"), //
EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1033, "A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"), // EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1034, "A problem occurred whilst attempting to set the property ''{0}'': {1}"), //
NOT_AN_INTEGER(Kind.ERROR, 1035, "The value ''{0}'' cannot be parsed as an int"), //
// indexing NOT_A_LONG(Kind.ERROR, 1036, "The value ''{0}'' cannot be parsed as a long"), //
ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1034, "The array has ''{0}'' elements, index ''{1}'' is invalid"), // INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1037, "First operand to matches operator must be a string. ''{0}'' is not"), //
COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1035, "The collection has ''{0}'' elements, index ''{1}'' is invalid"), // INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1038, "Second operand to matches operator must be a string. ''{0}'' is not"), //
STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1036, "The string has ''{0}'' characters, index ''{1}'' is invalid"), // FUNCTION_MUST_BE_STATIC(Kind.ERROR, 1039, "Only static methods can be called via function references. The method ''{0}'' referred to by name ''{1}'' is not static."),//
INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1037, "Indexing into type ''{0}'' is not supported"), // NOT_A_REAL(Kind.ERROR, 1040, "The value ''{0}'' cannot be parsed as a double"), //
MORE_INPUT(Kind.ERROR,1041, "After parsing a valid expression, there is still more data in the expression: ''{0}''"),
INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1038, "The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"), // RIGHT_OPERAND_PROBLEM(Kind.ERROR,1042, "Problem parsing right operand"),
EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1039, "A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"), // NOT_EXPECTED_TOKEN(Kind.ERROR,1043,"Unexpected token. Expected ''{0}'' but was ''{1}''"),
OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1040, "The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"), // OOD(Kind.ERROR,1044,"Unexpectedly ran out of input"), //
UNEXPECTED_PROBLEM_INVOKING_OPERATOR(Kind.ERROR, 1041, "Unexpected problem invoking operator ''{0}'' between objects of type ''{1}'' and ''{2}'': {3}"), // NON_TERMINATING_DOUBLE_QUOTED_STRING(Kind.ERROR,1045,"Cannot find terminating \" for string"),//
PROBLEM_LOCATING_METHOD(Kind.ERROR, 1042, "Problem locating method {0} cannot on type {1}"), NON_TERMINATING_QUOTED_STRING(Kind.ERROR,1046,"Cannot find terminating ' for string"), //
PROBLEM_LOCATING_CONSTRUCTOR(Kind.ERROR, 1043, "A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"), // MISSING_LEADING_ZERO_FOR_NUMBER(Kind.ERROR,1047,"A real number must be prefixed by zero, it cannot start with just ''.''"), //
SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1044, "setValue(ExpressionState, Object) not implemented for ''{0}'' (''{1}''"), // REAL_CANNOT_BE_LONG(Kind.ERROR,1048,"Real number cannot be suffixed with a long (L or l) suffix"),//
PROBLEM_DURING_TYPE_CONVERSION(Kind.ERROR, 1045, "Problem occurred during type conversion: {0}"), // UNEXPECTED_DATA_AFTER_DOT(Kind.ERROR,1049,"Unexpected data after ''.'': ''{0}''"),//
MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1046, "Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"), // MISSING_CONSTRUCTOR_ARGS(Kind.ERROR,1050,"The arguments '(...)' for the constructor call are missing"),//
EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1047, "A problem occurred whilst attempting to set the property ''{0}'': {1}"), // RUN_OUT_OF_ARGUMENTS(Kind.ERROR,1051,"Unexpected ran out of arguments"),//
NOT_AN_INTEGER(Kind.ERROR, 1048, "The value ''{0}'' cannot be parsed as an int"), //
NOT_A_LONG(Kind.ERROR, 1049, "The value ''{0}'' cannot be parsed as a long"), //
PARSE_PROBLEM(Kind.ERROR, 1050, "Error occurred during expression parse: {0}"), //
INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1051, "First operand to matches operator must be a string. ''{0}'' is not"), //
INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1052, "Second operand to matches operator must be a string. ''{0}'' is not"), //
FUNCTION_MUST_BE_STATIC(Kind.ERROR, 1053, "Only static methods can be called via function references. The method ''{0}'' referred to by name ''{1}'' is not static."),//
; ;
private Kind kind; private Kind kind;
@ -125,12 +114,12 @@ public enum SpelMessages {
StringBuilder formattedMessage = new StringBuilder(); StringBuilder formattedMessage = new StringBuilder();
formattedMessage.append("EL").append(code); formattedMessage.append("EL").append(code);
switch (kind) { switch (kind) {
case WARNING: // case WARNING:
formattedMessage.append("W"); // formattedMessage.append("W");
break; // break;
case INFO: // case INFO:
formattedMessage.append("I"); // formattedMessage.append("I");
break; // break;
case ERROR: case ERROR:
formattedMessage.append("E"); formattedMessage.append("E");
break; break;

View File

@ -79,4 +79,9 @@ public interface SpelNode {
*/ */
int getStartPosition(); int getStartPosition();
/**
* @return the end position of this Ast node in the expression string
*/
int getEndPosition();
} }

View File

@ -0,0 +1,107 @@
/*
* Copyright 2004-2009 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.expression.spel;
import org.springframework.expression.ParseException;
/**
* Root exception for Spring EL related exceptions. Rather than holding a hard coded string indicating the problem, it
* records a message key and the inserts for the message. See {@link SpelMessages} for the list of all possible messages
* that can occur.
*
* @author Andy Clement
* @since 3.0
*/
public class SpelParseException extends ParseException {
private SpelMessages message;
private Object[] inserts;
// public SpelParseException(String expressionString, int position, Throwable cause, SpelMessages message, Object... inserts) {
// super(expressionString, position, message.formatMessage(position,inserts), cause);
// this.message = message;
// this.inserts = inserts;
// }
public SpelParseException(String expressionString, int position, SpelMessages message, Object... inserts) {
super(expressionString, position, message.formatMessage(position,inserts));
this.position = position;
this.message = message;
this.inserts = inserts;
}
public SpelParseException(int position, SpelMessages message, Object... inserts) {
super(position, message.formatMessage(position,inserts));
this.position = position;
this.message = message;
this.inserts = inserts;
}
public SpelParseException(int position, Throwable cause, SpelMessages message, Object... inserts) {
super(position, message.formatMessage(position,inserts), cause);
this.position = position;
this.message = message;
this.inserts = inserts;
}
//
// public SpelException(Throwable cause, SpelMessages message, Object... inserts) {
// super(cause);
// this.message = message;
// this.inserts = inserts;
// }
//
// public SpelException(int position, SpelMessages message, Object... inserts) {
// super((Throwable)null);
// this.position = position;
// this.message = message;
// this.inserts = inserts;
// }
//
// public SpelException(SpelMessages message, Object... inserts) {
// super((Throwable)null);
// this.message = message;
// this.inserts = inserts;
// }
/**
* @return a formatted message with inserts applied
*/
@Override
public String getMessage() {
if (message != null)
return message.formatMessage(position, inserts);
else
return super.getMessage();
}
/**
* @return the unformatted message
*/
public SpelMessages getMessageUnformatted() {
return this.message;
}
/**
* @return the message inserts
*/
public Object[] getInserts() {
return inserts;
}
}

View File

@ -1,79 +0,0 @@
/*
* Copyright 2002-2009 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.expression.spel.antlr;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateAwareExpressionParser;
import org.springframework.expression.spel.SpelException;
import org.springframework.expression.spel.SpelExpression;
import org.springframework.expression.spel.SpelNode;
import org.springframework.expression.spel.WrappedSpelException;
import org.springframework.expression.spel.generated.SpringExpressionsLexer;
import org.springframework.expression.spel.generated.SpringExpressionsParser.expr_return;
/**
* Default {@link org.springframework.expression.ExpressionParser} implementation,
* wrapping an Antlr lexer and parser that implements standard Spring EL syntax.
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
public class SpelAntlrExpressionParser extends TemplateAwareExpressionParser {
private final SpringExpressionsLexer lexer;
private final SpringExpressionsParserExtender parser;
public SpelAntlrExpressionParser() {
this.lexer = new SpringExpressionsLexerExtender();
CommonTokenStream tokens = new CommonTokenStream(this.lexer);
this.parser = new SpringExpressionsParserExtender(tokens);
}
/**
* Parse an expression string.
* @param expressionString the expression to parse
* @param context the parser context in which to perform the parse
* @return a parsed expression object
* @throws ParseException if the expression is invalid
*/
protected Expression doParseExpression(String expressionString, ParserContext context) throws ParseException {
try {
this.lexer.setCharStream(new ANTLRStringStream(expressionString));
CommonTokenStream tokens = new CommonTokenStream(this.lexer);
this.parser.setTokenStream(tokens);
expr_return exprReturn = this.parser.expr();
return new SpelExpression(expressionString, (SpelNode) exprReturn.getTree());
} catch (RecognitionException re) {
throw new ParseException(expressionString,
"Recognition error at position: " + re.charPositionInLine + ": " + re.getMessage(), re);
} catch (WrappedSpelException ex) {
SpelException wrappedException = ex.getCause();
throw new ParseException(expressionString,
"Parsing problem: " + wrappedException.getMessage(), wrappedException);
}
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright 2002-2009 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.expression.spel.antlr;
import org.antlr.runtime.RecognitionException;
import org.springframework.expression.spel.SpelException;
import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.WrappedSpelException;
import org.springframework.expression.spel.generated.SpringExpressionsLexer;
/**
* @author Andy Clement
* @since 3.0
*/
class SpringExpressionsLexerExtender extends SpringExpressionsLexer {
/**
* recover() attempts to provide better error messages once something has gone wrong. It then throws a
* InternalELException (has to be this unchecked exception as the exception must flow through Antlr lexer methods
* that do not have declared exceptions). The InternalELException will be caught at the top level and altered to
* include context (line,column) information before being rethrown.<br>
*
* This error analysis code is in recover() rather than reportError() because reportError() isn't always called by
* the lexer and there is no way to add the calls to it by editing the .g file.
*/
@Override
public void recover(RecognitionException re) {
// TODO recovery needs an overhaul once the expression language syntax is agreed
// List<?> rules = getRuleInvocationStack(re, SpringExpressionsLexer.class.getName());
// String failedRule = (String) rules.get(rules.size() - 1);
// System.out.println("DBG: lexer rule " + failedRule);
// need a concrete example of error recovery in here please! then i can delete the below
// if (re instanceof NoViableAltException) {
// NoViableAltException nvae = (NoViableAltException) re;
// // example error data: { "abc": def }
// if (failedRule.equals("mTokens") && Character.isLetter((char) (nvae.getUnexpectedType()))) {
// logger.error(ParserMessage.ERROR_STRINGS_MUST_BE_QUOTED, re.line, re.charPositionInLine);
// }
//
// } else if (re instanceof MismatchedRangeException) {
// // MismatchedRangeException mre = (MismatchedRangeException) re;
// // example error data: [ 123e ]
// if (failedRule.equals("mDIGIT") && rules.size() > 3 && ((String) rules.get(rules.size() -
// 3)).equals("mExponent")) {
// logger.error(ParserMessage.ERROR_INVALID_EXPONENT, re.line, re.charPositionInLine);
// }
// } else if (re instanceof MismatchedTokenException) {
// MismatchedTokenException mte = (MismatchedTokenException) re;
// logger.error(ParserMessage.ERROR_MISMATCHED_CHARACTER, mte.charPositionInLine, mte.charPositionInLine,
// getCharErrorDisplay(mte.expecting), getCharErrorDisplay(mte.c));
// }
SpelException realException = new SpelException(re, SpelMessages.RECOGNITION_ERROR, re.toString());
throw new WrappedSpelException(realException);
}
@Override
public void reportError(RecognitionException re) {
// Do not report anything. If better messages could be reported they will have been reported
// by the recover() method above.
}
// private String getTokenForId(int id) {
// if (id == -1)
// return "EOF";
// return getTokenNames()[id];
// }
}

View File

@ -1,95 +0,0 @@
/*
* Copyright 2002-2009 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.expression.spel.antlr;
import org.antlr.runtime.BitSet;
import org.antlr.runtime.IntStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.Token;
import org.antlr.runtime.TokenStream;
import org.springframework.expression.spel.SpelException;
import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.WrappedSpelException;
import org.springframework.expression.spel.ast.SpelTreeAdaptor;
import org.springframework.expression.spel.generated.SpringExpressionsParser;
/**
* @author Andy Clement
* @since 3.0
*/
class SpringExpressionsParserExtender extends SpringExpressionsParser {
public SpringExpressionsParserExtender(TokenStream input) {
super(input);
setTreeAdaptor(new SpelTreeAdaptor());
}
/**
* Override super type implementation and just include the character position rather than the line number since the
* expressions are nearly all going to be just one line.
*/
@Override
public String getErrorHeader(RecognitionException e) {
StringBuilder retval = new StringBuilder();
retval.append("(pos ").append(e.charPositionInLine).append("): ");
return retval.toString();
}
@Override
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
String message = getErrorMessage(e, tokenNames);
// TODO would something like this be worthwhile to improve messages?
// if (message.equals("no viable alternative at input '<EOF>'") && !paraphrase.isEmpty()) {
// // This means we ran out of input building something, that something is named in paraphrase
// message = "no more input data to process whilst constructing " + paraphrase.peek();
// }
SpelException parsingProblem = new SpelException(e.charPositionInLine, e, SpelMessages.PARSE_PROBLEM, message);
throw new WrappedSpelException(parsingProblem);
}
/**
* Overridden purely because the base implementation does a System.err.println()
*/
@Override
public void recoverFromMismatchedToken(IntStream input, RecognitionException e, int ttype, BitSet follow)
throws RecognitionException {
// if next token is what we are looking for then "delete" this token
if (input.LA(2) == ttype) {
reportError(e);
/*
* System.err.println("recoverFromMismatchedToken deleting "+input.LT(1)+ " since "+input.LT(2)+" is what we
* want");
*/
beginResync();
input.consume(); // simply delete extra token
endResync();
input.consume(); // move past ttype token as if all were ok
return;
}
if (!recoverFromMismatchedElement(input, e, follow)) {
throw e;
}
}
@Override
public String getTokenErrorDisplay(Token t) {
if (t == null) {
return "<unknown>";
}
return super.getTokenErrorDisplay(t);
}
}

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
@ -31,13 +30,13 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class Assign extends SpelNodeImpl { public class Assign extends SpelNodeImpl {
public Assign(Token payload) { public Assign(int pos,SpelNodeImpl... operands) {
super(payload); super(pos,operands);
} }
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
TypedValue newValue = getChild(1).getValueInternal(state); TypedValue newValue = children[1].getValueInternal(state);
getChild(0).setValue(state, newValue.getValue()); getChild(0).setValue(state, newValue.getValue());
return newValue; return newValue;
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
/** /**
@ -29,8 +28,8 @@ public class BooleanLiteral extends Literal {
private final BooleanTypedValue value; private final BooleanTypedValue value;
public BooleanLiteral(Token payload, boolean value) { public BooleanLiteral(String payload, int pos, boolean value) {
super(payload); super(payload, pos);
this.value = BooleanTypedValue.forValue(value); this.value = BooleanTypedValue.forValue(value);
} }

View File

@ -22,17 +22,16 @@ import org.springframework.core.convert.TypeDescriptor;
* @since 3.0 * @since 3.0
*/ */
public interface CommonTypeDescriptors { public interface CommonTypeDescriptors {
// TODO push into TypeDescriptor? // need a better home for these - TypeDescriptor?
static TypeDescriptor BOOLEAN_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Boolean.class); static TypeDescriptor<Boolean> BOOLEAN_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Boolean.class);
static TypeDescriptor INTEGER_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Integer.class); static TypeDescriptor<Integer> INTEGER_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Integer.class);
static TypeDescriptor CHARACTER_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Character.class); static TypeDescriptor<Character> CHARACTER_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Character.class);
static TypeDescriptor LONG_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Long.class); static TypeDescriptor<Long> LONG_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Long.class);
static TypeDescriptor SHORT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Short.class); static TypeDescriptor<Short> SHORT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Short.class);
static TypeDescriptor BYTE_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Byte.class); static TypeDescriptor<Byte> BYTE_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Byte.class);
static TypeDescriptor FLOAT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Float.class); static TypeDescriptor<Float> FLOAT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Float.class);
static TypeDescriptor DOUBLE_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Double.class); static TypeDescriptor<Double> DOUBLE_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Double.class);
static TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class); static TypeDescriptor<String> STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
static TypeDescriptor CLASS_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Class.class); static TypeDescriptor<Class> CLASS_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Class.class);
static TypeDescriptor OBJECT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Object.class); static TypeDescriptor<Object> OBJECT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Object.class);
} }

View File

@ -16,11 +16,10 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
/** /**
* Represents a DOT separated expression sequence, such as 'property1.property2.methodOne()' * Represents a DOT separated expression sequence, such as 'property1.property2.methodOne()'
@ -30,9 +29,13 @@ import org.springframework.expression.spel.SpelException;
*/ */
public class CompoundExpression extends SpelNodeImpl { public class CompoundExpression extends SpelNodeImpl {
public CompoundExpression(Token payload) { public CompoundExpression(int pos,SpelNodeImpl... expressionComponents) {
super(payload); super(pos,expressionComponents);
if (expressionComponents.length<2) {
throw new IllegalStateException("Dont build compound expression less than one entry: "+expressionComponents.length);
} }
}
/** /**
* Evalutes a compound expression. This involves evaluating each piece in turn and the return value from each piece * Evalutes a compound expression. This involves evaluating each piece in turn and the return value from each piece
@ -45,20 +48,20 @@ public class CompoundExpression extends SpelNodeImpl {
TypedValue result = null; TypedValue result = null;
SpelNodeImpl nextNode = null; SpelNodeImpl nextNode = null;
try { try {
nextNode = getChild(0); nextNode = children[0];
result = nextNode.getValueInternal(state); result = nextNode.getValueInternal(state);
for (int i = 1; i < getChildCount(); i++) { for (int i = 1; i < getChildCount(); i++) {
try { try {
state.pushActiveContextObject(result); state.pushActiveContextObject(result);
nextNode = getChild(i); nextNode = children[i];
result = nextNode.getValueInternal(state); result = nextNode.getValueInternal(state);
} finally { } finally {
state.popActiveContextObject(); state.popActiveContextObject();
} }
} }
} catch (SpelException ee) { } catch (SpelEvaluationException ee) {
// Correct the position for the error before rethrowing // Correct the position for the error before rethrowing
ee.setPosition(nextNode.getCharPositionInLine()); ee.setPosition(nextNode.getStartPosition());
throw ee; throw ee;
} }
return result; return result;
@ -70,11 +73,11 @@ public class CompoundExpression extends SpelNodeImpl {
getChild(0).setValue(state, value); getChild(0).setValue(state, value);
return; return;
} }
TypedValue ctx = getChild(0).getValueInternal(state); TypedValue ctx = children[0].getValueInternal(state);
for (int i = 1; i < getChildCount() - 1; i++) { for (int i = 1; i < getChildCount() - 1; i++) {
try { try {
state.pushActiveContextObject(ctx); state.pushActiveContextObject(ctx);
ctx = getChild(i).getValueInternal(state); ctx = children[i].getValueInternal(state);
} finally { } finally {
state.popActiveContextObject(); state.popActiveContextObject();
} }
@ -92,11 +95,11 @@ public class CompoundExpression extends SpelNodeImpl {
if (getChildCount() == 1) { if (getChildCount() == 1) {
return getChild(0).isWritable(state); return getChild(0).isWritable(state);
} }
TypedValue ctx = getChild(0).getValueInternal(state); TypedValue ctx = children[0].getValueInternal(state);
for (int i = 1; i < getChildCount() - 1; i++) { for (int i = 1; i < getChildCount() - 1; i++) {
try { try {
state.pushActiveContextObject(ctx); state.pushActiveContextObject(ctx);
ctx = getChild(i).getValueInternal(state); ctx = children[i].getValueInternal(state);
} finally { } finally {
state.popActiveContextObject(); state.popActiveContextObject();
} }
@ -113,6 +116,7 @@ public class CompoundExpression extends SpelNodeImpl {
public String toStringAST() { public String toStringAST() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i = 0; i < getChildCount(); i++) { for (int i = 0; i < getChildCount(); i++) {
if (i>0) { sb.append("."); }
sb.append(getChild(i).toStringAST()); sb.append(getChild(i).toStringAST());
} }
return sb.toString(); return sb.toString();

View File

@ -18,7 +18,6 @@ package org.springframework.expression.spel.ast;
import java.util.List; import java.util.List;
import org.antlr.runtime.Token;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.ConstructorExecutor; import org.springframework.expression.ConstructorExecutor;
import org.springframework.expression.ConstructorResolver; import org.springframework.expression.ConstructorResolver;
@ -26,10 +25,11 @@ import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
// TODO asc array constructor call logic has been removed for now // TODO asc array constructor call logic has been removed for now
// TODO make this like the method referencing one
/** /**
* Represents the invocation of a constructor. Either a constructor on a regular type or construction of an array. When * Represents the invocation of a constructor. Either a constructor on a regular type or construction of an array. When
* an array is constructed, an initializer can be specified. * an array is constructed, an initializer can be specified.
@ -51,8 +51,13 @@ public class ConstructorReference extends SpelNodeImpl {
*/ */
private volatile ConstructorExecutor cachedExecutor; private volatile ConstructorExecutor cachedExecutor;
public ConstructorReference(Token payload) {
super(payload); /**
* Create a constructor reference. The first argument is the type, the rest are the parameters to the
* constructor call
*/
public ConstructorReference(int pos, SpelNodeImpl... arguments) {
super(pos,arguments);
} }
/** /**
@ -73,7 +78,7 @@ public class ConstructorReference extends SpelNodeImpl {
Object[] arguments = new Object[getChildCount() - 1]; Object[] arguments = new Object[getChildCount() - 1];
Class<?>[] argumentTypes = new Class[getChildCount() - 1]; Class<?>[] argumentTypes = new Class[getChildCount() - 1];
for (int i = 0; i < arguments.length; i++) { for (int i = 0; i < arguments.length; i++) {
TypedValue childValue = getChild(i + 1).getValueInternal(state); TypedValue childValue = children[i + 1].getValueInternal(state);
Object value = childValue.getValue(); Object value = childValue.getValue();
arguments[i] = value; arguments[i] = value;
argumentTypes[i] = (value==null?Object.class:value.getClass()); argumentTypes[i] = (value==null?Object.class:value.getClass());
@ -92,14 +97,16 @@ public class ConstructorReference extends SpelNodeImpl {
} }
// either there was no accessor or it no longer exists // either there was no accessor or it no longer exists
String typename = (String) getChild(0).getValueInternal(state).getValue(); String typename = (String) children[0].getValueInternal(state).getValue();
executorToUse = findExecutorForConstructor(typename, argumentTypes, state); executorToUse = findExecutorForConstructor(typename, argumentTypes, state);
try { try {
this.cachedExecutor = executorToUse; this.cachedExecutor = executorToUse;
TypedValue result = executorToUse.execute(state.getEvaluationContext(), arguments); TypedValue result = executorToUse.execute(state.getEvaluationContext(), arguments);
return result; return result;
} catch (AccessException ae) { } catch (AccessException ae) {
throw new SpelException(ae, SpelMessages.EXCEPTION_DURING_CONSTRUCTOR_INVOCATION, typename, ae.getMessage()); throw new SpelEvaluationException(getStartPosition(), ae, SpelMessages.CONSTRUCTOR_INVOCATION_PROBLEM, typename,
FormatHelper.formatMethodForMessage("", argumentTypes));
} }
} }
@ -110,10 +117,10 @@ public class ConstructorReference extends SpelNodeImpl {
* @param argumentTypes the types of the arguments supplied that the constructor must take * @param argumentTypes the types of the arguments supplied that the constructor must take
* @param state the current state of the expression * @param state the current state of the expression
* @return a reusable ConstructorExecutor that can be invoked to run the constructor or null * @return a reusable ConstructorExecutor that can be invoked to run the constructor or null
* @throws SpelException if there is a problem locating the constructor * @throws SpelEvaluationException if there is a problem locating the constructor
*/ */
private ConstructorExecutor findExecutorForConstructor( private ConstructorExecutor findExecutorForConstructor(
String typename, Class<?>[] argumentTypes, ExpressionState state) throws SpelException { String typename, Class<?>[] argumentTypes, ExpressionState state) throws SpelEvaluationException {
EvaluationContext eContext = state.getEvaluationContext(); EvaluationContext eContext = state.getEvaluationContext();
List<ConstructorResolver> cResolvers = eContext.getConstructorResolvers(); List<ConstructorResolver> cResolvers = eContext.getConstructorResolvers();
@ -125,14 +132,13 @@ public class ConstructorReference extends SpelNodeImpl {
if (cEx != null) { if (cEx != null) {
return cEx; return cEx;
} }
} } catch (AccessException ex) {
catch (AccessException ex) { throw new SpelEvaluationException(getStartPosition(),ex, SpelMessages.CONSTRUCTOR_INVOCATION_PROBLEM, typename,
throw new SpelException(ex, SpelMessages.PROBLEM_LOCATING_CONSTRUCTOR, typename,
FormatHelper.formatMethodForMessage("", argumentTypes)); FormatHelper.formatMethodForMessage("", argumentTypes));
} }
} }
} }
throw new SpelException(SpelMessages.CONSTRUCTOR_NOT_FOUND, typename, FormatHelper.formatMethodForMessage("", throw new SpelEvaluationException(getStartPosition(),SpelMessages.CONSTRUCTOR_NOT_FOUND, typename, FormatHelper.formatMethodForMessage("",
argumentTypes)); argumentTypes));
} }

View File

@ -16,33 +16,42 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException;
/** /**
* This is used for preserving positional information from the input expression. * Represents the elvis operator ?:. For an expression "a?:b" if a is not null, the value of the expression
* is "a", if a is null then the value of the expression is "b".
* *
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class Dot extends SpelNodeImpl { public class Elvis extends SpelNodeImpl {
// TODO Keep Dot for the positional information or remove it?
public Dot(Token payload) { public Elvis(int pos, SpelNodeImpl... args) {
super(payload); super(pos,args);
}
/**
* Evaluate the condition and if not null, return it. If it is null return the other value.
* @param state the expression state
* @throws EvaluationException if the condition does not evaluate correctly to a boolean or there is a problem
* executing the chosen alternative
*/
@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
TypedValue value = children[0].getValueInternal(state);
if (value.getValue()!=null) {
return value;
} else {
return children[1].getValueInternal(state);
}
} }
@Override @Override
public String toStringAST() { public String toStringAST() {
return "."; return new StringBuilder().append(getChild(0).toStringAST()).append(" ?: ").append(getChild(1).toStringAST()).toString();
}
@Override
public TypedValue getValueInternal(ExpressionState state) throws SpelException {
// This makes Dot a do-nothing operation, but this is not free in terms of computation
return state.getActiveContextObject();
} }
} }

View File

@ -20,14 +20,13 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import org.antlr.runtime.Token;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeConverter; import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.support.ReflectionHelper; import org.springframework.expression.spel.support.ReflectionHelper;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
@ -48,26 +47,28 @@ public class FunctionReference extends SpelNodeImpl {
private final String name; private final String name;
public FunctionReference(String functionName, int pos, SpelNodeImpl... arguments) {
public FunctionReference(Token payload) { super(pos,arguments);
super(payload); name = functionName;
this.name = payload.getText();
} }
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
TypedValue o = state.lookupVariable(name); TypedValue o = state.lookupVariable(name);
if (o == null) { if (o == null) {
throw new SpelException(SpelMessages.FUNCTION_NOT_DEFINED, name); throw new SpelEvaluationException(getStartPosition(), SpelMessages.FUNCTION_NOT_DEFINED, name);
} }
// Two possibilities: a lambda function or a Java static method registered as a function // Two possibilities: a lambda function or a Java static method registered as a function
if (!(o.getValue() instanceof Method)) { if (!(o.getValue() instanceof Method)) {
throw new SpelException(SpelMessages.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, name, o.getClass()); throw new SpelEvaluationException(SpelMessages.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, name, o.getClass());
} }
try {
return executeFunctionJLRMethod(state, (Method) o.getValue()); return executeFunctionJLRMethod(state, (Method) o.getValue());
} catch (SpelEvaluationException se) {
se.setPosition(getStartPosition());
throw se;
}
} }
/** /**
@ -82,12 +83,12 @@ public class FunctionReference extends SpelNodeImpl {
Object[] functionArgs = getArguments(state); Object[] functionArgs = getArguments(state);
if (!m.isVarArgs() && m.getParameterTypes().length != functionArgs.length) { if (!m.isVarArgs() && m.getParameterTypes().length != functionArgs.length) {
throw new SpelException(SpelMessages.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, functionArgs.length, m throw new SpelEvaluationException(SpelMessages.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, functionArgs.length, m
.getParameterTypes().length); .getParameterTypes().length);
} }
// Only static methods can be called in this way // Only static methods can be called in this way
if (!Modifier.isStatic(m.getModifiers())) { if (!Modifier.isStatic(m.getModifiers())) {
throw new SpelException(getCharPositionInLine(), SpelMessages.FUNCTION_MUST_BE_STATIC, m throw new SpelEvaluationException(getStartPosition(), SpelMessages.FUNCTION_MUST_BE_STATIC, m
.getDeclaringClass().getName() .getDeclaringClass().getName()
+ "." + m.getName(), name); + "." + m.getName(), name);
} }
@ -106,13 +107,13 @@ public class FunctionReference extends SpelNodeImpl {
Object result = m.invoke(m.getClass(), functionArgs); Object result = m.invoke(m.getClass(), functionArgs);
return new TypedValue(result, new TypeDescriptor(new MethodParameter(m,-1))); return new TypedValue(result, new TypeDescriptor(new MethodParameter(m,-1)));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new SpelException(getCharPositionInLine(), e, SpelMessages.EXCEPTION_DURING_FUNCTION_CALL, name, e throw new SpelEvaluationException(getStartPosition(), e, SpelMessages.EXCEPTION_DURING_FUNCTION_CALL, name, e
.getMessage()); .getMessage());
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new SpelException(getCharPositionInLine(), e, SpelMessages.EXCEPTION_DURING_FUNCTION_CALL, name, e throw new SpelEvaluationException(getStartPosition(), e, SpelMessages.EXCEPTION_DURING_FUNCTION_CALL, name, e
.getMessage()); .getMessage());
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
throw new SpelException(getCharPositionInLine(), e, SpelMessages.EXCEPTION_DURING_FUNCTION_CALL, name, e throw new SpelEvaluationException(getStartPosition(), e, SpelMessages.EXCEPTION_DURING_FUNCTION_CALL, name, e
.getMessage()); .getMessage());
} }
} }
@ -140,7 +141,7 @@ public class FunctionReference extends SpelNodeImpl {
// Compute arguments to the function // Compute arguments to the function
Object[] arguments = new Object[getChildCount()]; Object[] arguments = new Object[getChildCount()];
for (int i = 0; i < arguments.length; i++) { for (int i = 0; i < arguments.length; i++) {
arguments[i] = getChild(i).getValueInternal(state).getValue(); arguments[i] = children[i].getValueInternal(state).getValue();
} }
return arguments; return arguments;
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
@ -28,9 +27,9 @@ public class Identifier extends SpelNodeImpl {
private final TypedValue id; private final TypedValue id;
public Identifier(Token payload) { public Identifier(String payload,int pos) {
super(payload); super(pos);
this.id = new TypedValue(payload.getText(), STRING_TYPE_DESCRIPTOR); this.id = new TypedValue(payload, STRING_TYPE_DESCRIPTOR);
} }
@Override @Override

View File

@ -20,12 +20,11 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.antlr.runtime.Token;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
// TODO support multidimensional arrays // TODO support multidimensional arrays
@ -39,16 +38,17 @@ import org.springframework.expression.spel.SpelMessages;
*/ */
public class Indexer extends SpelNodeImpl { public class Indexer extends SpelNodeImpl {
public Indexer(Token payload) { public Indexer(int pos,SpelNodeImpl expr) {
super(payload); super(pos,expr);
} }
@SuppressWarnings("unchecked")
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
TypedValue context = state.getActiveContextObject(); TypedValue context = state.getActiveContextObject();
Object targetObject = context.getValue(); Object targetObject = context.getValue();
TypeDescriptor targetObjectTypeDescriptor = context.getTypeDescriptor(); TypeDescriptor targetObjectTypeDescriptor = context.getTypeDescriptor();
TypedValue indexValue = getChild(0).getValueInternal(state); TypedValue indexValue = children[0].getValueInternal(state);
Object index = indexValue.getValue(); Object index = indexValue.getValue();
// Indexing into a Map // Indexing into a Map
@ -61,7 +61,7 @@ public class Indexer extends SpelNodeImpl {
int idx = (Integer)state.convertValue(index, INTEGER_TYPE_DESCRIPTOR); int idx = (Integer)state.convertValue(index, INTEGER_TYPE_DESCRIPTOR);
if (targetObject == null) { if (targetObject == null) {
throw new SpelException(SpelMessages.CANNOT_INDEX_INTO_NULL_VALUE); throw new SpelEvaluationException(getStartPosition(),SpelMessages.CANNOT_INDEX_INTO_NULL_VALUE);
} }
if (targetObject.getClass().isArray()) { if (targetObject.getClass().isArray()) {
@ -69,7 +69,7 @@ public class Indexer extends SpelNodeImpl {
} else if (targetObject instanceof Collection) { } else if (targetObject instanceof Collection) {
Collection<?> c = (Collection<?>) targetObject; Collection<?> c = (Collection<?>) targetObject;
if (idx >= c.size()) { if (idx >= c.size()) {
throw new SpelException(SpelMessages.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx); throw new SpelEvaluationException(getStartPosition(),SpelMessages.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
} }
int pos = 0; int pos = 0;
for (Object o : c) { for (Object o : c) {
@ -81,16 +81,16 @@ public class Indexer extends SpelNodeImpl {
} else if (targetObject instanceof String) { } else if (targetObject instanceof String) {
String ctxString = (String) targetObject; String ctxString = (String) targetObject;
if (idx >= ctxString.length()) { if (idx >= ctxString.length()) {
throw new SpelException(SpelMessages.STRING_INDEX_OUT_OF_BOUNDS, ctxString.length(), idx); throw new SpelEvaluationException(getStartPosition(),SpelMessages.STRING_INDEX_OUT_OF_BOUNDS, ctxString.length(), idx);
} }
return new TypedValue(String.valueOf(ctxString.charAt(idx)),STRING_TYPE_DESCRIPTOR); return new TypedValue(String.valueOf(ctxString.charAt(idx)),STRING_TYPE_DESCRIPTOR);
} }
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.asString()); throw new SpelEvaluationException(getStartPosition(),SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.asString());
} }
@Override @Override
public boolean isWritable(ExpressionState expressionState) throws SpelException { public boolean isWritable(ExpressionState expressionState) throws SpelEvaluationException {
return true; return true;
} }
@ -100,10 +100,10 @@ public class Indexer extends SpelNodeImpl {
TypedValue contextObject = state.getActiveContextObject(); TypedValue contextObject = state.getActiveContextObject();
Object targetObject = contextObject.getValue(); Object targetObject = contextObject.getValue();
TypeDescriptor targetObjectTypeDescriptor = contextObject.getTypeDescriptor(); TypeDescriptor targetObjectTypeDescriptor = contextObject.getTypeDescriptor();
TypedValue index = getChild(0).getValueInternal(state); TypedValue index = children[0].getValueInternal(state);
if (targetObject == null) { if (targetObject == null) {
throw new SpelException(SpelMessages.CANNOT_INDEX_INTO_NULL_VALUE); throw new SpelEvaluationException(SpelMessages.CANNOT_INDEX_INTO_NULL_VALUE);
} }
// Indexing into a Map // Indexing into a Map
if (targetObjectTypeDescriptor.isMap()) { if (targetObjectTypeDescriptor.isMap()) {
@ -121,17 +121,17 @@ public class Indexer extends SpelNodeImpl {
int idx = (Integer)state.convertValue(index, INTEGER_TYPE_DESCRIPTOR); int idx = (Integer)state.convertValue(index, INTEGER_TYPE_DESCRIPTOR);
Collection c = (Collection) targetObject; Collection c = (Collection) targetObject;
if (idx >= c.size()) { if (idx >= c.size()) {
throw new SpelException(SpelMessages.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx); throw new SpelEvaluationException(getStartPosition(),SpelMessages.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
} }
if (targetObject instanceof List) { if (targetObject instanceof List) {
List list = (List)targetObject; List list = (List)targetObject;
Object possiblyConvertedValue = state.convertValue(newValue,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType())); Object possiblyConvertedValue = state.convertValue(newValue,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
list.set(idx,possiblyConvertedValue); list.set(idx,possiblyConvertedValue);
} else { } else {
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, contextObject.getClass().getName()); throw new SpelEvaluationException(getStartPosition(),SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, contextObject.getClass().getName());
} }
} else { } else {
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, contextObject.getClass().getName()); throw new SpelEvaluationException(getStartPosition(),SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, contextObject.getClass().getName());
} }
} }
@ -148,6 +148,7 @@ public class Indexer extends SpelNodeImpl {
return sb.toString(); return sb.toString();
} }
@SuppressWarnings("unchecked")
private void setArrayElement(ExpressionState state, Object ctx, int idx, Object newValue, Class clazz) throws EvaluationException { private void setArrayElement(ExpressionState state, Object ctx, int idx, Object newValue, Class clazz) throws EvaluationException {
Class<?> arrayComponentType = clazz; Class<?> arrayComponentType = clazz;
if (arrayComponentType == Integer.TYPE) { if (arrayComponentType == Integer.TYPE) {
@ -190,7 +191,7 @@ public class Indexer extends SpelNodeImpl {
} }
private Object accessArrayElement(Object ctx, int idx) throws SpelException { private Object accessArrayElement(Object ctx, int idx) throws SpelEvaluationException {
Class<?> arrayComponentType = ctx.getClass().getComponentType(); Class<?> arrayComponentType = ctx.getClass().getComponentType();
if (arrayComponentType == Integer.TYPE) { if (arrayComponentType == Integer.TYPE) {
int[] array = (int[]) ctx; int[] array = (int[]) ctx;
@ -232,9 +233,9 @@ public class Indexer extends SpelNodeImpl {
} }
private void checkAccess(int arrayLength, int index) throws SpelException { private void checkAccess(int arrayLength, int index) throws SpelEvaluationException {
if (index > arrayLength) { if (index > arrayLength) {
throw new SpelException(getCharPositionInLine(), SpelMessages.ARRAY_INDEX_OUT_OF_BOUNDS, arrayLength, index); throw new SpelEvaluationException(getStartPosition(), SpelMessages.ARRAY_INDEX_OUT_OF_BOUNDS, arrayLength, index);
} }
} }

View File

@ -1,22 +1,5 @@
/*
* Copyright 2002-2009 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.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
/** /**
@ -29,8 +12,8 @@ public class IntLiteral extends Literal {
private final TypedValue value; private final TypedValue value;
IntLiteral(Token payload, int value) { IntLiteral(String payload, int pos, int value) {
super(payload); super(payload, pos);
this.value = new TypedValue(value, INTEGER_TYPE_DESCRIPTOR); this.value = new TypedValue(value, INTEGER_TYPE_DESCRIPTOR);
} }

View File

@ -16,29 +16,31 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.WrappedSpelException; import org.springframework.expression.spel.SpelParseException;
import org.springframework.expression.spel.standard.InternalParseException;
/** /**
* Common superclass for nodes representing literals (boolean, string, number, etc). * Common superclass for nodes representing literals (boolean, string, number, etc).
* *
* @author Andy Clement * @author Andy Clement
*
*/ */
public abstract class Literal extends SpelNodeImpl { public abstract class Literal extends SpelNodeImpl {
public Literal(Token payload) { protected String literalValue;
super(payload);
public Literal(String payload, int pos) {
super(pos);
this.literalValue = payload;
} }
public abstract TypedValue getLiteralValue(); public abstract TypedValue getLiteralValue();
@Override @Override
public final TypedValue getValueInternal(ExpressionState state) throws SpelException { public final TypedValue getValueInternal(ExpressionState state) throws SpelEvaluationException {
return getLiteralValue(); return getLiteralValue();
} }
@ -60,37 +62,38 @@ public abstract class Literal extends SpelNodeImpl {
* @param radix the base of number * @param radix the base of number
* @return a subtype of Literal that can represent it * @return a subtype of Literal that can represent it
*/ */
public static Literal getIntLiteral(Token numberToken, int radix) { public static Literal getIntLiteral(String numberToken, int pos, int radix) {
String numberString = numberToken.getText();
boolean isLong = false;
boolean isHex = (radix == 16);
isLong = numberString.endsWith("L") || numberString.endsWith("l");
if (isLong || isHex) { // needs to be chopped up a little
int len = numberString.length();
// assert: if hex then startsWith 0x or 0X
numberString = numberString.substring((isHex ? 2 : 0), isLong ? len - 1 : len);
}
if (isLong) {
try { try {
long value = Long.parseLong(numberString, radix); int value = Integer.parseInt(numberToken, radix);
return new LongLiteral(numberToken, value); return new IntLiteral(numberToken, pos, value);
} catch (NumberFormatException nfe) { } catch (NumberFormatException nfe) {
throw new WrappedSpelException(new SpelException(numberToken.getCharPositionInLine(), nfe, throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessages.NOT_AN_INTEGER, numberToken));
SpelMessages.NOT_A_LONG, numberToken.getText()));
} }
}
public static Literal getLongLiteral(String numberToken, int pos, int radix) {
try {
long value = Long.parseLong(numberToken, radix);
return new LongLiteral(numberToken, pos, value);
} catch (NumberFormatException nfe) {
throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessages.NOT_A_LONG, numberToken));
}
}
// TODO should allow for 'f' for float, not just double
public static Literal getRealLiteral(String numberToken, int pos, boolean isFloat) {
try {
if (isFloat) {
float value = Float.parseFloat(numberToken);
return new RealLiteral(numberToken, pos, value);
} else { } else {
try { double value = Double.parseDouble(numberToken);
int value = Integer.parseInt(numberString, radix); return new RealLiteral(numberToken, pos, value);
return new IntLiteral(numberToken, value);
} catch (NumberFormatException nfe) {
throw new WrappedSpelException(new SpelException(numberToken.getCharPositionInLine(), nfe,
SpelMessages.NOT_AN_INTEGER, numberToken.getText()));
} }
} catch (NumberFormatException nfe) {
throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessages.NOT_A_REAL, numberToken));
} }
} }
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
/** /**
@ -29,8 +28,8 @@ public class LongLiteral extends Literal {
private final TypedValue value; private final TypedValue value;
LongLiteral(Token payload, long value) { LongLiteral(String payload, int pos, long value) {
super(payload); super(payload, pos);
this.value = new TypedValue(value, LONG_TYPE_DESCRIPTOR); this.value = new TypedValue(value, LONG_TYPE_DESCRIPTOR);
} }

View File

@ -18,7 +18,6 @@ package org.springframework.expression.spel.ast;
import java.util.List; import java.util.List;
import org.antlr.runtime.Token;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
@ -26,7 +25,7 @@ import org.springframework.expression.MethodExecutor;
import org.springframework.expression.MethodResolver; import org.springframework.expression.MethodResolver;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
/** /**
@ -39,11 +38,12 @@ public class MethodReference extends SpelNodeImpl {
private final String name; private final String name;
private volatile MethodExecutor cachedExecutor; private volatile MethodExecutor cachedExecutor;
private final boolean nullSafe;
public MethodReference(boolean nullSafe, String methodName, int pos, SpelNodeImpl... arguments) {
public MethodReference(Token payload) { super(pos,arguments);
super(payload); name = methodName;
name = payload.getText(); this.nullSafe = nullSafe;
} }
@ -52,12 +52,17 @@ public class MethodReference extends SpelNodeImpl {
TypedValue currentContext = state.getActiveContextObject(); TypedValue currentContext = state.getActiveContextObject();
Object[] arguments = new Object[getChildCount()]; Object[] arguments = new Object[getChildCount()];
for (int i = 0; i < arguments.length; i++) { for (int i = 0; i < arguments.length; i++) {
arguments[i] = getChild(i).getValueInternal(state).getValue(); // System.out.println(i);
arguments[i] = children[i].getValueInternal(state).getValue();
} }
if (currentContext.getValue() == null) { if (currentContext.getValue() == null) {
throw new SpelException(getCharPositionInLine(), SpelMessages.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED, if (nullSafe) {
return TypedValue.NULL_TYPED_VALUE;
} else {
throw new SpelEvaluationException(getStartPosition(), SpelMessages.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED,
FormatHelper.formatMethodForMessage(name, getTypes(arguments))); FormatHelper.formatMethodForMessage(name, getTypes(arguments)));
} }
}
MethodExecutor executorToUse = this.cachedExecutor; MethodExecutor executorToUse = this.cachedExecutor;
if (executorToUse != null) { if (executorToUse != null) {
@ -79,7 +84,7 @@ public class MethodReference extends SpelNodeImpl {
return executorToUse.execute( return executorToUse.execute(
state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments); state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments);
} catch (AccessException ae) { } catch (AccessException ae) {
throw new SpelException(getCharPositionInLine(), ae, SpelMessages.EXCEPTION_DURING_METHOD_INVOCATION, throw new SpelEvaluationException( getStartPosition(), ae, SpelMessages.EXCEPTION_DURING_METHOD_INVOCATION,
this.name, state.getActiveContextObject().getValue().getClass().getName(), ae.getMessage()); this.name, state.getActiveContextObject().getValue().getClass().getName(), ae.getMessage());
} }
} }
@ -106,7 +111,7 @@ public class MethodReference extends SpelNodeImpl {
} }
private MethodExecutor findAccessorForMethod(String name, Class<?>[] argumentTypes, ExpressionState state) private MethodExecutor findAccessorForMethod(String name, Class<?>[] argumentTypes, ExpressionState state)
throws SpelException { throws SpelEvaluationException {
TypedValue context = state.getActiveContextObject(); TypedValue context = state.getActiveContextObject();
Object contextObject = context.getValue(); Object contextObject = context.getValue();
@ -123,11 +128,11 @@ public class MethodReference extends SpelNodeImpl {
} }
} }
catch (AccessException ex) { catch (AccessException ex) {
throw new SpelException(ex, SpelMessages.PROBLEM_LOCATING_METHOD, name, contextObject.getClass()); throw new SpelEvaluationException(getStartPosition(),ex, SpelMessages.PROBLEM_LOCATING_METHOD, name, contextObject.getClass());
} }
} }
} }
throw new SpelException(SpelMessages.METHOD_NOT_FOUND, FormatHelper.formatMethodForMessage(name, argumentTypes), throw new SpelEvaluationException(getStartPosition(),SpelMessages.METHOD_NOT_FOUND, FormatHelper.formatMethodForMessage(name, argumentTypes),
FormatHelper.formatClassNameForMessage(contextObject instanceof Class ? ((Class<?>) contextObject) : contextObject.getClass())); FormatHelper.formatClassNameForMessage(contextObject instanceof Class ? ((Class<?>) contextObject) : contextObject.getClass()));
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
/** /**
@ -25,8 +24,8 @@ import org.springframework.expression.TypedValue;
*/ */
public class NullLiteral extends Literal { public class NullLiteral extends Literal {
public NullLiteral(Token payload) { public NullLiteral(int pos) {
super(payload); super(null,pos);
} }
@Override @Override

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
@ -27,15 +26,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class OperatorEquality extends Operator { public class OpEQ extends Operator {
public OperatorEquality(Token payload) { public OpEQ(int pos, SpelNodeImpl... operands) {
super(payload); super("==", pos, operands);
}
@Override
public String getOperatorName() {
return "==";
} }
@Override @Override

View File

@ -15,7 +15,6 @@
*/ */
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
@ -26,15 +25,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class OperatorGreaterThanOrEqual extends Operator { public class OpGE extends Operator {
public OperatorGreaterThanOrEqual(Token payload) { public OpGE(int pos, SpelNodeImpl... operands) {
super(payload); super(">=", pos, operands);
}
@Override
public String getOperatorName() {
return ">=";
} }
@Override @Override

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
@ -27,15 +26,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class OperatorGreaterThan extends Operator { public class OpGT extends Operator {
public OperatorGreaterThan(Token payload) { public OpGT(int pos, SpelNodeImpl... operands) {
super(payload); super(">", pos, operands);
}
@Override
public String getOperatorName() {
return ">";
} }
@Override @Override

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
@ -27,10 +26,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class OperatorLessThanOrEqual extends Operator { public class OpLE extends Operator {
public OperatorLessThanOrEqual(Token payload) { public OpLE(int pos, SpelNodeImpl... operands) {
super(payload); super("<=", pos, operands);
} }
@Override @Override
@ -51,9 +50,4 @@ public class OperatorLessThanOrEqual extends Operator {
return BooleanTypedValue.forValue( state.getTypeComparator().compare(left, right) <= 0); return BooleanTypedValue.forValue( state.getTypeComparator().compare(left, right) <= 0);
} }
@Override
public String getOperatorName() {
return "<=";
}
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
@ -27,15 +26,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class OperatorLessThan extends Operator { public class OpLT extends Operator {
public OperatorLessThan(Token payload) { public OpLT(int pos, SpelNodeImpl... operands) {
super(payload); super("<", pos, operands);
}
@Override
public String getOperatorName() {
return "<";
} }
@Override @Override

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
@ -27,15 +26,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class OperatorInequality extends Operator { public class OpNE extends Operator {
public OperatorInequality(Token payload) { public OpNE(int pos, SpelNodeImpl... operands) {
super(payload); super("!=", pos, operands);
}
@Override
public String getOperatorName() {
return "!=";
} }
@Override @Override

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
/** /**
* Common supertype for operators that operate on either one or two operands. In the case of multiply or divide there * Common supertype for operators that operate on either one or two operands. In the case of multiply or divide there
@ -27,19 +26,24 @@ import org.antlr.runtime.Token;
*/ */
public abstract class Operator extends SpelNodeImpl { public abstract class Operator extends SpelNodeImpl {
public Operator(Token payload) { String operatorName;
super(payload);
public Operator(String payload,int pos,SpelNodeImpl... operands) {
super(pos, operands);
this.operatorName = payload;
} }
public SpelNodeImpl getLeftOperand() { public SpelNodeImpl getLeftOperand() {
return getChild(0); return children[0];
} }
public SpelNodeImpl getRightOperand() { public SpelNodeImpl getRightOperand() {
return getChild(1); return children[1];
} }
public abstract String getOperatorName(); public final String getOperatorName() {
return operatorName;
}
/** /**
* String format for all operators is the same '(' [operand] [operator] [operand] ')' * String format for all operators is the same '(' [operand] [operator] [operand] ')'

View File

@ -16,11 +16,10 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
/** /**
@ -31,13 +30,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OperatorAnd extends Operator { public class OperatorAnd extends Operator {
public OperatorAnd(Token payload) { public OperatorAnd(int pos, SpelNodeImpl... operands) {
super(payload); super("and", pos, operands);
}
@Override
public String getOperatorName() {
return "and";
} }
@Override @Override
@ -48,8 +42,8 @@ public class OperatorAnd extends Operator {
try { try {
leftValue = (Boolean)state.convertValue(getLeftOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR); leftValue = (Boolean)state.convertValue(getLeftOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
} }
catch (SpelException ee) { catch (SpelEvaluationException ee) {
ee.setPosition(getLeftOperand().getCharPositionInLine()); ee.setPosition(getLeftOperand().getStartPosition());
throw ee; throw ee;
} }
@ -60,8 +54,8 @@ public class OperatorAnd extends Operator {
try { try {
rightValue = (Boolean)state.convertValue(getRightOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR); rightValue = (Boolean)state.convertValue(getRightOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
} }
catch (SpelException ee) { catch (SpelEvaluationException ee) {
ee.setPosition(getRightOperand().getCharPositionInLine()); ee.setPosition(getRightOperand().getStartPosition());
throw ee; throw ee;
} }

View File

@ -18,11 +18,10 @@ package org.springframework.expression.spel.ast;
import java.util.List; import java.util.List;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeComparator; import org.springframework.expression.TypeComparator;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
@ -36,13 +35,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OperatorBetween extends Operator { public class OperatorBetween extends Operator {
public OperatorBetween(Token payload) { public OperatorBetween(int pos, SpelNodeImpl... operands) {
super(payload); super("between", pos, operands);
}
@Override
public String getOperatorName() {
return "between";
} }
/** /**
@ -57,7 +51,7 @@ public class OperatorBetween extends Operator {
Object left = getLeftOperand().getValueInternal(state).getValue(); Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue(); Object right = getRightOperand().getValueInternal(state).getValue();
if (!(right instanceof List) || ((List<?>) right).size() != 2) { if (!(right instanceof List) || ((List<?>) right).size() != 2) {
throw new SpelException(getRightOperand().getCharPositionInLine(), throw new SpelEvaluationException(getRightOperand().getStartPosition(),
SpelMessages.BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST); SpelMessages.BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST);
} }
List<?> l = (List<?>) right; List<?> l = (List<?>) right;
@ -66,8 +60,8 @@ public class OperatorBetween extends Operator {
TypeComparator comparator = state.getTypeComparator(); TypeComparator comparator = state.getTypeComparator();
try { try {
return BooleanTypedValue.forValue((comparator.compare(left, low) >= 0 && comparator.compare(left, high) <= 0)); return BooleanTypedValue.forValue((comparator.compare(left, low) >= 0 && comparator.compare(left, high) <= 0));
} catch (SpelException ex) { } catch (SpelEvaluationException ex) {
ex.setPosition(getCharPositionInLine()); ex.setPosition(getStartPosition());
throw ex; throw ex;
} }
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
@ -31,13 +30,8 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class OperatorDivide extends Operator { public class OperatorDivide extends Operator {
public OperatorDivide(Token payload) { public OperatorDivide(int pos, SpelNodeImpl... operands) {
super(payload); super("/", pos, operands);
}
@Override
public String getOperatorName() {
return "/";
} }
@Override @Override

View File

@ -16,11 +16,10 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
@ -33,13 +32,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OperatorInstanceof extends Operator { public class OperatorInstanceof extends Operator {
public OperatorInstanceof(Token payload) { public OperatorInstanceof(int pos, SpelNodeImpl... operands) {
super(payload); super("instanceof", pos, operands);
}
@Override
public String getOperatorName() {
return "instanceof";
} }
/** /**
@ -59,7 +53,7 @@ public class OperatorInstanceof extends Operator {
return BooleanTypedValue.False; // null is not an instanceof anything return BooleanTypedValue.False; // null is not an instanceof anything
} }
if (rightValue == null || !(rightValue instanceof Class<?>)) { if (rightValue == null || !(rightValue instanceof Class<?>)) {
throw new SpelException(getRightOperand().getCharPositionInLine(), throw new SpelEvaluationException(getRightOperand().getStartPosition(),
SpelMessages.INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND, SpelMessages.INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND,
(rightValue == null ? "null" : rightValue.getClass().getName())); (rightValue == null ? "null" : rightValue.getClass().getName()));
} }

View File

@ -20,10 +20,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
@ -36,13 +35,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OperatorMatches extends Operator { public class OperatorMatches extends Operator {
public OperatorMatches(Token payload) { public OperatorMatches(int pos, SpelNodeImpl... operands) {
super(payload); super("matches", pos, operands);
}
@Override
public String getOperatorName() {
return "matches";
} }
/** /**
@ -59,11 +53,11 @@ public class OperatorMatches extends Operator {
Object right = getRightOperand().getValueInternal(state).getValue(); Object right = getRightOperand().getValueInternal(state).getValue();
try { try {
if (!(left instanceof String)) { if (!(left instanceof String)) {
throw new SpelException(leftOp.getCharPositionInLine(), throw new SpelEvaluationException(leftOp.getStartPosition(),
SpelMessages.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, left); SpelMessages.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, left);
} }
if (!(right instanceof String)) { if (!(right instanceof String)) {
throw new SpelException(rightOp.getCharPositionInLine(), throw new SpelEvaluationException(rightOp.getStartPosition(),
SpelMessages.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, right); SpelMessages.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, right);
} }
Pattern pattern = Pattern.compile((String) right); Pattern pattern = Pattern.compile((String) right);
@ -71,7 +65,7 @@ public class OperatorMatches extends Operator {
return BooleanTypedValue.forValue(matcher.matches()); return BooleanTypedValue.forValue(matcher.matches());
} }
catch (PatternSyntaxException pse) { catch (PatternSyntaxException pse) {
throw new SpelException(rightOp.getCharPositionInLine(), pse, SpelMessages.INVALID_PATTERN, right); throw new SpelEvaluationException(rightOp.getStartPosition(), pse, SpelMessages.INVALID_PATTERN, right);
} }
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
@ -39,8 +38,8 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class OperatorMinus extends Operator { public class OperatorMinus extends Operator {
public OperatorMinus(Token payload) { public OperatorMinus(int pos, SpelNodeImpl... operands) {
super(payload); super("-", pos, operands);
} }
@Override @Override
@ -83,11 +82,6 @@ public class OperatorMinus extends Operator {
} }
} }
@Override
public String getOperatorName() {
return "-";
}
@Override @Override
public String toStringAST() { public String toStringAST() {
if (getRightOperand() == null) { // unary minus if (getRightOperand() == null) { // unary minus
@ -95,5 +89,9 @@ public class OperatorMinus extends Operator {
} }
return super.toStringAST(); return super.toStringAST();
} }
public SpelNodeImpl getRightOperand() {
if (children.length<2) {return null;}
return children[1];
}
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
@ -30,13 +29,8 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class OperatorModulus extends Operator { public class OperatorModulus extends Operator {
public OperatorModulus(Token payload) { public OperatorModulus(int pos, SpelNodeImpl... operands) {
super(payload); super("%", pos, operands);
}
@Override
public String getOperatorName() {
return "%";
} }
@Override @Override

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
@ -39,8 +38,9 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class OperatorMultiply extends Operator { public class OperatorMultiply extends Operator {
public OperatorMultiply(Token payload) {
super(payload); public OperatorMultiply(int pos, SpelNodeImpl... operands) {
super("*", pos, operands);
} }
/** /**
@ -77,9 +77,4 @@ public class OperatorMultiply extends Operator {
return state.operate(Operation.MULTIPLY, operandOne, operandTwo); return state.operate(Operation.MULTIPLY, operandOne, operandTwo);
} }
@Override
public String getOperatorName() {
return "*";
}
} }

View File

@ -16,10 +16,9 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
/** /**
@ -30,18 +29,18 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so do not extend BinaryOperator public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so do not extend BinaryOperator
public OperatorNot(Token payload) { public OperatorNot(int pos, SpelNodeImpl operand) {
super(payload); super(pos, operand);
} }
@Override @Override
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException { public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
try { try {
boolean value = (Boolean)state.convertValue(getChild(0).getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR); boolean value = (Boolean)state.convertValue(children[0].getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
return BooleanTypedValue.forValue(!value); return BooleanTypedValue.forValue(!value);
} }
catch (SpelException see) { catch (SpelEvaluationException see) {
see.setPosition(getChild(0).getCharPositionInLine()); see.setPosition(getChild(0).getStartPosition());
throw see; throw see;
} }
} }

View File

@ -16,10 +16,9 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
/** /**
@ -30,13 +29,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OperatorOr extends Operator { public class OperatorOr extends Operator {
public OperatorOr(Token payload) { public OperatorOr(int pos, SpelNodeImpl... operands) {
super(payload); super("or", pos, operands);
}
@Override
public String getOperatorName() {
return "or";
} }
@Override @Override
@ -46,8 +40,8 @@ public class OperatorOr extends Operator {
try { try {
leftValue = (Boolean)state.convertValue(getLeftOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR); leftValue = (Boolean)state.convertValue(getLeftOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
} }
catch (SpelException see) { catch (SpelEvaluationException see) {
see.setPosition(getLeftOperand().getCharPositionInLine()); see.setPosition(getLeftOperand().getStartPosition());
throw see; throw see;
} }
@ -58,8 +52,8 @@ public class OperatorOr extends Operator {
try { try {
rightValue = (Boolean)state.convertValue(getRightOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR); rightValue = (Boolean)state.convertValue(getRightOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
} }
catch (SpelException see) { catch (SpelEvaluationException see) {
see.setPosition(getRightOperand().getCharPositionInLine()); see.setPosition(getRightOperand().getStartPosition()); // TODO end positions here and in similar situations
throw see; throw see;
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
@ -38,8 +37,8 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class OperatorPlus extends Operator { public class OperatorPlus extends Operator {
public OperatorPlus(Token payload) { public OperatorPlus(int pos, SpelNodeImpl... operands) {
super(payload); super("+", pos, operands);
} }
@Override @Override
@ -79,17 +78,18 @@ public class OperatorPlus extends Operator {
} }
} }
@Override
public String getOperatorName() {
return "+";
}
@Override @Override
public String toStringAST() { public String toStringAST() {
if (getRightOperand() == null) { // unary plus if (children.length<2) { // unary plus
return new StringBuilder().append("+").append(getLeftOperand().toStringAST()).toString(); return new StringBuilder().append("+").append(getLeftOperand().toStringAST()).toString();
} }
return super.toStringAST(); return super.toStringAST();
} }
public SpelNodeImpl getRightOperand() {
if (children.length<2) {return null;}
return children[1];
}
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
@ -30,8 +29,8 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class OperatorPower extends Operator { public class OperatorPower extends Operator {
public OperatorPower(Token payload) { public OperatorPower(int pos, SpelNodeImpl... operands) {
super(payload); super("^", pos, operands);
} }
@Override @Override
@ -61,9 +60,4 @@ public class OperatorPower extends Operator {
return state.operate(Operation.POWER, operandOne, operandTwo); return state.operate(Operation.POWER, operandOne, operandTwo);
} }
@Override
public String getOperatorName() {
return "^";
}
} }

View File

@ -21,12 +21,11 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.antlr.runtime.Token;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
/** /**
@ -39,10 +38,14 @@ import org.springframework.expression.spel.SpelMessages;
*/ */
public class Projection extends SpelNodeImpl { public class Projection extends SpelNodeImpl {
public Projection(Token payload) { private final boolean nullSafe;
super(payload);
public Projection(boolean nullSafe, int pos,SpelNodeImpl expression) {
super(pos,expression);
this.nullSafe = nullSafe;
} }
@SuppressWarnings("unchecked")
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
TypedValue op = state.getActiveContextObject(); TypedValue op = state.getActiveContextObject();
@ -61,7 +64,7 @@ public class Projection extends SpelNodeImpl {
for (Map.Entry entry : mapdata.entrySet()) { for (Map.Entry entry : mapdata.entrySet()) {
try { try {
state.pushActiveContextObject(new TypedValue(entry,TypeDescriptor.valueOf(Map.Entry.class))); state.pushActiveContextObject(new TypedValue(entry,TypeDescriptor.valueOf(Map.Entry.class)));
result.add(getChild(0).getValueInternal(state).getValue()); result.add(children[0].getValueInternal(state).getValue());
} finally { } finally {
state.popActiveContextObject(); state.popActiveContextObject();
} }
@ -76,7 +79,7 @@ public class Projection extends SpelNodeImpl {
try { try {
state.pushActiveContextObject(new TypedValue(element,TypeDescriptor.valueOf(op.getTypeDescriptor().getType()))); state.pushActiveContextObject(new TypedValue(element,TypeDescriptor.valueOf(op.getTypeDescriptor().getType())));
state.enterScope("index", idx); state.enterScope("index", idx);
result.add(getChild(0).getValueInternal(state).getValue()); result.add(children[0].getValueInternal(state).getValue());
} finally { } finally {
state.exitScope(); state.exitScope();
state.popActiveContextObject(); state.popActiveContextObject();
@ -85,7 +88,11 @@ public class Projection extends SpelNodeImpl {
} }
return new TypedValue(result,op.getTypeDescriptor()); return new TypedValue(result,op.getTypeDescriptor());
} else { } else {
throw new SpelException(SpelMessages.PROJECTION_NOT_SUPPORTED_ON_TYPE, operand.getClass().getName()); if (operand==null && nullSafe) {
return TypedValue.NULL_TYPED_VALUE;
} else {
throw new SpelEvaluationException(getStartPosition(),SpelMessages.PROJECTION_NOT_SUPPORTED_ON_TYPE, operand.getClass().getName());
}
} }
} }

View File

@ -19,13 +19,12 @@ package org.springframework.expression.spel.ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.antlr.runtime.Token;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.PropertyAccessor; import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
/** /**
@ -43,24 +42,26 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
private volatile PropertyAccessor cachedWriteAccessor; private volatile PropertyAccessor cachedWriteAccessor;
public PropertyOrFieldReference(Token payload) { private final boolean nullSafe;
super(payload);
this.name = payload.getText(); public PropertyOrFieldReference(boolean nullSafe, String propertyOrFieldName, int pos) {
super(pos);
name = propertyOrFieldName;
this.nullSafe = nullSafe;
} }
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws SpelException { public TypedValue getValueInternal(ExpressionState state) throws SpelEvaluationException {
return readProperty(state, this.name); return readProperty(state, this.name);
} }
@Override @Override
public void setValue(ExpressionState state, Object newValue) throws SpelException { public void setValue(ExpressionState state, Object newValue) throws SpelEvaluationException {
writeProperty(state, this.name, newValue); writeProperty(state, this.name, newValue);
} }
@Override @Override
public boolean isWritable(ExpressionState state) throws SpelException { public boolean isWritable(ExpressionState state) throws SpelEvaluationException {
return isWritableProperty(this.name, state); return isWritableProperty(this.name, state);
} }
@ -74,12 +75,16 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
* @param state the evaluation state * @param state the evaluation state
* @param name the name of the property * @param name the name of the property
* @return the value of the property * @return the value of the property
* @throws SpelException if any problem accessing the property or it cannot be found * @throws SpelEvaluationException if any problem accessing the property or it cannot be found
*/ */
private TypedValue readProperty(ExpressionState state, String name) throws SpelException { private TypedValue readProperty(ExpressionState state, String name) throws SpelEvaluationException {
TypedValue contextObject = state.getActiveContextObject(); TypedValue contextObject = state.getActiveContextObject();
EvaluationContext eContext = state.getEvaluationContext(); EvaluationContext eContext = state.getEvaluationContext();
if (contextObject.getValue() == null && nullSafe) {
return TypedValue.NULL_TYPED_VALUE;
}
PropertyAccessor accessorToUse = this.cachedReadAccessor; PropertyAccessor accessorToUse = this.cachedReadAccessor;
if (accessorToUse != null) { if (accessorToUse != null) {
try { try {
@ -108,21 +113,25 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
} }
} }
catch (AccessException ae) { catch (AccessException ae) {
throw new SpelException(ae, SpelMessages.EXCEPTION_DURING_PROPERTY_READ, name, ae.getMessage()); throw new SpelEvaluationException(ae, SpelMessages.EXCEPTION_DURING_PROPERTY_READ, name, ae.getMessage());
} }
} }
if (contextObject.getValue() == null) { if (contextObject.getValue() == null) {
throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL, name); throw new SpelEvaluationException(SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL, name);
} else { } else {
throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE, name, throw new SpelEvaluationException(getStartPosition(),SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE, name,
FormatHelper.formatClassNameForMessage(contextObjectClass)); FormatHelper.formatClassNameForMessage(contextObjectClass));
} }
} }
private void writeProperty(ExpressionState state, String name, Object newValue) throws SpelException { private void writeProperty(ExpressionState state, String name, Object newValue) throws SpelEvaluationException {
TypedValue contextObject = state.getActiveContextObject(); TypedValue contextObject = state.getActiveContextObject();
EvaluationContext eContext = state.getEvaluationContext(); EvaluationContext eContext = state.getEvaluationContext();
if (contextObject.getValue() == null && nullSafe) {
return;
}
PropertyAccessor accessorToUse = this.cachedWriteAccessor; PropertyAccessor accessorToUse = this.cachedWriteAccessor;
if (accessorToUse != null) { if (accessorToUse != null) {
try { try {
@ -149,19 +158,19 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
} }
} }
} catch (AccessException ae) { } catch (AccessException ae) {
throw new SpelException(getCharPositionInLine(), ae, SpelMessages.EXCEPTION_DURING_PROPERTY_WRITE, throw new SpelEvaluationException(getStartPosition(), ae, SpelMessages.EXCEPTION_DURING_PROPERTY_WRITE,
name, ae.getMessage()); name, ae.getMessage());
} }
} }
if (contextObject.getValue()==null) { if (contextObject.getValue()==null) {
throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL, name); throw new SpelEvaluationException(getStartPosition(),SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL, name);
} else { } else {
throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE, name, FormatHelper throw new SpelEvaluationException(getStartPosition(),SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE, name, FormatHelper
.formatClassNameForMessage(contextObjectClass)); .formatClassNameForMessage(contextObjectClass));
} }
} }
public boolean isWritableProperty(String name, ExpressionState state) throws SpelException { public boolean isWritableProperty(String name, ExpressionState state) throws SpelEvaluationException {
Object contextObject = state.getActiveContextObject().getValue(); Object contextObject = state.getActiveContextObject().getValue();
EvaluationContext eContext = state.getEvaluationContext(); EvaluationContext eContext = state.getEvaluationContext();

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
@ -31,11 +30,11 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class QualifiedIdentifier extends SpelNodeImpl { public class QualifiedIdentifier extends SpelNodeImpl {
// TODO safe to cache? dont think so
private TypedValue value; private TypedValue value;
public QualifiedIdentifier(Token payload) { public QualifiedIdentifier(int pos,SpelNodeImpl... operands) {
super(payload); super(pos,operands);
// value = payload.getText();
} }
@Override @Override
@ -47,7 +46,7 @@ public class QualifiedIdentifier extends SpelNodeImpl {
if (i > 0) { if (i > 0) {
sb.append("."); sb.append(".");
} }
sb.append(getChild(i).getValueInternal(state).getValue()); sb.append(children[i].getValueInternal(state).getValue());
} }
this.value = new TypedValue(sb.toString(),STRING_TYPE_DESCRIPTOR); this.value = new TypedValue(sb.toString(),STRING_TYPE_DESCRIPTOR);
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
/** /**
@ -27,9 +26,9 @@ public class RealLiteral extends Literal {
private final TypedValue value; private final TypedValue value;
public RealLiteral(Token payload) { public RealLiteral(String payload, int pos, double value) {
super(payload); super(payload, pos);
value = new TypedValue(Double.parseDouble(payload.getText()),DOUBLE_TYPE_DESCRIPTOR); this.value = new TypedValue(value,DOUBLE_TYPE_DESCRIPTOR);
} }
@Override @Override

View File

@ -22,12 +22,11 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.antlr.runtime.Token;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
/** /**
@ -46,18 +45,21 @@ public class Selection extends SpelNodeImpl {
public final static int LAST = 2; // $[] public final static int LAST = 2; // $[]
private final int variant; private final int variant;
private final boolean nullSafe;
public Selection(Token payload, int variant) { public Selection(boolean nullSafe, int variant,int pos,SpelNodeImpl expression) {
super(payload); super(pos,expression);
this.nullSafe = nullSafe;
this.variant = variant; this.variant = variant;
} }
@SuppressWarnings("unchecked")
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
TypedValue op = state.getActiveContextObject(); TypedValue op = state.getActiveContextObject();
Object operand = op.getValue(); Object operand = op.getValue();
SpelNodeImpl selectionCriteria = getChild(0); SpelNodeImpl selectionCriteria = children[0];
if (operand instanceof Map) { if (operand instanceof Map) {
Map<?, ?> mapdata = (Map<?, ?>) operand; Map<?, ?> mapdata = (Map<?, ?>) operand;
// TODO don't lose generic info for the new map // TODO don't lose generic info for the new map
@ -78,7 +80,7 @@ public class Selection extends SpelNodeImpl {
result.put(entry.getKey(),entry.getValue()); result.put(entry.getKey(),entry.getValue());
} }
} else { } else {
throw new SpelException(selectionCriteria.getCharPositionInLine(), throw new SpelEvaluationException(selectionCriteria.getStartPosition(),
SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST()); SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST());
} }
} finally { } finally {
@ -113,7 +115,7 @@ public class Selection extends SpelNodeImpl {
result.add(element); result.add(element);
} }
} else { } else {
throw new SpelException(selectionCriteria.getCharPositionInLine(), throw new SpelEvaluationException(selectionCriteria.getStartPosition(),
SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST()); SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST());
} }
idx++; idx++;
@ -130,10 +132,14 @@ public class Selection extends SpelNodeImpl {
} }
return new TypedValue(result,op.getTypeDescriptor()); return new TypedValue(result,op.getTypeDescriptor());
} else { } else {
throw new SpelException(getCharPositionInLine(), SpelMessages.INVALID_TYPE_FOR_SELECTION, if (operand==null && nullSafe) {
return TypedValue.NULL_TYPED_VALUE;
} else {
throw new SpelEvaluationException(getStartPosition(), SpelMessages.INVALID_TYPE_FOR_SELECTION,
(operand == null ? "null" : operand.getClass().getName())); (operand == null ? "null" : operand.getClass().getName()));
} }
} }
}
@Override @Override
public String toStringAST() { public String toStringAST() {

View File

@ -16,18 +16,13 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.io.Serializable;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.common.ExpressionUtils; import org.springframework.expression.common.ExpressionUtils;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.SpelNode; import org.springframework.expression.spel.SpelNode;
import org.springframework.expression.spel.generated.SpringExpressionsParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
/** /**
@ -36,14 +31,22 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Serializable, CommonTypeDescriptors { public abstract class SpelNodeImpl implements SpelNode, CommonTypeDescriptors {
/** private static SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0];
* The Antlr parser uses this constructor to build SpelNodes.
* @param payload the token for the node that has been parsed protected int pos; // start = top 16bits, end = bottom 16bits
*/ protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
protected SpelNodeImpl(Token payload) {
super(payload); public SpelNodeImpl(int pos, SpelNodeImpl... operands) {
this.pos = pos;
if (pos==0) {
// pos embodies start and end so can never be zero because tokens cannot be zero length
throw new IllegalStateException("Node cannot have zero position: "+this.getClass());
}
if (operands!=null && operands.length>0) {
this.children = operands;
}
} }
public final Object getValue(ExpressionState expressionState) throws EvaluationException { public final Object getValue(ExpressionState expressionState) throws EvaluationException {
@ -60,20 +63,15 @@ public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Seria
} }
public void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException { public void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException {
throw new SpelException( throw new SpelEvaluationException(getStartPosition(), SpelMessages.SETVALUE_NOT_SUPPORTED, getClass());
getCharPositionInLine(), SpelMessages.SETVALUE_NOT_SUPPORTED, getClass(), getTokenName());
} }
protected String getTokenName() { public SpelNode getChild(int index) {
if (getToken() == null) { return children[index];
return "UNKNOWN";
}
return SpringExpressionsParser.tokenNames[getToken().getType()];
} }
@Override public int getChildCount() {
public SpelNodeImpl getChild(int index) { return children.length;
return (SpelNodeImpl) super.getChild(index);
} }
public Class<?> getObjectClass(Object obj) { public Class<?> getObjectClass(Object obj) {
@ -97,13 +95,16 @@ public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Seria
return (T) result; return (T) result;
} }
public int getStartPosition() {
return getCharPositionInLine();
}
public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException; public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException;
public abstract String toStringAST(); public abstract String toStringAST();
public int getStartPosition() {
return (pos>>16);
}
public int getEndPosition() {
return (pos&0xffff);
}
} }

View File

@ -1,139 +0,0 @@
/*
* Copyright 2002-2009 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.expression.spel.ast;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTreeAdaptor;
import org.springframework.expression.spel.generated.SpringExpressionsLexer;
/**
* @author Andy Clement
* @since 3.0
*/
public class SpelTreeAdaptor extends CommonTreeAdaptor {
@Override
public Object create(Token payload) {
if (payload != null) {
switch (payload.getType()) {
case SpringExpressionsLexer.TRUE:
return new BooleanLiteral(payload, true);
case SpringExpressionsLexer.FALSE:
return new BooleanLiteral(payload, false);
case SpringExpressionsLexer.OR:
return new OperatorOr(payload);
case SpringExpressionsLexer.AND:
return new OperatorAnd(payload);
case SpringExpressionsLexer.BANG:
return new OperatorNot(payload);
case SpringExpressionsLexer.REAL_LITERAL:
return new RealLiteral(payload);
case SpringExpressionsLexer.INTEGER_LITERAL:
return Literal.getIntLiteral(payload, 10);
case SpringExpressionsLexer.HEXADECIMAL_INTEGER_LITERAL:
return Literal.getIntLiteral(payload, 16);
case SpringExpressionsLexer.NOT_EQUAL:
return new OperatorInequality(payload);
case SpringExpressionsLexer.EQUAL:
return new OperatorEquality(payload);
case SpringExpressionsLexer.GREATER_THAN:
return new OperatorGreaterThan(payload);
case SpringExpressionsLexer.LESS_THAN:
return new OperatorLessThan(payload);
case SpringExpressionsLexer.LESS_THAN_OR_EQUAL:
return new OperatorLessThanOrEqual(payload);
case SpringExpressionsLexer.GREATER_THAN_OR_EQUAL:
return new OperatorGreaterThanOrEqual(payload);
case SpringExpressionsLexer.PLUS:
return new OperatorPlus(payload);
case SpringExpressionsLexer.MINUS:
return new OperatorMinus(payload);
case SpringExpressionsLexer.STAR/* MULTIPLY */:
return new OperatorMultiply(payload);
case SpringExpressionsLexer.DIV/* DIVIDE */:
return new OperatorDivide(payload);
case SpringExpressionsLexer.MOD:
return new OperatorModulus(payload);
case SpringExpressionsLexer.POWER:
return new OperatorPower(payload);
case SpringExpressionsLexer.STRING_LITERAL:
case SpringExpressionsLexer.DQ_STRING_LITERAL:
return new StringLiteral(payload);
case SpringExpressionsLexer.NULL_LITERAL:
return new NullLiteral(payload);
case SpringExpressionsLexer.ID:
return new Identifier(payload);
case SpringExpressionsLexer.PROPERTY_OR_FIELD:
return new PropertyOrFieldReference(payload);
case SpringExpressionsLexer.METHOD:
return new MethodReference(payload);
case SpringExpressionsLexer.QUALIFIED_IDENTIFIER:
return new QualifiedIdentifier(payload);
case SpringExpressionsLexer.TYPEREF:
return new TypeReference(payload);
case SpringExpressionsLexer.EXPRESSION:
return new CompoundExpression(payload);
case SpringExpressionsLexer.CONSTRUCTOR:
return new ConstructorReference(payload);
case SpringExpressionsLexer.VARIABLEREF:
return new VariableReference(payload);
case SpringExpressionsLexer.FUNCTIONREF:
return new FunctionReference(payload);
case SpringExpressionsLexer.PROJECT:
return new Projection(payload);
case SpringExpressionsLexer.SELECT:
return new Selection(payload, Selection.ALL);
case SpringExpressionsLexer.SELECT_FIRST:
return new Selection(payload, Selection.FIRST);
case SpringExpressionsLexer.SELECT_LAST:
return new Selection(payload, Selection.LAST);
case SpringExpressionsLexer.ASSIGN:
return new Assign(payload);
case SpringExpressionsLexer.QMARK:
return new Ternary(payload);
case SpringExpressionsLexer.INDEXER:
return new Indexer(payload);
case SpringExpressionsLexer.BETWEEN:
return new OperatorBetween(payload);
case SpringExpressionsLexer.MATCHES:
return new OperatorMatches(payload);
case SpringExpressionsLexer.INSTANCEOF:
return new OperatorInstanceof(payload);
case SpringExpressionsLexer.DOT:
return new Dot(payload);
default:
throw new RuntimeException("Not implemented for '" + payload + "' " + getToken(payload) + "' "
+ payload.getType());
}
}
return new EmptySpelNode(payload);
}
}

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
/** /**
@ -28,12 +27,11 @@ public class StringLiteral extends Literal {
private final TypedValue value; private final TypedValue value;
public StringLiteral(Token payload) { public StringLiteral(String payload, int pos, String value) {
super(payload); super(payload,pos);
String val = payload.getText();
// TODO should these have been skipped being created by the parser rules? or not? // TODO should these have been skipped being created by the parser rules? or not?
val = val.substring(1, val.length() - 1); value = value.substring(1, value.length() - 1);
this.value = new TypedValue(val.replaceAll("''", "'"),STRING_TYPE_DESCRIPTOR); this.value = new TypedValue(value.replaceAll("''", "'"),STRING_TYPE_DESCRIPTOR);
} }
@Override @Override

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
@ -30,8 +29,9 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class Ternary extends SpelNodeImpl { public class Ternary extends SpelNodeImpl {
public Ternary(Token payload) {
super(payload); public Ternary(int pos, SpelNodeImpl... args) {
super(pos,args);
} }
/** /**
@ -42,11 +42,11 @@ public class Ternary extends SpelNodeImpl {
*/ */
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Boolean value = getChild(0).getValue(state, Boolean.class); Boolean value = children[0].getValue(state, Boolean.class);
if (value.booleanValue()) { if (value.booleanValue()) {
return getChild(1).getValueInternal(state); return children[1].getValueInternal(state);
} else { } else {
return getChild(2).getValueInternal(state); return children[2].getValueInternal(state);
} }
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
@ -28,14 +27,14 @@ import org.springframework.expression.spel.ExpressionState;
*/ */
public class TypeReference extends SpelNodeImpl { public class TypeReference extends SpelNodeImpl {
public TypeReference(Token payload) { public TypeReference(int pos,SpelNodeImpl qualifiedId) {
super(payload); super(pos,qualifiedId);
} }
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
// TODO possible optimization here if we cache the discovered type reference, but can we do that? // TODO possible optimization here if we cache the discovered type reference, but can we do that?
String typename = (String) getChild(0).getValueInternal(state).getValue(); String typename = (String) children[0].getValueInternal(state).getValue();
if (typename.indexOf(".") == -1 && Character.isLowerCase(typename.charAt(0))) { if (typename.indexOf(".") == -1 && Character.isLowerCase(typename.charAt(0))) {
TypeCode tc = TypeCode.valueOf(typename.toUpperCase()); TypeCode tc = TypeCode.valueOf(typename.toUpperCase());
if (tc != TypeCode.OBJECT) { if (tc != TypeCode.OBJECT) {

View File

@ -16,10 +16,9 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.antlr.runtime.Token;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
/** /**
* Represents a variable reference, eg. #someVar. Note this is different to a *local* variable like $someVar * Represents a variable reference, eg. #someVar. Note this is different to a *local* variable like $someVar
@ -36,14 +35,14 @@ public class VariableReference extends SpelNodeImpl {
private final String name; private final String name;
public VariableReference(Token payload) { public VariableReference(String variableName, int pos) {
super(payload); super(pos);
this.name = payload.getText(); name = variableName;
} }
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws SpelException { public TypedValue getValueInternal(ExpressionState state) throws SpelEvaluationException {
if (this.name.equals(THIS)) { if (this.name.equals(THIS)) {
return state.getActiveContextObject(); return state.getActiveContextObject();
} }
@ -56,7 +55,7 @@ public class VariableReference extends SpelNodeImpl {
} }
@Override @Override
public void setValue(ExpressionState state, Object value) throws SpelException { public void setValue(ExpressionState state, Object value) throws SpelEvaluationException {
state.setVariable(this.name, value); state.setVariable(this.name, value);
} }
@ -66,7 +65,7 @@ public class VariableReference extends SpelNodeImpl {
} }
@Override @Override
public boolean isWritable(ExpressionState expressionState) throws SpelException { public boolean isWritable(ExpressionState expressionState) throws SpelEvaluationException {
return !(this.name.equals(THIS) || this.name.equals(ROOT)); return !(this.name.equals(THIS) || this.name.equals(ROOT));
} }

View File

@ -1,74 +0,0 @@
SIGN=76
DOLLAR=71
DECIMAL_DIGIT=52
APOS=68
TYPEREF=13
HEXADECIMAL_INTEGER_LITERAL=48
STAR=29
MOD=31
VARIABLEREF=14
AND=26
ID=36
SUBTRACT=17
UPTO=73
LPAREN=23
TYPE=44
HOLDER=10
AT=72
LBRACKET=38
QUALIFIED_IDENTIFIER=6
RPAREN=24
STRING_LITERAL=45
MATCHES=63
REAL_LITERAL=49
NOT_EQUAL=56
COMMA=37
FUNCTIONREF=12
EQUAL=55
PIPE=67
PLUS=27
RBRACKET=39
DOT=34
SELECT=41
EXPRESSION=5
ADD=16
LESS_THAN_OR_EQUAL=58
GREATER_THAN=59
POUND=35
PROJECT=40
SELECT_LAST=43
DEFAULT=20
NUMBER=18
REAL_TYPE_SUFFIX=75
HEX_DIGIT=54
POWER=32
LCURLY=65
NULL_LITERAL=47
PROPERTY_OR_FIELD=7
BANG=33
INSTANCEOF=61
MINUS=28
SEMI=64
TRUE=50
COLON=22
GREATER_THAN_OR_EQUAL=60
WS=70
DOT_ESCAPED=69
DQ_STRING_LITERAL=46
INTEGER_LITERAL=4
RCURLY=66
INDEXER=8
OR=25
LESS_THAN=57
ASSIGN=19
NAMED_ARGUMENT=11
SELECT_FIRST=42
DIV=30
FALSE=51
EXPONENT_PART=74
BETWEEN=62
INTEGER_TYPE_SUFFIX=53
METHOD=15
CONSTRUCTOR=9
QMARK=21
'new'=77

View File

@ -1,142 +0,0 @@
lexer grammar SpringExpressions;
options {
language=Java;
}
@header {package org.springframework.expression.spel.generated;}
T77 : 'new' ;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 183
INTEGER_LITERAL
: (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 186
HEXADECIMAL_INTEGER_LITERAL : ('0x' | '0X') (HEX_DIGIT)+ (INTEGER_TYPE_SUFFIX)?;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 200
ASSIGN: '=';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 201
EQUAL: '==';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 202
NOT_EQUAL: '!=';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 203
LESS_THAN: '<';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 204
LESS_THAN_OR_EQUAL: '<=';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 205
GREATER_THAN: '>';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 206
GREATER_THAN_OR_EQUAL: '>=';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 207
INSTANCEOF: 'instanceof';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 208
BETWEEN:'between';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 209
MATCHES:'matches';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 210
NULL_LITERAL: 'null';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 212
SEMI: ';';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 213
DOT: '.';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 214
COMMA: ',';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 215
LPAREN: '(';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 216
RPAREN: ')';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 217
LCURLY: '{';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 218
RCURLY: '}';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 219
LBRACKET: '[';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 220
RBRACKET: ']';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 221
PIPE: '|';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 223
AND: 'and';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 224
OR: 'or';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 225
FALSE: 'false';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 226
TRUE: 'true';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 228
PLUS: '+';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 229
MINUS: '-';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 230
DIV: '/';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 231
STAR: '*';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 232
MOD: '%';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 233
POWER: '^';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 234
BANG: '!';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 235
POUND: '#';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 236
QMARK: '?';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 237
DEFAULT: '??';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 238
PROJECT: '![';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 239
SELECT: '?[';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 240
SELECT_FIRST: '^[';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 241
SELECT_LAST: '$[';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 242
TYPE: 'T(';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 244
STRING_LITERAL: '\''! (APOS|~'\'')* '\''!;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 245
DQ_STRING_LITERAL: '"'! (~'"')* '"'!;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 246
ID: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|DOT_ESCAPED)*;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 247
DOT_ESCAPED: '\\.';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 248
WS: ( ' ' | '\t' | '\n' |'\r')+ { $channel=HIDDEN; } ;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 249
DOLLAR: '$';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 250
AT: '@';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 251
UPTO: '..';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 252
COLON: ':';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 255
REAL_LITERAL :
('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) |
((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX));
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 261
fragment APOS : '\''! '\'';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 262
fragment DECIMAL_DIGIT : '0'..'9' ;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 263
fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' );
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 264
fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f';
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 266
fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 267
fragment SIGN : '+' | '-' ;
// $ANTLR src "F:\svn\sfw2\org.springframework.expression\src\main\java\org\springframework\expression\spel\generated\SpringExpressions.g" 268
fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd';

View File

@ -13,32 +13,25 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.expression.spel.standard;
package org.springframework.expression.spel.ast; import org.springframework.expression.spel.SpelParseException;
import org.antlr.runtime.Token;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException;
/** /**
* Wraps a real parse exception. This exception flows to the top parse method and then
* the wrapped exception is thrown as the real problem.
*
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @since 3.0
*/ */
public class EmptySpelNode extends SpelNodeImpl { public class InternalParseException extends RuntimeException {
public EmptySpelNode(Token payload) { public InternalParseException(SpelParseException t) {
super(payload); super(t);
} }
@Override public SpelParseException getCause() {
public TypedValue getValueInternal(ExpressionState state) throws SpelException { return (SpelParseException)super.getCause();
throw new RuntimeException("?");
}
@Override
public String toStringAST() {
return "<no string form node '" + getTokenName() + "'>";
} }
} }

View File

@ -0,0 +1,745 @@
/*
* Copyright 2008-2009 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.expression.spel.standard;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import org.springframework.expression.ParseException;
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;
import org.springframework.expression.spel.ast.CompoundExpression;
import org.springframework.expression.spel.ast.ConstructorReference;
import org.springframework.expression.spel.ast.Elvis;
import org.springframework.expression.spel.ast.FunctionReference;
import org.springframework.expression.spel.ast.Identifier;
import org.springframework.expression.spel.ast.Indexer;
import org.springframework.expression.spel.ast.Literal;
import org.springframework.expression.spel.ast.MethodReference;
import org.springframework.expression.spel.ast.NullLiteral;
import org.springframework.expression.spel.ast.OpEQ;
import org.springframework.expression.spel.ast.OpGE;
import org.springframework.expression.spel.ast.OpGT;
import org.springframework.expression.spel.ast.OpLE;
import org.springframework.expression.spel.ast.OpLT;
import org.springframework.expression.spel.ast.OpNE;
import org.springframework.expression.spel.ast.OperatorAnd;
import org.springframework.expression.spel.ast.OperatorDivide;
import org.springframework.expression.spel.ast.OperatorInstanceof;
import org.springframework.expression.spel.ast.OperatorMatches;
import org.springframework.expression.spel.ast.OperatorMinus;
import org.springframework.expression.spel.ast.OperatorModulus;
import org.springframework.expression.spel.ast.OperatorMultiply;
import org.springframework.expression.spel.ast.OperatorNot;
import org.springframework.expression.spel.ast.OperatorOr;
import org.springframework.expression.spel.ast.OperatorPlus;
import org.springframework.expression.spel.ast.OperatorPower;
import org.springframework.expression.spel.ast.Projection;
import org.springframework.expression.spel.ast.PropertyOrFieldReference;
import org.springframework.expression.spel.ast.QualifiedIdentifier;
import org.springframework.expression.spel.ast.Selection;
import org.springframework.expression.spel.ast.SpelNodeImpl;
import org.springframework.expression.spel.ast.StringLiteral;
import org.springframework.expression.spel.ast.Ternary;
import org.springframework.expression.spel.ast.TypeReference;
import org.springframework.expression.spel.ast.VariableReference;
/**
* Hand written SpEL parser. Instances are reusable.
*
* @author Andy Clement
* @since 3.0
*/
public class SpelExpressionParser extends TemplateAwareExpressionParser {
// The expression being parsed
private String expressionString;
// The token stream constructed from that expression string
private List<Token> tokenStream;
// length of a populated token stream
private int tokenStreamLength;
// Current location in the token stream when processing tokens
private int tokenStreamPointer;
// For rules that build nodes, they are stacked here for return
private Stack<SpelNodeImpl> constructedNodes = new Stack<SpelNodeImpl>();
public SpelExpressionParser() {
}
public SpelExpression parse(String expressionString) throws ParseException {
return doParseExpression(expressionString, null);
}
protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
try {
Tokenizer tokenizer = new Tokenizer(expressionString);
tokenizer.process();
this.expressionString = expressionString;
tokenStream = tokenizer.getTokens();
tokenStreamLength = tokenStream.size();
tokenStreamPointer = 0;
constructedNodes.clear();
SpelNode ast = eatExpression();
if (moreTokens()) {
throw new SpelParseException(peekToken().startpos,SpelMessages.MORE_INPUT,toString(nextToken()));
}
assert constructedNodes.isEmpty();
return new SpelExpression(expressionString,ast);
} catch (InternalParseException ipe) {
throw ipe.getCause();
}
}
public String toString(Token t) {
if (t.getKind().hasPayload()) {
return t.stringValue();
} else {
return t.kind.toString().toLowerCase();
}
}
// expression
// : logicalOrExpression
// ( (ASSIGN^ logicalOrExpression)
// | (DEFAULT^ logicalOrExpression)
// | (QMARK^ expression COLON! expression))?;
private SpelNodeImpl eatExpression() {
SpelNodeImpl expr = eatLogicalOrExpression();
if (moreTokens()) {
Token t = peekToken();
if (t.kind==TokenKind.ASSIGN) { // a=b
nextToken();
SpelNodeImpl assignedValue = eatLogicalOrExpression();
return new Assign(toPos(t),expr,assignedValue);
} else if (t.kind==TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b)
nextToken(); // elvis has left the building
SpelNodeImpl valueIfNull = eatLogicalOrExpression();
return new Elvis(toPos(t),expr,valueIfNull);
} else if (t.kind==TokenKind.QMARK) { // a?b:c
nextToken();
SpelNodeImpl ifTrueExprValue = eatLogicalOrExpression();
eatToken(TokenKind.COLON);
SpelNodeImpl ifFalseExprValue = eatLogicalOrExpression();
return new Ternary(toPos(t),expr,ifTrueExprValue,ifFalseExprValue);
}
}
return expr;
}
//logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*;
private SpelNodeImpl eatLogicalOrExpression() {
SpelNodeImpl expr = eatLogicalAndExpression();
while (peekIdentifierToken("or")) {
Token t = nextToken();//consume OR
SpelNodeImpl expr2 = eatLogicalAndExpression();
checkRightOperand(t,expr2);
expr = new OperatorOr(toPos(t),expr,expr2);
}
return expr;
}
private void checkRightOperand(Token token, SpelNodeImpl operandExpression) {
if (operandExpression==null) {
throw new InternalParseException(new SpelParseException(token.startpos,SpelMessages.RIGHT_OPERAND_PROBLEM));
}
}
//logicalAndExpression : relationalExpression (AND^ relationalExpression)*;
private SpelNodeImpl eatLogicalAndExpression() {
SpelNodeImpl expr = eatRelationalExpression();
while (peekIdentifierToken("and")) {
Token t = nextToken();// consume 'AND'
SpelNodeImpl rightExpr = eatRelationalExpression();
checkRightOperand(t,rightExpr);
expr = new OperatorAnd(toPos(t),expr,rightExpr);
}
return expr;
}
//relationalExpression : sumExpression (relationalOperator^ sumExpression)?;
private SpelNodeImpl eatRelationalExpression() {
SpelNodeImpl expr = eatSumExpression();
Token relationalOperatorToken = maybeEatRelationalOperator();
if (relationalOperatorToken!=null) {
Token t = nextToken();//consume relational operator token
SpelNodeImpl expr2 = eatSumExpression();
checkRightOperand(t,expr2);
if (relationalOperatorToken.isNumericRelationalOperator()) {
if (relationalOperatorToken.isGreaterThan()) {
return new OpGT(toPos(t),expr,expr2);
} else if (relationalOperatorToken.isLessThan()) {
return new OpLT(toPos(t),expr,expr2);
} else if (relationalOperatorToken.isLessThanOrEqual()) {
return new OpLE(toPos(t),expr,expr2);
} else if (relationalOperatorToken.isGreaterThanOrEqual()) {
return new OpGE(toPos(t),expr,expr2);
} else if (relationalOperatorToken.isEquality()) {
return new OpEQ(toPos(t),expr,expr2);
} else {
assert relationalOperatorToken.kind==TokenKind.NE;
return new OpNE(toPos(t),expr,expr2);
}
}
if (relationalOperatorToken.kind==TokenKind.INSTANCEOF) {
return new OperatorInstanceof(toPos(t),expr,expr2);
} else if (relationalOperatorToken.kind==TokenKind.MATCHES) {
return new OperatorMatches(toPos(t),expr,expr2);
} else {
assert relationalOperatorToken.kind==TokenKind.BETWEEN;
return new org.springframework.expression.spel.ast.OperatorBetween(toPos(t),expr,expr2);
}
}
return expr;
}
//sumExpression: productExpression ( (PLUS^ | MINUS^) productExpression)*;
private SpelNodeImpl eatSumExpression() {
SpelNodeImpl expr = eatProductExpression();
while (peekToken(TokenKind.PLUS,TokenKind.MINUS)) {
Token t = nextToken();//consume PLUS or MINUS
SpelNodeImpl rhOperand = eatProductExpression();
checkRightOperand(t,rhOperand);
if (t.getKind()==TokenKind.PLUS) {
expr = new OperatorPlus(toPos(t),expr,rhOperand);
} else {
expr = new OperatorMinus(toPos(t),expr,rhOperand);
}
}
return expr;
}
//productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ;
private SpelNodeImpl eatProductExpression() {
SpelNodeImpl expr = eatPowerExpression();
while (peekToken(TokenKind.STAR,TokenKind.DIV,TokenKind.MOD)) {
Token t = nextToken(); // consume STAR/DIV/MOD
SpelNodeImpl expr2 = eatPowerExpression();
checkRightOperand(t,expr2);
if (t.getKind()==TokenKind.STAR) {
expr = new OperatorMultiply(toPos(t),expr,expr2);
} else if (t.getKind()==TokenKind.DIV) {
expr = new OperatorDivide(toPos(t),expr,expr2);
} else {
expr = new OperatorModulus(toPos(t),expr,expr2);
}
}
return expr;
}
//powerExpr : unaryExpression (POWER^ unaryExpression)? ;
private SpelNodeImpl eatPowerExpression() {
SpelNodeImpl expr = eatUnaryExpression();
if (peekToken(TokenKind.POWER)) {
Token t = nextToken();//consume POWER
SpelNodeImpl expr2 = eatUnaryExpression();
checkRightOperand(t,expr2);
return new OperatorPower(toPos(t),expr, expr2);
}
return expr;
}
//unaryExpression: (PLUS^ | MINUS^ | BANG^) unaryExpression | primaryExpression ;
private SpelNodeImpl eatUnaryExpression() {
if (peekToken(TokenKind.PLUS) || peekToken(TokenKind.MINUS) || peekToken(TokenKind.BANG)) {
Token t = nextToken();
SpelNodeImpl expr = eatUnaryExpression();
if (t.kind==TokenKind.BANG) {
return new OperatorNot(toPos(t),expr);
} else if (t.kind==TokenKind.PLUS) {
return new OperatorPlus(toPos(t),expr);
} else {
assert t.kind==TokenKind.MINUS;
return new OperatorMinus(toPos(t),expr);
}
} else {
return eatPrimaryExpression();
}
}
//primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?);
private SpelNodeImpl eatPrimaryExpression() {
List<SpelNodeImpl> nodes = new ArrayList<SpelNodeImpl>();
SpelNodeImpl start = eatStartNode();
nodes.add(start);
while (maybeEatNode()) {
nodes.add(pop());
}
if (nodes.size()==1) {
return nodes.get(0);
} else {
return new CompoundExpression(toPos(start.getStartPosition(),nodes.get(nodes.size()-1).getEndPosition()),nodes.toArray(new SpelNodeImpl[nodes.size()]));
}
}
private int toPos(int start,int end) {
return (start<<16)+end;
}
//node : ((DOT dottedNode) | nonDottedNode)+;
private boolean maybeEatNode() {
Token t = peekToken();
SpelNodeImpl expr = null;
if (t!=null && peekToken(TokenKind.DOT,TokenKind.SAFE_NAVI)) {
expr = eatDottedNode();
} else {
expr = maybeEatNonDottedNode();
}
if (expr==null) {
return false;
} else {
push(expr);
return true;
}
}
//nonDottedNode: indexer;
private SpelNodeImpl maybeEatNonDottedNode() {
if (peekToken(TokenKind.LSQUARE)) {
if (maybeEatIndexer()) {
return pop();
}
}
return null;
}
//dottedNode
// : ((methodOrProperty
// | functionOrVar
// | projection
// | selection
// | firstSelection
// | lastSelection
// ))
// ;
private SpelNodeImpl eatDottedNode() {
Token t = nextToken();// it was a '.' or a '?.'
//eatToken(TokenKind.DOT);
boolean nullSafeNavigation = t.kind==TokenKind.SAFE_NAVI;
if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) {
return pop();
}
throw new InternalParseException(new SpelParseException(expressionString,t.startpos,SpelMessages.UNEXPECTED_DATA_AFTER_DOT,toString(peekToken())));
}
// functionOrVar
// : (POUND ID LPAREN) => function
// | var
// ;
//
//function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs);
//
//var : POUND id=ID -> ^(VARIABLEREF[$id]);
private boolean maybeEatFunctionOrVar() {
if (!peekToken(TokenKind.HASH)) {
return false;
}
Token t = nextToken();
Token functionOrVariableName = eatToken(TokenKind.IDENTIFIER);
SpelNodeImpl[] args = maybeEatMethodArgs();
if (args==null) {
push(new VariableReference(functionOrVariableName.data,toPos(t.startpos,functionOrVariableName.endpos)));
return true;
} else {
push(new FunctionReference(functionOrVariableName.data,toPos(t.startpos,functionOrVariableName.endpos),args));
return true;
}
}
//methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!;
private SpelNodeImpl[] maybeEatMethodArgs() {
if (!peekToken(TokenKind.LPAREN)) {
return null;
}
List<SpelNodeImpl> args = new ArrayList<SpelNodeImpl>();
consumeArguments(args);
eatToken(TokenKind.RPAREN);
return args.toArray(new SpelNodeImpl[args.size()]);
}
private void eatConstructorArgs(List<SpelNodeImpl> accumulatedArguments) {
if (!peekToken(TokenKind.LPAREN)) {
throw new InternalParseException(new SpelParseException(expressionString,positionOf(peekToken()),SpelMessages.MISSING_CONSTRUCTOR_ARGS));
}
consumeArguments(accumulatedArguments);
eatToken(TokenKind.RPAREN);
}
/**
* Used for consuming arguments for either a method or a constructor call
*/
private void consumeArguments(List<SpelNodeImpl> accumulatedArguments) {
int pos = peekToken().startpos;
Token next = null;
do {
nextToken();// consume ( (first time through) or comma (subsequent times)
Token t = peekToken();
if (t==null) {
raiseInternalException(pos,SpelMessages.RUN_OUT_OF_ARGUMENTS);
}
if (t.kind!=TokenKind.RPAREN) {
accumulatedArguments.add(eatExpression());
}
next = peekToken();
} while (next!=null && next.kind==TokenKind.COMMA);
if (next==null) {
raiseInternalException(pos,SpelMessages.RUN_OUT_OF_ARGUMENTS);
}
}
private int positionOf(Token t) {
if (t==null) {
// if null assume the problem is because the right token was
// not found at the end of the expression
return expressionString.length();
} else {
return t.startpos;
}
}
//startNode
// : parenExpr | literal
// | type
// | methodOrProperty
// | functionOrVar
// | projection
// | selection
// | firstSelection
// | lastSelection
// | indexer
// | constructor
private SpelNodeImpl eatStartNode() {
if (maybeEatLiteral()) {
return pop();
} else if (maybeEatParenExpression()) {
return pop();
} else if (maybeEatTypeReference() || maybeEatNullReference() || maybeEatConstructorReference() || maybeEatMethodOrProperty(false) || maybeEatFunctionOrVar()) {
return pop();
} else if (maybeEatProjection(false) || maybeEatSelection(false) || maybeEatIndexer()) {
return pop();
} else {
return null;
}
}
private boolean maybeEatTypeReference() {
if (peekToken(TokenKind.IDENTIFIER)) {
Token typeName = peekToken();
if (!typeName.stringValue().equals("T")) {
return false;
}
nextToken();
eatToken(TokenKind.LPAREN);
SpelNodeImpl node = eatPossiblyQualifiedId();
// dotted qualified id
eatToken(TokenKind.RPAREN);
constructedNodes.push(new TypeReference(toPos(typeName),node));
return true;
}
return false;
}
private boolean maybeEatNullReference() {
if (peekToken(TokenKind.IDENTIFIER)) {
Token nullToken = peekToken();
if (!nullToken.stringValue().equals("null")) {
return false;
}
nextToken();
constructedNodes.push(new NullLiteral(toPos(nullToken)));
return true;
}
return false;
}
//projection: PROJECT^ expression RCURLY!;
private boolean maybeEatProjection(boolean nullSafeNavigation) {
Token t = peekToken();
if (!peekToken(TokenKind.PROJECT)) {
return false;
}
nextToken();
SpelNodeImpl expr = eatExpression();
eatToken(TokenKind.RSQUARE);
constructedNodes.push(new Projection(nullSafeNavigation, toPos(t),expr));
return true;
}
private boolean maybeEatIndexer() {
Token t = peekToken();
if (!peekToken(TokenKind.LSQUARE)) {
return false;
}
nextToken();
SpelNodeImpl expr = eatExpression();
eatToken(TokenKind.RSQUARE);
constructedNodes.push(new Indexer(toPos(t),expr));
return true;
}
private boolean maybeEatSelection(boolean nullSafeNavigation) {
Token t = peekToken();
if (!peekSelectToken()) {
return false;
}
nextToken();
SpelNodeImpl expr = eatExpression();
eatToken(TokenKind.RSQUARE);
if (t.kind==TokenKind.SELECT_FIRST) {
constructedNodes.push(new Selection(nullSafeNavigation,Selection.FIRST,toPos(t),expr));
} else if (t.kind==TokenKind.SELECT_LAST) {
constructedNodes.push(new Selection(nullSafeNavigation,Selection.LAST,toPos(t),expr));
} else {
constructedNodes.push(new Selection(nullSafeNavigation,Selection.ALL,toPos(t),expr));
}
return true;
}
private SpelNodeImpl eatPossiblyQualifiedId() {
List<SpelNodeImpl> qualifiedIdPieces = new ArrayList<SpelNodeImpl>();
Token startnode = eatToken(TokenKind.IDENTIFIER);
qualifiedIdPieces.add(new Identifier(startnode.stringValue(),toPos(startnode)));
while (peekToken(TokenKind.DOT)) {
nextToken();
Token node = eatToken(TokenKind.IDENTIFIER);
qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node)));
}
return new QualifiedIdentifier(toPos(startnode.startpos,qualifiedIdPieces.get(qualifiedIdPieces.size()-1).getEndPosition()),qualifiedIdPieces.toArray(new SpelNodeImpl[qualifiedIdPieces.size()]));
}
private boolean maybeEatMethodOrProperty(boolean nullSafeNavigation) {
if (peekToken(TokenKind.IDENTIFIER)) {
Token methodOrPropertyName = nextToken();
SpelNodeImpl[] args = maybeEatMethodArgs();
if (args==null) {
// property
push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName)));
return true;
} else {
// methodreference
push(new MethodReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName),args));
// TODO what is the end position for a method reference? the name or the last arg?
return true;
}
}
return false;
}
//constructor
// : ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs)
// ;
private boolean maybeEatConstructorReference() {
if (peekIdentifierToken("new")) {
Token newToken = nextToken();
SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId();
List<SpelNodeImpl> nodes = new ArrayList<SpelNodeImpl>();
nodes.add(possiblyQualifiedConstructorName);
eatConstructorArgs(nodes);
push(new ConstructorReference(toPos(newToken),nodes.toArray(new SpelNodeImpl[nodes.size()]))); // TODO correct end position?
return true;
}
return false;
}
private void push(SpelNodeImpl newNode) {
constructedNodes.push(newNode);
}
private SpelNodeImpl pop() {
return constructedNodes.pop();
}
// literal:
// INTEGER_LITERAL
// | boolLiteral
// | STRING_LITERAL
// | HEXADECIMAL_INTEGER_LITERAL
// | REAL_LITERAL
// | DQ_STRING_LITERAL
// | NULL_LITERAL
// ;
private boolean maybeEatLiteral() {
Token t = peekToken();
if (t==null) {
return false;
}
if (t.kind==TokenKind.LITERAL_INT) {
nextToken();
push(Literal.getIntLiteral(t.data, toPos(t), 10));
return true;
} else if (t.kind==TokenKind.LITERAL_LONG) {
nextToken();
push(Literal.getLongLiteral(t.data, toPos(t), 10));
return true;
} else if (t.kind==TokenKind.LITERAL_HEXINT) {
nextToken();
push(Literal.getIntLiteral(t.data, toPos(t), 16));
return true;
} else if (t.kind==TokenKind.LITERAL_HEXLONG) {
nextToken();
push(Literal.getLongLiteral(t.data, toPos(t), 16));
return true;
} else if (t.kind==TokenKind.LITERAL_REAL) {
nextToken();
push(Literal.getRealLiteral(t.data, toPos(t),false));
return true;
} else if (t.kind==TokenKind.LITERAL_REAL_FLOAT) {
nextToken();
push(Literal.getRealLiteral(t.data, toPos(t), true));
return true;
} else if (peekIdentifierToken("true")) {
nextToken();
push(new BooleanLiteral(t.data,toPos(t),true));
return true;
} else if (peekIdentifierToken("false")) {
nextToken();
push(new BooleanLiteral(t.data,toPos(t),false));
return true;
} else if (t.kind==TokenKind.LITERAL_STRING) {
nextToken();
push(new StringLiteral(t.data,toPos(t),t.data));
return true;
}
return false;
}
private int toPos(Token t) {
return (t.startpos<<16)+t.endpos;
}
//parenExpr : LPAREN! expression RPAREN!;
private boolean maybeEatParenExpression() {
if (peekToken(TokenKind.LPAREN)) {
nextToken();
SpelNodeImpl expr = eatExpression();
eatToken(TokenKind.RPAREN);
push(expr);
return true;
} else {
return false;
}
}
// relationalOperator
// : EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN | GREATER_THAN_OR_EQUAL | INSTANCEOF
// | BETWEEN | MATCHES
private Token maybeEatRelationalOperator() {
Token t = peekToken();
if (t==null) {
return null;
}
if (t.isNumericRelationalOperator()) {
return t;
}
if (t.isIdentifier()) {
String idString = t.stringValue();
if (idString.equalsIgnoreCase("instanceof")) {
return t.asInstanceOfToken();
} else if (idString.equalsIgnoreCase("matches")) {
return t.asMatchesToken();
} else if (idString.equalsIgnoreCase("between")) {
return t.asBetweenToken();
}
}
return null;
}
private Token eatToken(TokenKind expectedKind) {
assert moreTokens();
Token t = nextToken();
if (t==null) {
raiseInternalException( expressionString.length(), SpelMessages.OOD);
}
if (t.kind!=expectedKind) {
raiseInternalException(t.startpos,SpelMessages.NOT_EXPECTED_TOKEN, expectedKind.toString().toLowerCase(),t.getKind().toString().toLowerCase());
}
return t;
}
private boolean peekToken(TokenKind desiredTokenKind) {
if (!moreTokens()) return false;
Token t = peekToken();
return t.kind==desiredTokenKind;
}
private boolean peekToken(TokenKind possible1,TokenKind possible2) {
if (!moreTokens()) return false;
Token t = peekToken();
return t.kind==possible1 || t.kind==possible2;
}
private boolean peekToken(TokenKind possible1,TokenKind possible2, TokenKind possible3) {
if (!moreTokens()) return false;
Token t = peekToken();
return t.kind==possible1 || t.kind==possible2 || t.kind==possible3;
}
private boolean peekIdentifierToken(String identifierString) {
if (!moreTokens()) return false;
Token t = peekToken();
return t.kind==TokenKind.IDENTIFIER && t.stringValue().equalsIgnoreCase(identifierString);
}
private boolean peekSelectToken() {
if (!moreTokens()) return false;
Token t = peekToken();
return t.kind==TokenKind.SELECT || t.kind==TokenKind.SELECT_FIRST || t.kind==TokenKind.SELECT_LAST;
}
private boolean moreTokens() {
return tokenStreamPointer<tokenStream.size();
}
private Token nextToken() {
if (tokenStreamPointer>=tokenStreamLength) {
return null;
}
return tokenStream.get(tokenStreamPointer++);
}
private Token peekToken() {
if (tokenStreamPointer>=tokenStreamLength) {
return null;
}
return tokenStream.get(tokenStreamPointer);
}
private void raiseInternalException(int pos, SpelMessages message,Object... inserts) {
throw new InternalParseException(new SpelParseException(expressionString,pos,message,inserts));
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 2002-2009 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.expression.spel.standard;
/**
* Holder for a kind of token, the associated data and its position in the input data stream (start/end).
*
* @author Andy Clement
* @since 3.0
*/
class Token {
TokenKind kind;
String data;
int startpos; // index of first character
int endpos; // index of char after the last character
/**
* Constructor for use when there is no particular data for the token (eg. TRUE or '+')
* @param startpos the exact start
* @param endpos the index to the last character
*/
Token(TokenKind tokenKind, int startpos, int endpos) {
this.kind = tokenKind;
this.startpos = startpos;
this.endpos = endpos;
}
Token(TokenKind tokenKind, char[] tokenData, int pos, int endpos) {
this(tokenKind,pos,endpos);
this.data = new String(tokenData);
}
public TokenKind getKind() {
return kind;
}
public String toString() {
StringBuilder s = new StringBuilder();
s.append("[").append(kind.toString());
if (kind.hasPayload()) {
s.append(":").append(data);
}
s.append("]");
s.append("(").append(startpos).append(",").append(endpos).append(")");
return s.toString();
}
public boolean isIdentifier() {
return kind==TokenKind.IDENTIFIER;
}
public boolean isGreaterThan() {
return kind==TokenKind.GT;
}
public boolean isLessThan() {
return kind==TokenKind.LT;
}
public boolean isGreaterThanOrEqual() {
return kind==TokenKind.GE;
}
public boolean isEquality() {
return kind==TokenKind.EQ;
}
public boolean isLessThanOrEqual() {
return kind==TokenKind.LE;
}
public boolean isInstanceOf() {
return kind==TokenKind.INSTANCEOF;
}
public boolean isNumericRelationalOperator() {
return kind==TokenKind.GT || kind==TokenKind.GE || kind==TokenKind.LT || kind==TokenKind.LE || kind==TokenKind.EQ || kind==TokenKind.NE;
}
public String stringValue() {
return data;
}
public Token asInstanceOfToken() {
return new Token(TokenKind.INSTANCEOF,startpos,endpos);
}
public Token asMatchesToken() {
return new Token(TokenKind.MATCHES,startpos,endpos);
}
public Token asBetweenToken() {
return new Token(TokenKind.BETWEEN,startpos,endpos);
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2002-2009 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.expression.spel.standard;
/**
* @author Andy Clement
* @since 3.0
*/
enum TokenKind {
// ordered by priority - operands first
LITERAL_INT, LITERAL_LONG, LITERAL_HEXINT, LITERAL_HEXLONG, LITERAL_STRING, LITERAL_REAL, LITERAL_REAL_FLOAT,
LPAREN("("), RPAREN(")"), COMMA(","), IDENTIFIER,
COLON(":"),HASH("#"),RSQUARE("]"), LSQUARE("["),
DOT("."), PLUS("+"), STAR("*"), DIV("/"), BANG("!"), MINUS("-"), SELECT_FIRST("^["), SELECT_LAST("$["), QMARK("?"), PROJECT("!["),
GE(">="),GT(">"),LE("<="),LT("<"),EQ("=="),NE("!="),ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"),
SELECT("?["), MOD("%"), POWER("^"), DOLLAR("$"),
ELVIS("?:"), SAFE_NAVI("?.");
;
char[] tokenChars;
private boolean hasPayload; // is there more to this token than simply the kind
private TokenKind(String tokenString) {
tokenChars = tokenString.toCharArray();
hasPayload = tokenChars.length==0;
}
private TokenKind() {
this("");
}
public String toString() {
return this.name()+(tokenChars.length!=0?"("+new String(tokenChars)+")":"");
}
public boolean hasPayload() {
return hasPayload;
}
}

View File

@ -0,0 +1,474 @@
/*
* Copyright 2002-2009 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.expression.spel.standard;
import java.util.ArrayList;
import java.util.List;
import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.SpelParseException;
/**
* Lex some input data into a stream of tokens that can then be parsed.
*
* @author Andy Clement
* @since 3.0
*/
public class Tokenizer {
String expressionString;
char[] toProcess;
int pos;
int max;
List<Token> tokens = new ArrayList<Token>();
public Tokenizer(String inputdata) {
this.expressionString = inputdata;
this.toProcess = (inputdata+"\0").toCharArray();
this.max = toProcess.length;
this.pos = 0;
process();
}
public void process() {
while (pos<max) {
char ch = toProcess[pos];
if (isAlphabetic(ch)) {
lexIdentifier();
} else {
switch (ch) {
case '+':
pushCharToken(TokenKind.PLUS);
break;
case '-':
pushCharToken(TokenKind.MINUS);
break;
case ':':
pushCharToken(TokenKind.COLON);
break;
case '.':
pushCharToken(TokenKind.DOT);
break;
case ',':
pushCharToken(TokenKind.COMMA);
break;
case '*':
pushCharToken(TokenKind.STAR);
break;
case '/':
pushCharToken(TokenKind.DIV);
break;
case '%':
pushCharToken(TokenKind.MOD);
break;
case '(':
pushCharToken(TokenKind.LPAREN);
break;
case ')':
pushCharToken(TokenKind.RPAREN);
break;
case '[':
pushCharToken(TokenKind.LSQUARE);
break;
case '#':
pushCharToken(TokenKind.HASH);
break;
case ']':
pushCharToken(TokenKind.RSQUARE);
break;
case '^':
if (isTwoCharToken(TokenKind.SELECT_FIRST)) {
pushPairToken(TokenKind.SELECT_FIRST);
} else {
pushCharToken(TokenKind.POWER);
}
break;
case '!':
if (isTwoCharToken(TokenKind.NE)) {
pushPairToken(TokenKind.NE);
} else if (isTwoCharToken(TokenKind.PROJECT)) {
pushPairToken(TokenKind.PROJECT);
} else {
pushCharToken(TokenKind.BANG);
}
break;
case '=':
if (isTwoCharToken(TokenKind.EQ)) {
pushPairToken(TokenKind.EQ);
} else {
pushCharToken(TokenKind.ASSIGN);
}
break;
case '?':
if (isTwoCharToken(TokenKind.SELECT)) {
pushPairToken(TokenKind.SELECT);
} else if (isTwoCharToken(TokenKind.ELVIS)) {
pushPairToken(TokenKind.ELVIS);
} else if (isTwoCharToken(TokenKind.SAFE_NAVI)) {
pushPairToken(TokenKind.SAFE_NAVI);
} else {
pushCharToken(TokenKind.QMARK);
}
break;
case '$':
if (isTwoCharToken(TokenKind.SELECT_LAST)) {
pushPairToken(TokenKind.SELECT_LAST);
} else {
pushCharToken(TokenKind.DOLLAR);
}
break;
case '>':
if (isTwoCharToken(TokenKind.GE)) {
pushPairToken(TokenKind.GE);
} else {
pushCharToken(TokenKind.GT);
}
break;
case '<':
if (isTwoCharToken(TokenKind.LE)) {
pushPairToken(TokenKind.LE);
} else {
pushCharToken(TokenKind.LT);
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
lexNumericLiteral(ch=='0');
break;
case ' ':
case '\t':
case '\r':
case '\n':
// drift over white space
pos++;
break;
case '\'':
lexQuotedStringLiteral();
break;
case '"':
lexDoubleQuotedStringLiteral();
break;
case 0:
// hit sentinel at end of value
pos++; // will take us to the end
break;
default:
throw new IllegalStateException("Cannot handle ("+Integer.valueOf(ch)+") '"+ch+"'");
}
}
}
}
public List<Token> getTokens() {
return tokens;
}
// STRING_LITERAL: '\''! (APOS|~'\'')* '\''!;
private void lexQuotedStringLiteral() {
int start = pos;
boolean terminated = false;
while (!terminated) {
pos++;
char ch = toProcess[pos];
if (ch=='\'') {
// may not be the end if the char after is also a '
if (toProcess[pos+1]=='\'') {
pos++; // skip over that too, and continue
} else {
terminated = true;
}
}
if (ch==0) {
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessages.NON_TERMINATING_QUOTED_STRING));
}
}
pos++;
tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos));
}
// DQ_STRING_LITERAL: '"'! (~'"')* '"'!;
private void lexDoubleQuotedStringLiteral() {
int start = pos;
boolean terminated = false;
while (!terminated) {
pos++;
char ch = toProcess[pos];
if (ch=='"') {
terminated = true;
}
if (ch==0) {
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessages.NON_TERMINATING_DOUBLE_QUOTED_STRING));
}
}
pos++;
tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos));
}
// REAL_LITERAL :
// ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
// ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
// ((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) |
// ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX));
// fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' );
// fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f';
//
// fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ;
// fragment SIGN : '+' | '-' ;
// fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd';
// INTEGER_LITERAL
// : (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?;
private void lexNumericLiteral(boolean firstCharIsZero) {
boolean isReal = false;
int start = pos;
char ch = toProcess[pos+1];
boolean isHex = ch=='x' || ch=='X';
// deal with hexadecimal
if (firstCharIsZero && isHex) {
pos=pos+1;
do {
pos++;
} while (isHexadecimalDigit(toProcess[pos]));
if (isChar('L','l')) {
pushHexIntToken(subarray(start+2,pos),true, start, pos);
pos++;
} else {
pushHexIntToken(subarray(start+2,pos),false, start, pos);
}
return;
}
// real numbers must have leading digits
// Consume first part of number
do {
pos++;
} while (isDigit(toProcess[pos]));
// a '.' indicates this number is a real
ch = toProcess[pos];
if (ch=='.') {
isReal = true;
// carry on consuming digits
do {
pos++;
} while (isDigit(toProcess[pos]));
}
int endOfNumber = pos;
// Now there may or may not be an exponent
// is it a long ?
if (isChar('L','l')) {
if (isReal) { // 3.4L - not allowed
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessages.REAL_CANNOT_BE_LONG));
}
pushIntToken(subarray(start, endOfNumber), true, start, endOfNumber);
pos++;
} else if (isExponentChar(toProcess[pos])) {
isReal = true; // if it wasnt before, it is now
pos++;
char possibleSign = toProcess[pos];
if (isSign(possibleSign)) {
pos++;
}
// exponent digits
do {
pos++;
} while (isDigit(toProcess[pos]));
boolean isFloat = false;
if (isFloatSuffix(toProcess[pos])) {
isFloat = true;
endOfNumber = ++pos;
} else if (isDoubleSuffix(toProcess[pos])) {
endOfNumber = ++pos;
}
pushRealToken(subarray(start,pos), isFloat, start, pos);
} else {
ch = toProcess[pos];
boolean isFloat = false;
if (isFloatSuffix(ch)) {
isReal = true;
isFloat = true;
endOfNumber = ++pos;
} else if (isDoubleSuffix(ch)) {
isReal = true;
endOfNumber = ++pos;
}
if (isReal) {
pushRealToken(subarray(start,endOfNumber), isFloat, start, endOfNumber);
} else {
pushIntToken(subarray(start,endOfNumber), false, start, endOfNumber);
}
}
}
private void lexIdentifier() {
int start = pos;
do {
pos++;
} while (isIdentifier(toProcess[pos]));
tokens.add(new Token(TokenKind.IDENTIFIER,subarray(start,pos),start,pos));
}
private void pushIntToken(char[] data,boolean isLong, int start, int end) {
if (isLong) {
tokens.add(new Token(TokenKind.LITERAL_LONG,data, start, end));
} else {
tokens.add(new Token(TokenKind.LITERAL_INT,data, start, end));
}
}
private void pushHexIntToken(char[] data,boolean isLong, int start, int end) {
if (data.length==0) {
if (isLong) {
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessages.NOT_A_LONG,expressionString.substring(start,end+1)));
} else {
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessages.NOT_AN_INTEGER,expressionString.substring(start,end)));
}
}
if (isLong) {
tokens.add(new Token(TokenKind.LITERAL_HEXLONG, data, start, end));
} else {
tokens.add(new Token(TokenKind.LITERAL_HEXINT, data, start, end));
}
}
private void pushRealToken(char[] data, boolean isFloat, int start, int end) {
if (isFloat) {
tokens.add(new Token(TokenKind.LITERAL_REAL_FLOAT, data, start, end));
} else {
tokens.add(new Token(TokenKind.LITERAL_REAL, data, start, end));
}
}
private char[] subarray(int start, int end) {
char[] result = new char[end - start];
System.arraycopy(toProcess, start, result, 0, end - start);
return result;
}
/**
* Check if this might be a two character token.
*/
private boolean isTwoCharToken(TokenKind kind) {
assert kind.tokenChars.length==2;
assert toProcess[pos] == kind.tokenChars[0];
return toProcess[pos+1] == kind.tokenChars[1];
}
/**
* Push a token of just one character in length.
*/
private void pushCharToken(TokenKind kind) {
tokens.add(new Token(kind,pos,pos+1));
pos++;
}
/**
* Push a token of two characters in length.
*/
private void pushPairToken(TokenKind kind) {
tokens.add(new Token(kind,pos,pos+2));
pos+=2;
}
// ID: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|DOT_ESCAPED)*;
private boolean isIdentifier(char ch) {
return isAlphabetic(ch) || isDigit(ch) || ch=='_';
}
private boolean isChar(char a,char b) {
char ch = toProcess[pos];
return ch==a || ch==b;
}
private boolean isExponentChar(char ch) {
return ch=='e' || ch=='E';
}
private boolean isFloatSuffix(char ch) {
return ch=='f' || ch=='F';
}
private boolean isDoubleSuffix(char ch) {
return ch=='d' || ch=='D';
}
private boolean isSign(char ch) {
return ch=='+' || ch=='-';
}
private boolean isDigit(char ch) {
if (ch>255) {
return false;
}
return (flags[ch] & IS_DIGIT)!=0;
}
private boolean isAlphabetic(char ch) {
if (ch>255) {
return false;
}
return (flags[ch] & IS_ALPHA)!=0;
}
private boolean isHexadecimalDigit(char ch) {
if (ch>255) {
return false;
}
return (flags[ch] & IS_HEXDIGIT)!=0;
}
private static final byte flags[] = new byte[256];
private static final byte IS_DIGIT=0x01;
private static final byte IS_HEXDIGIT=0x02;
private static final byte IS_ALPHA=0x04;
static {
for (int ch='0';ch<='9';ch++) {
flags[ch]|=IS_DIGIT | IS_HEXDIGIT;
}
for (int ch='A';ch<='F';ch++) {
flags[ch]|= IS_HEXDIGIT;
}
for (int ch='a';ch<='f';ch++) {
flags[ch]|= IS_HEXDIGIT;
}
for (int ch='A';ch<='Z';ch++) {
flags[ch]|= IS_ALPHA;
}
for (int ch='a';ch<='z';ch++) {
flags[ch]|= IS_ALPHA;
}
}
}

View File

@ -16,7 +16,7 @@
package org.springframework.expression.spel.support; package org.springframework.expression.spel.support;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ast.SpelNodeImpl; import org.springframework.expression.spel.ast.CommonTypeDescriptors;
/** /**
* @author Andy Clement * @author Andy Clement
@ -28,7 +28,7 @@ public class BooleanTypedValue extends TypedValue {
public static final BooleanTypedValue False = new BooleanTypedValue(false); public static final BooleanTypedValue False = new BooleanTypedValue(false);
private BooleanTypedValue(boolean b) { private BooleanTypedValue(boolean b) {
super(b,SpelNodeImpl.BOOLEAN_TYPE_DESCRIPTOR); super(b,CommonTypeDescriptors.BOOLEAN_TYPE_DESCRIPTOR);
} }
public static BooleanTypedValue forValue(boolean b) { public static BooleanTypedValue forValue(boolean b) {

View File

@ -22,7 +22,7 @@ import java.util.List;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeConverter; import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -112,7 +112,7 @@ public class ReflectionHelper {
int argCountUpToVarargs = expectedArgTypes.length-1; int argCountUpToVarargs = expectedArgTypes.length-1;
for (int i = 0; i < argCountUpToVarargs && match != null; i++) { for (int i = 0; i < argCountUpToVarargs && match != null; i++) {
Class suppliedArg = suppliedArgTypes[i]; Class suppliedArg = suppliedArgTypes[i];
Class expectedArg = expectedArgTypes[i]; Class<?> expectedArg = expectedArgTypes[i];
if (expectedArg != suppliedArg) { if (expectedArg != suppliedArg) {
if (expectedArg.isAssignableFrom(suppliedArg) || ClassUtils.isAssignableValue(expectedArg, suppliedArg)) { if (expectedArg.isAssignableFrom(suppliedArg) || ClassUtils.isAssignableValue(expectedArg, suppliedArg)) {
if (match != ArgsMatchKind.REQUIRES_CONVERSION) { if (match != ArgsMatchKind.REQUIRES_CONVERSION) {
@ -226,10 +226,10 @@ public class ReflectionHelper {
* @param isVarargs whether parameterTypes relates to a varargs method * @param isVarargs whether parameterTypes relates to a varargs method
* @param converter the converter to use for type conversions * @param converter the converter to use for type conversions
* @param arguments the arguments to convert to the requested parameter types * @param arguments the arguments to convert to the requested parameter types
* @throws SpelException if there is a problem with conversion * @throws SpelEvaluationException if there is a problem with conversion
*/ */
public static void convertAllArguments(Class[] parameterTypes, boolean isVarargs, TypeConverter converter, public static void convertAllArguments(Class[] parameterTypes, boolean isVarargs, TypeConverter converter,
Object[] arguments) throws SpelException { Object[] arguments) throws SpelEvaluationException {
Assert.notNull(arguments,"should not be called if nothing to convert"); Assert.notNull(arguments,"should not be called if nothing to convert");
@ -248,16 +248,16 @@ public class ReflectionHelper {
try { try {
if (arguments[i] != null && arguments[i].getClass() != targetType) { if (arguments[i] != null && arguments[i].getClass() != targetType) {
if (converter == null) { if (converter == null) {
throw new SpelException(SpelMessages.TYPE_CONVERSION_ERROR, arguments[i].getClass().getName(),targetType); throw new SpelEvaluationException(SpelMessages.TYPE_CONVERSION_ERROR, arguments[i].getClass().getName(),targetType);
} }
arguments[i] = converter.convertValue(arguments[i], targetType); arguments[i] = converter.convertValue(arguments[i], targetType);
} }
} catch (EvaluationException ex) { } catch (EvaluationException ex) {
// allows for another type converter throwing a different kind of EvaluationException // allows for another type converter throwing a different kind of EvaluationException
if (ex instanceof SpelException) { if (ex instanceof SpelEvaluationException) {
throw (SpelException)ex; throw (SpelEvaluationException)ex;
} else { } else {
throw new SpelException(ex, SpelMessages.TYPE_CONVERSION_ERROR,arguments[i].getClass().getName(),targetType); throw new SpelEvaluationException(ex, SpelMessages.TYPE_CONVERSION_ERROR,arguments[i].getClass().getName(),targetType);
} }
} }
} }

View File

@ -24,7 +24,7 @@ import org.springframework.expression.EvaluationException;
import org.springframework.expression.MethodExecutor; import org.springframework.expression.MethodExecutor;
import org.springframework.expression.MethodResolver; import org.springframework.expression.MethodResolver;
import org.springframework.expression.TypeConverter; import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
/** /**
@ -88,7 +88,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
} }
else if (matchRequiringConversion != null) { else if (matchRequiringConversion != null) {
if (multipleOptions) { if (multipleOptions) {
throw new SpelException(SpelMessages.MULTIPLE_POSSIBLE_METHODS, name); throw new SpelEvaluationException(SpelMessages.MULTIPLE_POSSIBLE_METHODS, name);
} }
return new ReflectiveMethodExecutor(matchRequiringConversion, argsToConvert); return new ReflectiveMethodExecutor(matchRequiringConversion, argsToConvert);
} }

View File

@ -17,7 +17,7 @@
package org.springframework.expression.spel.support; package org.springframework.expression.spel.support;
import org.springframework.expression.TypeComparator; import org.springframework.expression.TypeComparator;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
/** /**
@ -30,7 +30,7 @@ import org.springframework.expression.spel.SpelMessages;
public class StandardTypeComparator implements TypeComparator { public class StandardTypeComparator implements TypeComparator {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public int compare(Object left, Object right) throws SpelException { public int compare(Object left, Object right) throws SpelEvaluationException {
// If one is null, check if the other is // If one is null, check if the other is
if (left == null) { if (left == null) {
return right == null ? 0 : 1; return right == null ? 0 : 1;
@ -65,7 +65,7 @@ public class StandardTypeComparator implements TypeComparator {
return ((Comparable) left).compareTo(right); return ((Comparable) left).compareTo(right);
} }
throw new SpelException(SpelMessages.NOT_COMPARABLE, left.getClass(), right.getClass()); throw new SpelEvaluationException(SpelMessages.NOT_COMPARABLE, left.getClass(), right.getClass());
} }
public boolean canCompare(Object left, Object right) { public boolean canCompare(Object left, Object right) {

View File

@ -22,7 +22,7 @@ import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultTypeConverter; import org.springframework.core.convert.support.DefaultTypeConverter;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeConverter; import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -55,10 +55,10 @@ public class StandardTypeConverter implements TypeConverter {
return this.typeConverter.convert(value, typeDescriptor); return this.typeConverter.convert(value, typeDescriptor);
} }
catch (ConverterNotFoundException cenfe) { catch (ConverterNotFoundException cenfe) {
throw new SpelException(cenfe, SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString()); throw new SpelEvaluationException(cenfe, SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString());
} }
catch (ConvertException ce) { catch (ConvertException ce) {
throw new SpelException(ce, SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString()); throw new SpelEvaluationException(ce, SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString());
} }
} }

View File

@ -22,7 +22,7 @@ import java.util.List;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeLocator; import org.springframework.expression.TypeLocator;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -76,7 +76,7 @@ public class StandardTypeLocator implements TypeLocator {
// might be a different prefix // might be a different prefix
} }
} }
throw new SpelException(SpelMessages.TYPE_NOT_FOUND, typename); throw new SpelEvaluationException(SpelMessages.TYPE_NOT_FOUND, typename);
} }
/** /**

View File

@ -16,6 +16,8 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import org.junit.Test;
/** /**
* Tests the evaluation of real boolean expressions, these use AND, OR, NOT, TRUE, FALSE * Tests the evaluation of real boolean expressions, these use AND, OR, NOT, TRUE, FALSE
* *
@ -23,14 +25,17 @@ package org.springframework.expression.spel;
*/ */
public class BooleanExpressionTests extends ExpressionTestCase { public class BooleanExpressionTests extends ExpressionTestCase {
@Test
public void testBooleanTrue() { public void testBooleanTrue() {
evaluate("true", Boolean.TRUE, Boolean.class); evaluate("true", Boolean.TRUE, Boolean.class);
} }
@Test
public void testBooleanFalse() { public void testBooleanFalse() {
evaluate("false", Boolean.FALSE, Boolean.class); evaluate("false", Boolean.FALSE, Boolean.class);
} }
@Test
public void testOr() { public void testOr() {
evaluate("false or false", Boolean.FALSE, Boolean.class); evaluate("false or false", Boolean.FALSE, Boolean.class);
evaluate("false or true", Boolean.TRUE, Boolean.class); evaluate("false or true", Boolean.TRUE, Boolean.class);
@ -38,6 +43,7 @@ public class BooleanExpressionTests extends ExpressionTestCase {
evaluate("true or true", Boolean.TRUE, Boolean.class); evaluate("true or true", Boolean.TRUE, Boolean.class);
} }
@Test
public void testAnd() { public void testAnd() {
evaluate("false and false", Boolean.FALSE, Boolean.class); evaluate("false and false", Boolean.FALSE, Boolean.class);
evaluate("false and true", Boolean.FALSE, Boolean.class); evaluate("false and true", Boolean.FALSE, Boolean.class);
@ -45,23 +51,27 @@ public class BooleanExpressionTests extends ExpressionTestCase {
evaluate("true and true", Boolean.TRUE, Boolean.class); evaluate("true and true", Boolean.TRUE, Boolean.class);
} }
@Test
public void testNot() { public void testNot() {
evaluate("!false", Boolean.TRUE, Boolean.class); evaluate("!false", Boolean.TRUE, Boolean.class);
evaluate("!true", Boolean.FALSE, Boolean.class); evaluate("!true", Boolean.FALSE, Boolean.class);
} }
@Test
public void testCombinations01() { public void testCombinations01() {
evaluate("false and false or true", Boolean.TRUE, Boolean.class); evaluate("false and false or true", Boolean.TRUE, Boolean.class);
evaluate("true and false or true", Boolean.TRUE, Boolean.class); evaluate("true and false or true", Boolean.TRUE, Boolean.class);
evaluate("true and false or false", Boolean.FALSE, Boolean.class); evaluate("true and false or false", Boolean.FALSE, Boolean.class);
} }
@Test
public void testWritability() { public void testWritability() {
evaluate("true and true", Boolean.TRUE, Boolean.class, false); evaluate("true and true", Boolean.TRUE, Boolean.class, false);
evaluate("true or true", Boolean.TRUE, Boolean.class, false); evaluate("true or true", Boolean.TRUE, Boolean.class, false);
evaluate("!false", Boolean.TRUE, Boolean.class, false); evaluate("!false", Boolean.TRUE, Boolean.class, false);
} }
@Test
public void testBooleanErrors01() { public void testBooleanErrors01() {
evaluateAndCheckError("1.0 or false", SpelMessages.TYPE_CONVERSION_ERROR, 0); evaluateAndCheckError("1.0 or false", SpelMessages.TYPE_CONVERSION_ERROR, 0);
evaluateAndCheckError("false or 39.4", SpelMessages.TYPE_CONVERSION_ERROR, 9); evaluateAndCheckError("false or 39.4", SpelMessages.TYPE_CONVERSION_ERROR, 9);

View File

@ -16,6 +16,8 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import org.junit.Test;
/** /**
* Tests invocation of constructors. * Tests invocation of constructors.
* *
@ -23,14 +25,17 @@ package org.springframework.expression.spel;
*/ */
public class ConstructorInvocationTests extends ExpressionTestCase { public class ConstructorInvocationTests extends ExpressionTestCase {
@Test
public void testTypeConstructors() { public void testTypeConstructors() {
evaluate("new String('hello world')", "hello world", String.class); evaluate("new String('hello world')", "hello world", String.class);
} }
@Test
public void testNonExistentType() { public void testNonExistentType() {
evaluateAndCheckError("new FooBar()",SpelMessages.PROBLEM_LOCATING_CONSTRUCTOR); evaluateAndCheckError("new FooBar()",SpelMessages.CONSTRUCTOR_INVOCATION_PROBLEM);
} }
@Test
public void testVarargsInvocation01() { public void testVarargsInvocation01() {
// Calling 'Fruit(String... strings)' // Calling 'Fruit(String... strings)'
evaluate("new org.springframework.expression.spel.testresources.Fruit('a','b','c').stringscount()", 3, Integer.class); evaluate("new org.springframework.expression.spel.testresources.Fruit('a','b','c').stringscount()", 3, Integer.class);
@ -41,6 +46,7 @@ public class ConstructorInvocationTests extends ExpressionTestCase {
evaluate("new org.springframework.expression.spel.testresources.Fruit(1,'a',3.0d).stringscount()", 3, Integer.class); // first and last need conversion evaluate("new org.springframework.expression.spel.testresources.Fruit(1,'a',3.0d).stringscount()", 3, Integer.class); // first and last need conversion
} }
@Test
public void testVarargsInvocation02() { public void testVarargsInvocation02() {
// Calling 'Fruit(int i, String... strings)' - returns int+length_of_strings // Calling 'Fruit(int i, String... strings)' - returns int+length_of_strings
evaluate("new org.springframework.expression.spel.testresources.Fruit(5,'a','b','c').stringscount()", 8, Integer.class); evaluate("new org.springframework.expression.spel.testresources.Fruit(5,'a','b','c').stringscount()", 8, Integer.class);
@ -56,6 +62,7 @@ public class ConstructorInvocationTests extends ExpressionTestCase {
* These tests are attempting to call constructors where we need to widen or convert the argument in order to * These tests are attempting to call constructors where we need to widen or convert the argument in order to
* satisfy a suitable constructor. * satisfy a suitable constructor.
*/ */
@Test
public void testWidening01() { public void testWidening01() {
// widening of int 3 to double 3 is OK // widening of int 3 to double 3 is OK
evaluate("new Double(3)", 3.0d, Double.class); evaluate("new Double(3)", 3.0d, Double.class);
@ -63,6 +70,7 @@ public class ConstructorInvocationTests extends ExpressionTestCase {
evaluate("new Long(3)", 3L, Long.class); evaluate("new Long(3)", 3L, Long.class);
} }
@Test
public void testArgumentConversion01() { public void testArgumentConversion01() {
// Closest ctor will be new String(String) and converter supports Double>String // Closest ctor will be new String(String) and converter supports Double>String
evaluate("new String(3.0d)", "3.0", String.class); evaluate("new String(3.0d)", "3.0", String.class);

View File

@ -15,8 +15,9 @@
*/ */
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.TestCase; import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeComparator; import org.springframework.expression.TypeComparator;
import org.springframework.expression.spel.support.StandardTypeComparator; import org.springframework.expression.spel.support.StandardTypeComparator;
@ -26,59 +27,63 @@ import org.springframework.expression.spel.support.StandardTypeComparator;
* *
* @author Andy Clement * @author Andy Clement
*/ */
public class DefaultComparatorUnitTests extends TestCase { public class DefaultComparatorUnitTests {
@Test
public void testPrimitives() throws EvaluationException { public void testPrimitives() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator(); TypeComparator comparator = new StandardTypeComparator();
// primitive int // primitive int
assertTrue(comparator.compare(1, 2) < 0); Assert.assertTrue(comparator.compare(1, 2) < 0);
assertTrue(comparator.compare(1, 1) == 0); Assert.assertTrue(comparator.compare(1, 1) == 0);
assertTrue(comparator.compare(2, 1) > 0); Assert.assertTrue(comparator.compare(2, 1) > 0);
assertTrue(comparator.compare(1.0d, 2) < 0); Assert.assertTrue(comparator.compare(1.0d, 2) < 0);
assertTrue(comparator.compare(1.0d, 1) == 0); Assert.assertTrue(comparator.compare(1.0d, 1) == 0);
assertTrue(comparator.compare(2.0d, 1) > 0); Assert.assertTrue(comparator.compare(2.0d, 1) > 0);
assertTrue(comparator.compare(1.0f, 2) < 0); Assert.assertTrue(comparator.compare(1.0f, 2) < 0);
assertTrue(comparator.compare(1.0f, 1) == 0); Assert.assertTrue(comparator.compare(1.0f, 1) == 0);
assertTrue(comparator.compare(2.0f, 1) > 0); Assert.assertTrue(comparator.compare(2.0f, 1) > 0);
assertTrue(comparator.compare(1L, 2) < 0); Assert.assertTrue(comparator.compare(1L, 2) < 0);
assertTrue(comparator.compare(1L, 1) == 0); Assert.assertTrue(comparator.compare(1L, 1) == 0);
assertTrue(comparator.compare(2L, 1) > 0); Assert.assertTrue(comparator.compare(2L, 1) > 0);
assertTrue(comparator.compare(1, 2L) < 0); Assert.assertTrue(comparator.compare(1, 2L) < 0);
assertTrue(comparator.compare(1, 1L) == 0); Assert.assertTrue(comparator.compare(1, 1L) == 0);
assertTrue(comparator.compare(2, 1L) > 0); Assert.assertTrue(comparator.compare(2, 1L) > 0);
assertTrue(comparator.compare(1L, 2L) < 0); Assert.assertTrue(comparator.compare(1L, 2L) < 0);
assertTrue(comparator.compare(1L, 1L) == 0); Assert.assertTrue(comparator.compare(1L, 1L) == 0);
assertTrue(comparator.compare(2L, 1L) > 0); Assert.assertTrue(comparator.compare(2L, 1L) > 0);
} }
@Test
public void testNulls() throws EvaluationException { public void testNulls() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator(); TypeComparator comparator = new StandardTypeComparator();
assertTrue(comparator.compare(null,"abc")>0); Assert.assertTrue(comparator.compare(null,"abc")>0);
assertTrue(comparator.compare(null,null)==0); Assert.assertTrue(comparator.compare(null,null)==0);
assertTrue(comparator.compare("abc",null)<0); Assert.assertTrue(comparator.compare("abc",null)<0);
} }
@Test
public void testObjects() throws EvaluationException { public void testObjects() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator(); TypeComparator comparator = new StandardTypeComparator();
assertTrue(comparator.compare("a","a")==0); Assert.assertTrue(comparator.compare("a","a")==0);
assertTrue(comparator.compare("a","b")<0); Assert.assertTrue(comparator.compare("a","b")<0);
assertTrue(comparator.compare("b","a")>0); Assert.assertTrue(comparator.compare("b","a")>0);
} }
@Test
public void testCanCompare() throws EvaluationException { public void testCanCompare() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator(); TypeComparator comparator = new StandardTypeComparator();
assertTrue(comparator.canCompare(null,1)); Assert.assertTrue(comparator.canCompare(null,1));
assertTrue(comparator.canCompare(1,null)); Assert.assertTrue(comparator.canCompare(1,null));
assertTrue(comparator.canCompare(2,1)); Assert.assertTrue(comparator.canCompare(2,1));
assertTrue(comparator.canCompare("abc","def")); Assert.assertTrue(comparator.canCompare("abc","def"));
assertTrue(comparator.canCompare("abc",3)); Assert.assertTrue(comparator.canCompare("abc",3));
assertFalse(comparator.canCompare(String.class,3)); Assert.assertFalse(comparator.canCompare(String.class,3));
} }
} }

View File

@ -16,9 +16,14 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeLocator; import org.springframework.expression.spel.support.StandardTypeLocator;
@ -29,68 +34,95 @@ import org.springframework.expression.spel.support.StandardTypeLocator;
*/ */
public class EvaluationTests extends ExpressionTestCase { public class EvaluationTests extends ExpressionTestCase {
@Test
public void testElvis01() {
evaluate("'Andy'?:'Dave'","Andy",String.class);
evaluate("null?:'Dave'","Dave",String.class);
}
@Test
public void testSafeNavigation() {
evaluate("null?.null?.null",null,null);
}
@Test
public void testRelOperatorGT01() { public void testRelOperatorGT01() {
evaluate("3 > 6", "false", Boolean.class); evaluate("3 > 6", "false", Boolean.class);
} }
@Test
public void testRelOperatorLT01() { public void testRelOperatorLT01() {
evaluate("3 < 6", "true", Boolean.class); evaluate("3 < 6", "true", Boolean.class);
} }
@Test
public void testRelOperatorLE01() { public void testRelOperatorLE01() {
evaluate("3 <= 6", "true", Boolean.class); evaluate("3 <= 6", "true", Boolean.class);
} }
@Test
public void testRelOperatorGE01() { public void testRelOperatorGE01() {
evaluate("3 >= 6", "false", Boolean.class); evaluate("3 >= 6", "false", Boolean.class);
} }
@Test
public void testRelOperatorGE02() { public void testRelOperatorGE02() {
evaluate("3 >= 3", "true", Boolean.class); evaluate("3 >= 3", "true", Boolean.class);
} }
public void testRelOperatorsIs01() { @Test
public void testRelOperatorsInstanceof01() {
evaluate("'xyz' instanceof T(int)", "false", Boolean.class); evaluate("'xyz' instanceof T(int)", "false", Boolean.class);
} }
public void testRelOperatorsIs04() { @Test
public void testRelOperatorsInstanceof04() {
evaluate("null instanceof T(String)", "false", Boolean.class); evaluate("null instanceof T(String)", "false", Boolean.class);
} }
public void testRelOperatorsIs05() { @Test
public void testRelOperatorsInstanceof05() {
evaluate("null instanceof T(Integer)", "false", Boolean.class); evaluate("null instanceof T(Integer)", "false", Boolean.class);
} }
public void testRelOperatorsIs06() { @Test
public void testRelOperatorsInstanceof06() {
evaluateAndCheckError("'A' instanceof null", SpelMessages.INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND, 15, "null"); evaluateAndCheckError("'A' instanceof null", SpelMessages.INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND, 15, "null");
} }
@Test
public void testRelOperatorsMatches01() { public void testRelOperatorsMatches01() {
evaluate("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "false", Boolean.class); evaluate("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "false", Boolean.class);
} }
@Test
public void testRelOperatorsMatches02() { public void testRelOperatorsMatches02() {
evaluate("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "true", Boolean.class); evaluate("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "true", Boolean.class);
} }
@Test
public void testRelOperatorsMatches03() { public void testRelOperatorsMatches03() {
evaluateAndCheckError("null matches '^.*$'", SpelMessages.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, 0, null); evaluateAndCheckError("null matches '^.*$'", SpelMessages.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, 0, null);
} }
@Test
public void testRelOperatorsMatches04() { public void testRelOperatorsMatches04() {
evaluateAndCheckError("'abc' matches null", SpelMessages.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, 14, null); evaluateAndCheckError("'abc' matches null", SpelMessages.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, 14, null);
} }
@Test
public void testRelOperatorsMatches05() { public void testRelOperatorsMatches05() {
evaluate("27 matches '^.*2.*$'", true, Boolean.class); // conversion int>string evaluate("27 matches '^.*2.*$'", true, Boolean.class); // conversion int>string
} }
// mixing operators // mixing operators
@Test
public void testMixingOperators01() { public void testMixingOperators01() {
evaluate("true and 5>3", "true", Boolean.class); evaluate("true and 5>3", "true", Boolean.class);
} }
// property access // property access
@Test
public void testPropertyField01() { public void testPropertyField01() {
evaluate("name", "Nikola Tesla", String.class, false); evaluate("name", "Nikola Tesla", String.class, false);
// not writable because (1) name is private (2) there is no setter, only a getter // not writable because (1) name is private (2) there is no setter, only a getter
@ -99,121 +131,157 @@ public class EvaluationTests extends ExpressionTestCase {
} }
// nested properties // nested properties
@Test
public void testPropertiesNested01() { public void testPropertiesNested01() {
evaluate("placeOfBirth.city", "SmilJan", String.class, true); evaluate("placeOfBirth.city", "SmilJan", String.class, true);
} }
@Test
public void testPropertiesNested02() { public void testPropertiesNested02() {
evaluate("placeOfBirth.doubleIt(12)", "24", Integer.class); evaluate("placeOfBirth.doubleIt(12)", "24", Integer.class);
} }
@Test
public void testPropertiesNested03() throws ParseException {
try {
new SpelExpressionParser().parse("placeOfBirth.23");
Assert.fail();
} catch (SpelParseException spe) {
Assert.assertEquals(spe.getMessageUnformatted(), SpelMessages.UNEXPECTED_DATA_AFTER_DOT);
Assert.assertEquals("23", spe.getInserts()[0]);
}
}
// methods // methods
@Test
public void testMethods01() { public void testMethods01() {
evaluate("echo(12)", "12", String.class); evaluate("echo(12)", "12", String.class);
} }
@Test
public void testMethods02() { public void testMethods02() {
evaluate("echo(name)", "Nikola Tesla", String.class); evaluate("echo(name)", "Nikola Tesla", String.class);
} }
// constructors // constructors
@Test
public void testConstructorInvocation01() { public void testConstructorInvocation01() {
evaluate("new String('hello')", "hello", String.class); evaluate("new String('hello')", "hello", String.class);
} }
@Test
public void testConstructorInvocation05() { public void testConstructorInvocation05() {
evaluate("new java.lang.String('foobar')", "foobar", String.class); evaluate("new java.lang.String('foobar')", "foobar", String.class);
} }
@Test
public void testConstructorInvocation06() throws Exception { public void testConstructorInvocation06() throws Exception {
// repeated evaluation to drive use of cached executor // repeated evaluation to drive use of cached executor
SpelExpression expr = (SpelExpression)parser.parseExpression("new String('wibble')"); SpelExpression expr = (SpelExpression)parser.parseExpression("new String('wibble')");
String newString = expr.getValue(String.class); String newString = expr.getValue(String.class);
assertEquals("wibble",newString); Assert.assertEquals("wibble",newString);
newString = expr.getValue(String.class); newString = expr.getValue(String.class);
assertEquals("wibble",newString); Assert.assertEquals("wibble",newString);
// not writable // not writable
assertFalse(expr.isWritable(new StandardEvaluationContext())); Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
// ast // ast
assertEquals("new String('wibble')",expr.toStringAST()); Assert.assertEquals("new String('wibble')",expr.toStringAST());
} }
// unary expressions // unary expressions
@Test
public void testUnaryMinus01() { public void testUnaryMinus01() {
evaluate("-5", "-5", Integer.class); evaluate("-5", "-5", Integer.class);
} }
@Test
public void testUnaryPlus01() { public void testUnaryPlus01() {
evaluate("+5", "5", Integer.class); evaluate("+5", "5", Integer.class);
} }
@Test
public void testUnaryNot01() { public void testUnaryNot01() {
evaluate("!true", "false", Boolean.class); evaluate("!true", "false", Boolean.class);
} }
// assignment // assignment
@Test
public void testAssignmentToVariables01() { public void testAssignmentToVariables01() {
evaluate("#var1='value1'", "value1", String.class); evaluate("#var1='value1'", "value1", String.class);
} }
@Test
public void testTernaryOperator01() { public void testTernaryOperator01() {
evaluate("2>4?1:2",2,Integer.class); evaluate("2>4?1:2",2,Integer.class);
} }
@Test
public void testTernaryOperator02() { public void testTernaryOperator02() {
evaluate("'abc'=='abc'?1:2",1,Integer.class); evaluate("'abc'=='abc'?1:2",1,Integer.class);
} }
@Test
public void testTernaryOperator03() { public void testTernaryOperator03() {
evaluateAndCheckError("'hello'?1:2", SpelMessages.TYPE_CONVERSION_ERROR); // cannot convert String to boolean evaluateAndCheckError("'hello'?1:2", SpelMessages.TYPE_CONVERSION_ERROR); // cannot convert String to boolean
} }
@Test
public void testTernaryOperator04() throws Exception { public void testTernaryOperator04() throws Exception {
Expression expr = parser.parseExpression("1>2?3:4"); Expression expr = parser.parseExpression("1>2?3:4");
assertFalse(expr.isWritable(eContext)); Assert.assertFalse(expr.isWritable(eContext));
} }
@Test
public void testIndexer03() { public void testIndexer03() {
evaluate("'christian'[8]", "n", String.class); evaluate("'christian'[8]", "n", String.class);
} }
@Test
public void testIndexerError() { public void testIndexerError() {
evaluateAndCheckError("new org.springframework.expression.spel.testresources.Inventor().inventions[1]",SpelMessages.CANNOT_INDEX_INTO_NULL_VALUE); evaluateAndCheckError("new org.springframework.expression.spel.testresources.Inventor().inventions[1]",SpelMessages.CANNOT_INDEX_INTO_NULL_VALUE);
} }
@Test
public void testStaticRef02() { public void testStaticRef02() {
evaluate("T(java.awt.Color).green.getRGB()!=0", "true", Boolean.class); evaluate("T(java.awt.Color).green.getRGB()!=0", "true", Boolean.class);
} }
// variables and functions // variables and functions
@Test
public void testVariableAccess01() { public void testVariableAccess01() {
evaluate("#answer", "42", Integer.class, true); evaluate("#answer", "42", Integer.class, true);
} }
@Test
public void testFunctionAccess01() { public void testFunctionAccess01() {
evaluate("#reverseInt(1,2,3)", "int[3]{3,2,1}", int[].class); evaluate("#reverseInt(1,2,3)", "int[3]{3,2,1}", int[].class);
} }
@Test
public void testFunctionAccess02() { public void testFunctionAccess02() {
evaluate("#reverseString('hello')", "olleh", String.class); evaluate("#reverseString('hello')", "olleh", String.class);
} }
// type references // type references
@Test
public void testTypeReferences01() { public void testTypeReferences01() {
evaluate("T(java.lang.String)", "class java.lang.String", Class.class); evaluate("T(java.lang.String)", "class java.lang.String", Class.class);
} }
@Test
public void testTypeReferencesAndQualifiedIdentifierCaching() throws Exception { public void testTypeReferencesAndQualifiedIdentifierCaching() throws Exception {
SpelExpression expr = (SpelExpression)parser.parseExpression("T(java.lang.String)"); SpelExpression expr = (SpelExpression)parser.parseExpression("T(java.lang.String)");
assertFalse(expr.isWritable(new StandardEvaluationContext())); Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
assertEquals("T(java.lang.String)",expr.toStringAST()); Assert.assertEquals("T(java.lang.String)",expr.toStringAST());
assertEquals(String.class,expr.getValue(Class.class)); Assert.assertEquals(String.class,expr.getValue(Class.class));
// use cached QualifiedIdentifier: // use cached QualifiedIdentifier:
assertEquals("T(java.lang.String)",expr.toStringAST()); Assert.assertEquals("T(java.lang.String)",expr.toStringAST());
assertEquals(String.class,expr.getValue(Class.class)); Assert.assertEquals(String.class,expr.getValue(Class.class));
} }
@Test
public void testTypeReferencesPrimitive() { public void testTypeReferencesPrimitive() {
evaluate("T(int)", "int", Class.class); evaluate("T(int)", "int", Class.class);
evaluate("T(byte)", "byte", Class.class); evaluate("T(byte)", "byte", Class.class);
@ -225,14 +293,17 @@ public class EvaluationTests extends ExpressionTestCase {
evaluate("T(float)", "float", Class.class); evaluate("T(float)", "float", Class.class);
} }
@Test
public void testTypeReferences02() { public void testTypeReferences02() {
evaluate("T(String)", "class java.lang.String", Class.class); evaluate("T(String)", "class java.lang.String", Class.class);
} }
@Test
public void testStringType() { public void testStringType() {
evaluateAndAskForReturnType("getPlaceOfBirth().getCity()", "SmilJan", String.class); evaluateAndAskForReturnType("getPlaceOfBirth().getCity()", "SmilJan", String.class);
} }
@Test
public void testNumbers01() { public void testNumbers01() {
evaluateAndAskForReturnType("3*4+5", 17, Integer.class); evaluateAndAskForReturnType("3*4+5", 17, Integer.class);
evaluateAndAskForReturnType("3*4+5", 17L, Long.class); evaluateAndAskForReturnType("3*4+5", 17L, Long.class);
@ -242,39 +313,43 @@ public class EvaluationTests extends ExpressionTestCase {
} }
@Test
public void testAdvancedNumerics() throws Exception { public void testAdvancedNumerics() throws Exception {
int twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Integer.class); int twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Integer.class);
assertEquals(24,twentyFour); Assert.assertEquals(24,twentyFour);
double one = parser.parseExpression("8.0 / 5e0 % 2").getValue(Double.class); double one = parser.parseExpression("8.0 / 5e0 % 2").getValue(Double.class);
assertEquals(1.6d,one); Assert.assertEquals(1.6d,one);
int o = parser.parseExpression("8.0 / 5e0 % 2").getValue(Integer.class); int o = parser.parseExpression("8.0 / 5e0 % 2").getValue(Integer.class);
assertEquals(1,o); Assert.assertEquals(1,o);
int sixteen = parser.parseExpression("-2 ^ 4").getValue(Integer.class); int sixteen = parser.parseExpression("-2 ^ 4").getValue(Integer.class);
assertEquals(16,sixteen); Assert.assertEquals(16,sixteen);
int minusFortyFive = parser.parseExpression("1+2-3*8^2/2/2").getValue(Integer.class); int minusFortyFive = parser.parseExpression("1+2-3*8^2/2/2").getValue(Integer.class);
assertEquals(-45,minusFortyFive); Assert.assertEquals(-45,minusFortyFive);
} }
@Test
public void testComparison() throws Exception { public void testComparison() throws Exception {
EvaluationContext context = TestScenarioCreator.getTestEvaluationContext(); EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
boolean trueValue = parser.parseExpression("T(java.util.Date) == Birthdate.Class").getValue(context, Boolean.class); boolean trueValue = parser.parseExpression("T(java.util.Date) == Birthdate.Class").getValue(context, Boolean.class);
assertTrue(trueValue); Assert.assertTrue(trueValue);
} }
@Test
public void testResolvingList() throws Exception { public void testResolvingList() throws Exception {
StandardEvaluationContext context = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
try { try {
assertFalse(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class)); Assert.assertFalse(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class));
fail("should have failed to find List"); Assert.fail("should have failed to find List");
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
// success - List not found // success - List not found
} }
((StandardTypeLocator)context.getTypeLocator()).registerImport("java.util"); ((StandardTypeLocator)context.getTypeLocator()).registerImport("java.util");
assertTrue(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class)); Assert.assertTrue(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class));
} }
@Test
public void testResolvingString() throws Exception { public void testResolvingString() throws Exception {
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class); Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
assertEquals(String.class,stringClass); Assert.assertEquals(String.class,stringClass);
} }
} }

View File

@ -23,6 +23,9 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
@ -31,9 +34,11 @@ import org.springframework.expression.Expression;
import org.springframework.expression.ParseException; import org.springframework.expression.ParseException;
import org.springframework.expression.PropertyAccessor; import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
///CLOVER:OFF
/** /**
* Testcases showing the common scenarios/use-cases for picking up the expression language support. * Testcases showing the common scenarios/use-cases for picking up the expression language support.
* The first test shows very basic usage, just drop it in and go. By 'standard infrastructure', it means:<br> * The first test shows very basic usage, just drop it in and go. By 'standard infrastructure', it means:<br>
@ -60,10 +65,11 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
/** /**
* Scenario: using the standard infrastructure and running simple expression evaluation. * Scenario: using the standard infrastructure and running simple expression evaluation.
*/ */
@Test
public void testScenario_UsingStandardInfrastructure() { public void testScenario_UsingStandardInfrastructure() {
try { try {
// Create a parser // Create a parser
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
// Parse an expression // Parse an expression
Expression expr = parser.parseExpression("new String('hello world')"); Expression expr = parser.parseExpression("new String('hello world')");
// Evaluate it using a 'standard' context // Evaluate it using a 'standard' context
@ -71,23 +77,24 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
// They are reusable // They are reusable
value = expr.getValue(); value = expr.getValue();
assertEquals("hello world", value); Assert.assertEquals("hello world", value);
assertEquals(String.class, value.getClass()); Assert.assertEquals(String.class, value.getClass());
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
ee.printStackTrace(); ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage()); Assert.fail("Unexpected Exception: " + ee.getMessage());
} catch (ParseException pe) { } catch (ParseException pe) {
pe.printStackTrace(); pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage()); Assert.fail("Unexpected Exception: " + pe.getMessage());
} }
} }
/** /**
* Scenario: using the standard context but adding your own variables * Scenario: using the standard context but adding your own variables
*/ */
@Test
public void testScenario_DefiningVariablesThatWillBeAccessibleInExpressions() throws Exception { public void testScenario_DefiningVariablesThatWillBeAccessibleInExpressions() throws Exception {
// Create a parser // Create a parser
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
// Use the standard evaluation context // Use the standard evaluation context
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
ctx.setVariable("favouriteColour","blue"); ctx.setVariable("favouriteColour","blue");
@ -97,16 +104,16 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
Expression expr = parser.parseExpression("#favouriteColour"); Expression expr = parser.parseExpression("#favouriteColour");
Object value = expr.getValue(ctx); Object value = expr.getValue(ctx);
assertEquals("blue", value); Assert.assertEquals("blue", value);
expr = parser.parseExpression("#primes.get(1)"); expr = parser.parseExpression("#primes.get(1)");
value = expr.getValue(ctx); value = expr.getValue(ctx);
assertEquals(3, value); Assert.assertEquals(3, value);
// all prime numbers > 10 from the list (using selection ?{...}) // all prime numbers > 10 from the list (using selection ?{...})
expr = parser.parseExpression("#primes.?[#this>10]"); expr = parser.parseExpression("#primes.?[#this>10]");
value = expr.getValue(ctx); value = expr.getValue(ctx);
assertEquals("[11, 13, 17]", value.toString()); Assert.assertEquals("[11, 13, 17]", value.toString());
} }
@ -120,9 +127,10 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
/** /**
* Scenario: using your own root context object * Scenario: using your own root context object
*/ */
@Test
public void testScenario_UsingADifferentRootContextObject() throws Exception { public void testScenario_UsingADifferentRootContextObject() throws Exception {
// Create a parser // Create a parser
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
// Use the standard evaluation context // Use the standard evaluation context
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
@ -134,30 +142,30 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
// read it, set it, read it again // read it, set it, read it again
Expression expr = parser.parseExpression("str"); Expression expr = parser.parseExpression("str");
Object value = expr.getValue(ctx); Object value = expr.getValue(ctx);
assertEquals("wibble", value); Assert.assertEquals("wibble", value);
expr = parser.parseExpression("str"); expr = parser.parseExpression("str");
expr.setValue(ctx, "wobble"); expr.setValue(ctx, "wobble");
expr = parser.parseExpression("str"); expr = parser.parseExpression("str");
value = expr.getValue(ctx); value = expr.getValue(ctx);
assertEquals("wobble", value); Assert.assertEquals("wobble", value);
// or using assignment within the expression // or using assignment within the expression
expr = parser.parseExpression("str='wabble'"); expr = parser.parseExpression("str='wabble'");
value = expr.getValue(ctx); value = expr.getValue(ctx);
expr = parser.parseExpression("str"); expr = parser.parseExpression("str");
value = expr.getValue(ctx); value = expr.getValue(ctx);
assertEquals("wabble", value); Assert.assertEquals("wabble", value);
// private property will be accessed through getter() // private property will be accessed through getter()
expr = parser.parseExpression("property"); expr = parser.parseExpression("property");
value = expr.getValue(ctx); value = expr.getValue(ctx);
assertEquals(42, value); Assert.assertEquals(42, value);
// ... and set through setter // ... and set through setter
expr = parser.parseExpression("property=4"); expr = parser.parseExpression("property=4");
value = expr.getValue(ctx); value = expr.getValue(ctx);
expr = parser.parseExpression("property"); expr = parser.parseExpression("property");
value = expr.getValue(ctx); value = expr.getValue(ctx);
assertEquals(4,value); Assert.assertEquals(4,value);
} }
public static String repeat(String s) { return s+s; } public static String repeat(String s) { return s+s; }
@ -165,66 +173,69 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
/** /**
* Scenario: using your own java methods and calling them from the expression * Scenario: using your own java methods and calling them from the expression
*/ */
@Test
public void testScenario_RegisteringJavaMethodsAsFunctionsAndCallingThem() throws SecurityException, NoSuchMethodException { public void testScenario_RegisteringJavaMethodsAsFunctionsAndCallingThem() throws SecurityException, NoSuchMethodException {
try { try {
// Create a parser // Create a parser
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
// Use the standard evaluation context // Use the standard evaluation context
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
ctx.registerFunction("repeat",ExpressionLanguageScenarioTests.class.getDeclaredMethod("repeat",String.class)); ctx.registerFunction("repeat",ExpressionLanguageScenarioTests.class.getDeclaredMethod("repeat",String.class));
Expression expr = parser.parseExpression("#repeat('hello')"); Expression expr = parser.parseExpression("#repeat('hello')");
Object value = expr.getValue(ctx); Object value = expr.getValue(ctx);
assertEquals("hellohello", value); Assert.assertEquals("hellohello", value);
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
ee.printStackTrace(); ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage()); Assert.fail("Unexpected Exception: " + ee.getMessage());
} catch (ParseException pe) { } catch (ParseException pe) {
pe.printStackTrace(); pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage()); Assert.fail("Unexpected Exception: " + pe.getMessage());
} }
} }
/** /**
* Scenario: add a property resolver that will get called in the resolver chain, this one only supports reading. * Scenario: add a property resolver that will get called in the resolver chain, this one only supports reading.
*/ */
@Test
public void testScenario_AddingYourOwnPropertyResolvers_1() throws Exception { public void testScenario_AddingYourOwnPropertyResolvers_1() throws Exception {
// Create a parser // Create a parser
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
// Use the standard evaluation context // Use the standard evaluation context
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
ctx.addPropertyAccessor(new FruitColourAccessor()); ctx.addPropertyAccessor(new FruitColourAccessor());
Expression expr = parser.parseExpression("orange"); Expression expr = parser.parseExpression("orange");
Object value = expr.getValue(ctx); Object value = expr.getValue(ctx);
assertEquals(Color.orange, value); Assert.assertEquals(Color.orange, value);
try { try {
expr.setValue(ctx, Color.blue); expr.setValue(ctx, Color.blue);
fail("Should not be allowed to set oranges to be blue !"); Assert.fail("Should not be allowed to set oranges to be blue !");
} catch (SpelException ee) { } catch (SpelEvaluationException ee) {
assertEquals(ee.getMessageUnformatted(), SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL); Assert.assertEquals(ee.getMessageUnformatted(), SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL);
} }
} }
@Test
public void testScenario_AddingYourOwnPropertyResolvers_2() throws Exception { public void testScenario_AddingYourOwnPropertyResolvers_2() throws Exception {
// Create a parser // Create a parser
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
// Use the standard evaluation context // Use the standard evaluation context
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
ctx.addPropertyAccessor(new VegetableColourAccessor()); ctx.addPropertyAccessor(new VegetableColourAccessor());
Expression expr = parser.parseExpression("pea"); Expression expr = parser.parseExpression("pea");
Object value = expr.getValue(ctx); Object value = expr.getValue(ctx);
assertEquals(Color.green, value); Assert.assertEquals(Color.green, value);
try { try {
expr.setValue(ctx, Color.blue); expr.setValue(ctx, Color.blue);
fail("Should not be allowed to set peas to be blue !"); Assert.fail("Should not be allowed to set peas to be blue !");
} }
catch (SpelException ee) { catch (SpelEvaluationException ee) {
assertEquals(ee.getMessageUnformatted(), SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL); Assert.assertEquals(ee.getMessageUnformatted(), SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL);
} }
} }

View File

@ -18,6 +18,9 @@ package org.springframework.expression.spel;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
@ -34,204 +37,218 @@ import org.springframework.expression.spel.testresources.Inventor;
*/ */
public class ExpressionStateTests extends ExpressionTestCase { public class ExpressionStateTests extends ExpressionTestCase {
@Test
public void testConstruction() { public void testConstruction() {
EvaluationContext context = TestScenarioCreator.getTestEvaluationContext(); EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
ExpressionState state = new ExpressionState(context); ExpressionState state = new ExpressionState(context);
assertEquals(context,state.getEvaluationContext()); Assert.assertEquals(context,state.getEvaluationContext());
} }
// Local variables are in variable scopes which come and go during evaluation. Normal variables are // Local variables are in variable scopes which come and go during evaluation. Normal variables are
// accessible through the evaluation context // accessible through the evaluation context
@Test
public void testLocalVariables() { public void testLocalVariables() {
ExpressionState state = getState(); ExpressionState state = getState();
Object value = state.lookupLocalVariable("foo"); Object value = state.lookupLocalVariable("foo");
assertNull(value); Assert.assertNull(value);
state.setLocalVariable("foo",34); state.setLocalVariable("foo",34);
value = state.lookupLocalVariable("foo"); value = state.lookupLocalVariable("foo");
assertEquals(34,value); Assert.assertEquals(34,value);
state.setLocalVariable("foo",null); state.setLocalVariable("foo",null);
value = state.lookupLocalVariable("foo"); value = state.lookupLocalVariable("foo");
assertEquals(null,value); Assert.assertEquals(null,value);
} }
@Test
public void testVariables() { public void testVariables() {
ExpressionState state = getState(); ExpressionState state = getState();
TypedValue typedValue = state.lookupVariable("foo"); TypedValue typedValue = state.lookupVariable("foo");
assertEquals(TypedValue.NULL_TYPED_VALUE,typedValue); Assert.assertEquals(TypedValue.NULL_TYPED_VALUE,typedValue);
state.setVariable("foo",34); state.setVariable("foo",34);
typedValue = state.lookupVariable("foo"); typedValue = state.lookupVariable("foo");
assertEquals(34,typedValue.getValue()); Assert.assertEquals(34,typedValue.getValue());
assertEquals(Integer.class,typedValue.getTypeDescriptor().getType()); Assert.assertEquals(Integer.class,typedValue.getTypeDescriptor().getType());
state.setVariable("foo","abc"); state.setVariable("foo","abc");
typedValue = state.lookupVariable("foo"); typedValue = state.lookupVariable("foo");
assertEquals("abc",typedValue.getValue()); Assert.assertEquals("abc",typedValue.getValue());
assertEquals(String.class,typedValue.getTypeDescriptor().getType()); Assert.assertEquals(String.class,typedValue.getTypeDescriptor().getType());
} }
@Test
public void testNoVariableInteference() { public void testNoVariableInteference() {
ExpressionState state = getState(); ExpressionState state = getState();
TypedValue typedValue = state.lookupVariable("foo"); TypedValue typedValue = state.lookupVariable("foo");
assertEquals(TypedValue.NULL_TYPED_VALUE,typedValue); Assert.assertEquals(TypedValue.NULL_TYPED_VALUE,typedValue);
state.setLocalVariable("foo",34); state.setLocalVariable("foo",34);
typedValue = state.lookupVariable("foo"); typedValue = state.lookupVariable("foo");
assertEquals(TypedValue.NULL_TYPED_VALUE,typedValue); Assert.assertEquals(TypedValue.NULL_TYPED_VALUE,typedValue);
state.setVariable("goo","hello"); state.setVariable("goo","hello");
assertNull(state.lookupLocalVariable("goo")); Assert.assertNull(state.lookupLocalVariable("goo"));
} }
@Test
public void testLocalVariableNestedScopes() { public void testLocalVariableNestedScopes() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(null,state.lookupLocalVariable("foo")); Assert.assertEquals(null,state.lookupLocalVariable("foo"));
state.setLocalVariable("foo",12); state.setLocalVariable("foo",12);
assertEquals(12,state.lookupLocalVariable("foo")); Assert.assertEquals(12,state.lookupLocalVariable("foo"));
state.enterScope(null); state.enterScope(null);
assertEquals(12,state.lookupLocalVariable("foo")); // found in upper scope Assert.assertEquals(12,state.lookupLocalVariable("foo")); // found in upper scope
state.setLocalVariable("foo","abc"); state.setLocalVariable("foo","abc");
assertEquals("abc",state.lookupLocalVariable("foo")); // found in nested scope Assert.assertEquals("abc",state.lookupLocalVariable("foo")); // found in nested scope
state.exitScope(); state.exitScope();
assertEquals(12,state.lookupLocalVariable("foo")); // found in nested scope Assert.assertEquals(12,state.lookupLocalVariable("foo")); // found in nested scope
} }
@Test
public void testRootContextObject() { public void testRootContextObject() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(Inventor.class,state.getRootContextObject().getValue().getClass()); Assert.assertEquals(Inventor.class,state.getRootContextObject().getValue().getClass());
state.getEvaluationContext().setRootObject(null); state.getEvaluationContext().setRootObject(null);
assertEquals(null,state.getRootContextObject().getValue()); Assert.assertEquals(null,state.getRootContextObject().getValue());
state = new ExpressionState(new StandardEvaluationContext()); state = new ExpressionState(new StandardEvaluationContext());
assertEquals(TypedValue.NULL_TYPED_VALUE,state.getRootContextObject()); Assert.assertEquals(TypedValue.NULL_TYPED_VALUE,state.getRootContextObject());
((StandardEvaluationContext)state.getEvaluationContext()).setRootObject(null,TypeDescriptor.NULL); ((StandardEvaluationContext)state.getEvaluationContext()).setRootObject(null,TypeDescriptor.NULL);
assertEquals(null,state.getRootContextObject().getValue()); Assert.assertEquals(null,state.getRootContextObject().getValue());
} }
@Test
public void testActiveContextObject() { public void testActiveContextObject() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(state.getRootContextObject().getValue(),state.getActiveContextObject().getValue()); Assert.assertEquals(state.getRootContextObject().getValue(),state.getActiveContextObject().getValue());
state.pushActiveContextObject(new TypedValue(34)); state.pushActiveContextObject(new TypedValue(34));
assertEquals(34,state.getActiveContextObject().getValue()); Assert.assertEquals(34,state.getActiveContextObject().getValue());
state.pushActiveContextObject(new TypedValue("hello")); state.pushActiveContextObject(new TypedValue("hello"));
assertEquals("hello",state.getActiveContextObject().getValue()); Assert.assertEquals("hello",state.getActiveContextObject().getValue());
state.popActiveContextObject(); state.popActiveContextObject();
assertEquals(34,state.getActiveContextObject().getValue()); Assert.assertEquals(34,state.getActiveContextObject().getValue());
state.popActiveContextObject(); state.popActiveContextObject();
assertEquals(state.getRootContextObject().getValue(),state.getActiveContextObject().getValue()); Assert.assertEquals(state.getRootContextObject().getValue(),state.getActiveContextObject().getValue());
state = new ExpressionState(new StandardEvaluationContext()); state = new ExpressionState(new StandardEvaluationContext());
assertEquals(TypedValue.NULL_TYPED_VALUE,state.getActiveContextObject()); Assert.assertEquals(TypedValue.NULL_TYPED_VALUE,state.getActiveContextObject());
} }
@Test
public void testPopulatedNestedScopes() { public void testPopulatedNestedScopes() {
ExpressionState state = getState(); ExpressionState state = getState();
assertNull(state.lookupLocalVariable("foo")); Assert.assertNull(state.lookupLocalVariable("foo"));
state.enterScope("foo",34); state.enterScope("foo",34);
assertEquals(34,state.lookupLocalVariable("foo")); Assert.assertEquals(34,state.lookupLocalVariable("foo"));
state.enterScope(null); state.enterScope(null);
state.setLocalVariable("foo",12); state.setLocalVariable("foo",12);
assertEquals(12,state.lookupLocalVariable("foo")); Assert.assertEquals(12,state.lookupLocalVariable("foo"));
state.exitScope(); state.exitScope();
assertEquals(34,state.lookupLocalVariable("foo")); Assert.assertEquals(34,state.lookupLocalVariable("foo"));
state.exitScope(); state.exitScope();
assertNull(state.lookupLocalVariable("goo")); Assert.assertNull(state.lookupLocalVariable("goo"));
} }
@Test
public void testPopulatedNestedScopesMap() { public void testPopulatedNestedScopesMap() {
ExpressionState state = getState(); ExpressionState state = getState();
assertNull(state.lookupLocalVariable("foo")); Assert.assertNull(state.lookupLocalVariable("foo"));
assertNull(state.lookupLocalVariable("goo")); Assert.assertNull(state.lookupLocalVariable("goo"));
Map<String,Object> m = new HashMap<String,Object>(); Map<String,Object> m = new HashMap<String,Object>();
m.put("foo",34); m.put("foo",34);
m.put("goo","abc"); m.put("goo","abc");
state.enterScope(m); state.enterScope(m);
assertEquals(34,state.lookupLocalVariable("foo")); Assert.assertEquals(34,state.lookupLocalVariable("foo"));
assertEquals("abc",state.lookupLocalVariable("goo")); Assert.assertEquals("abc",state.lookupLocalVariable("goo"));
state.enterScope(null); state.enterScope(null);
state.setLocalVariable("foo",12); state.setLocalVariable("foo",12);
assertEquals(12,state.lookupLocalVariable("foo")); Assert.assertEquals(12,state.lookupLocalVariable("foo"));
assertEquals("abc",state.lookupLocalVariable("goo")); Assert.assertEquals("abc",state.lookupLocalVariable("goo"));
state.exitScope(); state.exitScope();
state.exitScope(); state.exitScope();
assertNull(state.lookupLocalVariable("foo")); Assert.assertNull(state.lookupLocalVariable("foo"));
assertNull(state.lookupLocalVariable("goo")); Assert.assertNull(state.lookupLocalVariable("goo"));
} }
@Test
public void testOperators() throws Exception { public void testOperators() throws Exception {
ExpressionState state = getState(); ExpressionState state = getState();
try { try {
state.operate(Operation.ADD,1,2); state.operate(Operation.ADD,1,2);
fail("should have failed"); Assert.fail("should have failed");
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
SpelException sEx = (SpelException)ee; SpelEvaluationException sEx = (SpelEvaluationException)ee;
assertEquals(SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES,sEx.getMessageUnformatted()); Assert.assertEquals(SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES,sEx.getMessageUnformatted());
} }
try { try {
state.operate(Operation.ADD,null,null); state.operate(Operation.ADD,null,null);
fail("should have failed"); Assert.fail("should have failed");
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
SpelException sEx = (SpelException)ee; SpelEvaluationException sEx = (SpelEvaluationException)ee;
assertEquals(SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES,sEx.getMessageUnformatted()); Assert.assertEquals(SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES,sEx.getMessageUnformatted());
} }
} }
@Test
public void testComparator() { public void testComparator() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(state.getEvaluationContext().getTypeComparator(),state.getTypeComparator()); Assert.assertEquals(state.getEvaluationContext().getTypeComparator(),state.getTypeComparator());
} }
@Test
public void testTypeLocator() throws EvaluationException { public void testTypeLocator() throws EvaluationException {
ExpressionState state = getState(); ExpressionState state = getState();
assertNotNull(state.getEvaluationContext().getTypeLocator()); Assert.assertNotNull(state.getEvaluationContext().getTypeLocator());
assertEquals(Integer.class,state.findType("java.lang.Integer")); Assert.assertEquals(Integer.class,state.findType("java.lang.Integer"));
try { try {
state.findType("someMadeUpName"); state.findType("someMadeUpName");
fail("Should have failed to find it"); Assert.fail("Should have failed to find it");
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
SpelException sEx = (SpelException)ee; SpelEvaluationException sEx = (SpelEvaluationException)ee;
assertEquals(SpelMessages.TYPE_NOT_FOUND,sEx.getMessageUnformatted()); Assert.assertEquals(SpelMessages.TYPE_NOT_FOUND,sEx.getMessageUnformatted());
} }
} }
@Test
public void testTypeConversion() throws EvaluationException { public void testTypeConversion() throws EvaluationException {
ExpressionState state = getState(); ExpressionState state = getState();
String s = (String)state.convertValue(34,TypeDescriptor.valueOf(String.class)); String s = (String)state.convertValue(34,TypeDescriptor.valueOf(String.class));
assertEquals("34",s); Assert.assertEquals("34",s);
s = (String)state.convertValue(new TypedValue(34),TypeDescriptor.valueOf(String.class)); s = (String)state.convertValue(new TypedValue(34),TypeDescriptor.valueOf(String.class));
assertEquals("34",s); Assert.assertEquals("34",s);
} }
@Test
public void testPropertyAccessors() { public void testPropertyAccessors() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(state.getEvaluationContext().getPropertyAccessors(),state.getPropertyAccessors()); Assert.assertEquals(state.getEvaluationContext().getPropertyAccessors(),state.getPropertyAccessors());
} }
/** /**

View File

@ -19,28 +19,27 @@ package org.springframework.expression.spel;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import junit.framework.TestCase; import junit.framework.Assert;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException; import org.springframework.expression.ParseException;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
///CLOVER:OFF
/** /**
* Common superclass for expression tests. * Common superclass for expression tests.
* *
* @author Andy Clement * @author Andy Clement
*/ */
public abstract class ExpressionTestCase extends TestCase { public abstract class ExpressionTestCase {
private final static boolean DEBUG = false; private final static boolean DEBUG = false;
protected final static boolean SHOULD_BE_WRITABLE = true; protected final static boolean SHOULD_BE_WRITABLE = true;
protected final static boolean SHOULD_NOT_BE_WRITABLE = false; protected final static boolean SHOULD_NOT_BE_WRITABLE = false;
protected final static SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); protected final static ExpressionParser parser = SpelExpressionParserFactory.getParser();
protected final static StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext(); protected final static StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
/** /**
@ -54,13 +53,13 @@ public abstract class ExpressionTestCase extends TestCase {
try { try {
Expression expr = parser.parseExpression(expression); Expression expr = parser.parseExpression(expression);
if (expr == null) { if (expr == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
if (DEBUG) { if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, expr); SpelUtilities.printAbstractSyntaxTree(System.out, expr);
} }
// Class<?> expressionType = expr.getValueType(); // Class<?> expressionType = expr.getValueType();
// assertEquals("Type of the expression is not as expected. Should be '"+expectedResultType+"' but is // Assert.assertEquals("Type of the expression is not as expected. Should be '"+expectedResultType+"' but is
// '"+expressionType+"'", // '"+expressionType+"'",
// expectedResultType,expressionType); // expectedResultType,expressionType);
@ -71,12 +70,12 @@ public abstract class ExpressionTestCase extends TestCase {
if (expectedValue == null) { if (expectedValue == null) {
return; // no point doing other checks return; // no point doing other checks
} }
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, Assert.assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue,
null); null);
} }
Class<?> resultType = value.getClass(); Class<?> resultType = value.getClass();
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType Assert.assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType
+ "' but result was of type '" + resultType + "'", expectedResultType, resultType); + "' but result was of type '" + resultType + "'", expectedResultType, resultType);
// .equals/* isAssignableFrom */(resultType), truers); // .equals/* isAssignableFrom */(resultType), truers);
@ -84,17 +83,17 @@ public abstract class ExpressionTestCase extends TestCase {
// in the above expression... // in the above expression...
if (expectedValue instanceof String) { if (expectedValue instanceof String) {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, Assert.assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
ExpressionTestCase.stringValueOf(value)); ExpressionTestCase.stringValueOf(value));
} else { } else {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value); Assert.assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
} }
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
ee.printStackTrace(); ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage()); Assert.fail("Unexpected Exception: " + ee.getMessage());
} catch (ParseException pe) { } catch (ParseException pe) {
pe.printStackTrace(); pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage()); Assert.fail("Unexpected Exception: " + pe.getMessage());
} }
} }
@ -102,13 +101,13 @@ public abstract class ExpressionTestCase extends TestCase {
try { try {
Expression expr = parser.parseExpression(expression); Expression expr = parser.parseExpression(expression);
if (expr == null) { if (expr == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
if (DEBUG) { if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, expr); SpelUtilities.printAbstractSyntaxTree(System.out, expr);
} }
// Class<?> expressionType = expr.getValueType(); // Class<?> expressionType = expr.getValueType();
// assertEquals("Type of the expression is not as expected. Should be '"+expectedResultType+"' but is // Assert.assertEquals("Type of the expression is not as expected. Should be '"+expectedResultType+"' but is
// '"+expressionType+"'", // '"+expressionType+"'",
// expectedResultType,expressionType); // expectedResultType,expressionType);
@ -116,23 +115,23 @@ public abstract class ExpressionTestCase extends TestCase {
if (value == null) { if (value == null) {
if (expectedValue == null) if (expectedValue == null)
return; // no point doing other checks return; // no point doing other checks
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, Assert.assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue,
null); null);
} }
Class<?> resultType = value.getClass(); Class<?> resultType = value.getClass();
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType Assert.assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType
+ "' but result was of type '" + resultType + "'", expectedResultType, resultType); + "' but result was of type '" + resultType + "'", expectedResultType, resultType);
// .equals/* isAssignableFrom */(resultType), truers); // .equals/* isAssignableFrom */(resultType), truers);
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value); Assert.assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
// isAssignableFrom would allow some room for compatibility // isAssignableFrom would allow some room for compatibility
// in the above expression... // in the above expression...
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
SpelException ex = (SpelException) ee; SpelEvaluationException ex = (SpelEvaluationException) ee;
ex.printStackTrace(); ex.printStackTrace();
fail("Unexpected EvaluationException: " + ex.getMessage()); Assert.fail("Unexpected EvaluationException: " + ex.getMessage());
} catch (ParseException pe) { } catch (ParseException pe) {
fail("Unexpected ParseException: " + pe.getMessage()); Assert.fail("Unexpected ParseException: " + pe.getMessage());
} }
} }
@ -151,7 +150,7 @@ public abstract class ExpressionTestCase extends TestCase {
try { try {
Expression e = parser.parseExpression(expression); Expression e = parser.parseExpression(expression);
if (e == null) { if (e == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
if (DEBUG) { if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, e); SpelUtilities.printAbstractSyntaxTree(System.out, e);
@ -161,19 +160,19 @@ public abstract class ExpressionTestCase extends TestCase {
if (expectedValue == null) if (expectedValue == null)
return; // no point doing other return; // no point doing other
// checks // checks
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, Assert.assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue,
null); null);
} }
Class<? extends Object> resultType = value.getClass(); Class<? extends Object> resultType = value.getClass();
if (expectedValue instanceof String) { if (expectedValue instanceof String) {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, Assert.assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
ExpressionTestCase.stringValueOf(value)); ExpressionTestCase.stringValueOf(value));
} else { } else {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value); Assert.assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
} }
// assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, // Assert.assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
// ExpressionTestCase.stringValueOf(value)); // ExpressionTestCase.stringValueOf(value));
assertEquals("Type of the result was not as expected. Expected '" + expectedClassOfResult Assert.assertEquals("Type of the result was not as expected. Expected '" + expectedClassOfResult
+ "' but result was of type '" + resultType + "'", expectedClassOfResult + "' but result was of type '" + resultType + "'", expectedClassOfResult
.equals/* isAssignableFrom */(resultType), true); .equals/* isAssignableFrom */(resultType), true);
// TODO isAssignableFrom would allow some room for compatibility // TODO isAssignableFrom would allow some room for compatibility
@ -182,16 +181,16 @@ public abstract class ExpressionTestCase extends TestCase {
boolean isWritable = e.isWritable(eContext); boolean isWritable = e.isWritable(eContext);
if (isWritable != shouldBeWritable) { if (isWritable != shouldBeWritable) {
if (shouldBeWritable) if (shouldBeWritable)
fail("Expected the expression to be writable but it is not"); Assert.fail("Expected the expression to be writable but it is not");
else else
fail("Expected the expression to be readonly but it is not"); Assert.fail("Expected the expression to be readonly but it is not");
} }
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
ee.printStackTrace(); ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage()); Assert.fail("Unexpected Exception: " + ee.getMessage());
} catch (ParseException pe) { } catch (ParseException pe) {
pe.printStackTrace(); pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage()); Assert.fail("Unexpected Exception: " + pe.getMessage());
} }
} }
@ -222,7 +221,7 @@ public abstract class ExpressionTestCase extends TestCase {
try { try {
Expression expr = parser.parseExpression(expression); Expression expr = parser.parseExpression(expression);
if (expr == null) { if (expr == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
if (expectedReturnType != null) { if (expectedReturnType != null) {
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -231,18 +230,18 @@ public abstract class ExpressionTestCase extends TestCase {
@SuppressWarnings("unused") @SuppressWarnings("unused")
Object value = expr.getValue(eContext); Object value = expr.getValue(eContext);
} }
fail("Should have failed with message " + expectedMessage); Assert.fail("Should have failed with message " + expectedMessage);
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
SpelException ex = (SpelException) ee; SpelEvaluationException ex = (SpelEvaluationException) ee;
if (ex.getMessageUnformatted() != expectedMessage) { if (ex.getMessageUnformatted() != expectedMessage) {
System.out.println(ex.getMessage()); // System.out.println(ex.getMessage());
ex.printStackTrace(); ex.printStackTrace();
assertEquals("Failed to get expected message", expectedMessage, ex.getMessageUnformatted()); Assert.assertEquals("Failed to get expected message", expectedMessage, ex.getMessageUnformatted());
} }
if (otherProperties != null && otherProperties.length != 0) { if (otherProperties != null && otherProperties.length != 0) {
// first one is expected position of the error within the string // first one is expected position of the error within the string
int pos = ((Integer) otherProperties[0]).intValue(); int pos = ((Integer) otherProperties[0]).intValue();
assertEquals("Did not get correct position reported in error ", pos, ex.getPosition()); Assert.assertEquals("Did not get correct position reported in error ", pos, ex.getPosition());
if (otherProperties.length > 1) { if (otherProperties.length > 1) {
// Check inserts match // Check inserts match
Object[] inserts = ex.getInserts(); Object[] inserts = ex.getInserts();
@ -251,25 +250,25 @@ public abstract class ExpressionTestCase extends TestCase {
} }
if (inserts.length < otherProperties.length - 1) { if (inserts.length < otherProperties.length - 1) {
ex.printStackTrace(); ex.printStackTrace();
fail("Cannot check " + (otherProperties.length - 1) Assert.fail("Cannot check " + (otherProperties.length - 1)
+ " properties of the exception, it only has " + inserts.length + " inserts"); + " properties of the exception, it only has " + inserts.length + " inserts");
} }
for (int i = 1; i < otherProperties.length; i++) { for (int i = 1; i < otherProperties.length; i++) {
if (otherProperties[i] == null) { if (otherProperties[i] == null) {
if (inserts[i - 1] != null) { if (inserts[i - 1] != null) {
ex.printStackTrace(); ex.printStackTrace();
fail("Insert does not match, expected 'null' but insert value was '" + inserts[i - 1] Assert.fail("Insert does not match, expected 'null' but insert value was '" + inserts[i - 1]
+ "'"); + "'");
} }
} else if (inserts[i - 1] == null) { } else if (inserts[i - 1] == null) {
if (otherProperties[i] != null) { if (otherProperties[i] != null) {
ex.printStackTrace(); ex.printStackTrace();
fail("Insert does not match, expected '" + otherProperties[i] Assert.fail("Insert does not match, expected '" + otherProperties[i]
+ "' but insert value was 'null'"); + "' but insert value was 'null'");
} }
} else if (!inserts[i - 1].equals(otherProperties[i])) { } else if (!inserts[i - 1].equals(otherProperties[i])) {
ex.printStackTrace(); ex.printStackTrace();
fail("Insert does not match, expected '" + otherProperties[i] + "' but insert value was '" Assert.fail("Insert does not match, expected '" + otherProperties[i] + "' but insert value was '"
+ inserts[i - 1] + "'"); + inserts[i - 1] + "'");
} }
} }
@ -277,7 +276,7 @@ public abstract class ExpressionTestCase extends TestCase {
} }
} catch (ParseException pe) { } catch (ParseException pe) {
pe.printStackTrace(); pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage()); Assert.fail("Unexpected Exception: " + pe.getMessage());
} }
} }
@ -293,26 +292,29 @@ public abstract class ExpressionTestCase extends TestCase {
try { try {
Expression expr = parser.parseExpression(expression); Expression expr = parser.parseExpression(expression);
SpelUtilities.printAbstractSyntaxTree(System.out, expr); SpelUtilities.printAbstractSyntaxTree(System.out, expr);
fail("Parsing should have failed!"); Assert.fail("Parsing should have failed!");
} catch (ParseException pe) { } catch (ParseException pe) {
Throwable t = pe.getCause(); // pe.printStackTrace();
if (t == null) { // Throwable t = pe.getCause();
fail("ParseException caught with no defined cause"); // if (t == null) {
} // Assert.fail("ParseException caught with no defined cause");
if (!(t instanceof SpelException)) { // }
t.printStackTrace(); // if (!(t instanceof SpelEvaluationException)) {
fail("Cause of parse exception is not a SpelException"); // t.printStackTrace();
} // Assert.fail("Cause of parse exception is not a SpelException");
SpelException ex = (SpelException) t; // }
// SpelEvaluationException ex = (SpelEvaluationException) t;
// pe.printStackTrace();
SpelParseException ex = (SpelParseException)pe;
if (ex.getMessageUnformatted() != expectedMessage) { if (ex.getMessageUnformatted() != expectedMessage) {
System.out.println(ex.getMessage()); // System.out.println(ex.getMessage());
ex.printStackTrace(); ex.printStackTrace();
assertEquals("Failed to get expected message", expectedMessage, ex.getMessageUnformatted()); Assert.assertEquals("Failed to get expected message", expectedMessage, ex.getMessageUnformatted());
} }
if (otherProperties != null && otherProperties.length != 0) { if (otherProperties != null && otherProperties.length != 0) {
// first one is expected position of the error within the string // first one is expected position of the error within the string
int pos = ((Integer) otherProperties[0]).intValue(); int pos = ((Integer) otherProperties[0]).intValue();
assertEquals("Did not get correct position reported in error ", pos, ex.getPosition()); Assert.assertEquals("Did not get correct position reported in error ", pos, ex.getPosition());
if (otherProperties.length > 1) { if (otherProperties.length > 1) {
// Check inserts match // Check inserts match
Object[] inserts = ex.getInserts(); Object[] inserts = ex.getInserts();
@ -321,13 +323,13 @@ public abstract class ExpressionTestCase extends TestCase {
} }
if (inserts.length < otherProperties.length - 1) { if (inserts.length < otherProperties.length - 1) {
ex.printStackTrace(); ex.printStackTrace();
fail("Cannot check " + (otherProperties.length - 1) Assert.fail("Cannot check " + (otherProperties.length - 1)
+ " properties of the exception, it only has " + inserts.length + " inserts"); + " properties of the exception, it only has " + inserts.length + " inserts");
} }
for (int i = 1; i < otherProperties.length; i++) { for (int i = 1; i < otherProperties.length; i++) {
if (!inserts[i - 1].equals(otherProperties[i])) { if (!inserts[i - 1].equals(otherProperties[i])) {
ex.printStackTrace(); ex.printStackTrace();
fail("Insert does not match, expected '" + otherProperties[i] + "' but insert value was '" Assert.fail("Insert does not match, expected '" + otherProperties[i] + "' but insert value was '"
+ inserts[i - 1] + "'"); + inserts[i - 1] + "'");
} }
} }

View File

@ -19,6 +19,10 @@ package org.springframework.expression.spel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultTypeConverter; import org.springframework.core.convert.support.DefaultTypeConverter;
import org.springframework.core.convert.support.GenericTypeConverter; import org.springframework.core.convert.support.GenericTypeConverter;
@ -48,43 +52,45 @@ public class ExpressionTestsUsingCoreConversionService extends ExpressionTestCas
listOfInteger.add(6); listOfInteger.add(6);
} }
@Before
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); ExpressionTestsUsingCoreConversionService.typeDescriptorForListOfString = new TypeDescriptor(ExpressionTestsUsingCoreConversionService.class.getDeclaredField("listOfString"));
typeDescriptorForListOfString = new TypeDescriptor(ExpressionTestsUsingCoreConversionService.class.getDeclaredField("listOfString")); ExpressionTestsUsingCoreConversionService.typeDescriptorForListOfInteger = new TypeDescriptor(ExpressionTestsUsingCoreConversionService.class.getDeclaredField("listOfInteger"));
typeDescriptorForListOfInteger = new TypeDescriptor(ExpressionTestsUsingCoreConversionService.class.getDeclaredField("listOfInteger"));
} }
/** /**
* Test the service can convert what we are about to use in the expression evaluation tests. * Test the service can convert what we are about to use in the expression evaluation tests.
*/ */
@Test
public void testConversionsAvailable() throws Exception { public void testConversionsAvailable() throws Exception {
TypeConvertorUsingConversionService tcs = new TypeConvertorUsingConversionService(); TypeConvertorUsingConversionService tcs = new TypeConvertorUsingConversionService();
// ArrayList containing List<Integer> to List<String> // ArrayList containing List<Integer> to List<String>
Class<?> clazz = typeDescriptorForListOfString.getElementType(); Class<?> clazz = typeDescriptorForListOfString.getElementType();
assertEquals(String.class,clazz); Assert.assertEquals(String.class,clazz);
List l = (List) tcs.convertValue(listOfInteger, typeDescriptorForListOfString); List l = (List) tcs.convertValue(listOfInteger, typeDescriptorForListOfString);
assertNotNull(l); Assert.assertNotNull(l);
// ArrayList containing List<String> to List<Integer> // ArrayList containing List<String> to List<Integer>
clazz = typeDescriptorForListOfInteger.getElementType(); clazz = typeDescriptorForListOfInteger.getElementType();
assertEquals(Integer.class,clazz); Assert.assertEquals(Integer.class,clazz);
l = (List) tcs.convertValue(listOfString, typeDescriptorForListOfString); l = (List) tcs.convertValue(listOfString, typeDescriptorForListOfString);
assertNotNull(l); Assert.assertNotNull(l);
} }
@Test
public void testSetParameterizedList() throws Exception { public void testSetParameterizedList() throws Exception {
StandardEvaluationContext context = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
Expression e = parser.parseExpression("listOfInteger.size()"); Expression e = parser.parseExpression("listOfInteger.size()");
assertEquals(0,e.getValue(context,Integer.class).intValue()); Assert.assertEquals(0,e.getValue(context,Integer.class).intValue());
context.setTypeConverter(new TypeConvertorUsingConversionService()); context.setTypeConverter(new TypeConvertorUsingConversionService());
// Assign a List<String> to the List<Integer> field - the component elements should be converted // Assign a List<String> to the List<Integer> field - the component elements should be converted
parser.parseExpression("listOfInteger").setValue(context,listOfString); parser.parseExpression("listOfInteger").setValue(context,listOfString);
assertEquals(3,e.getValue(context,Integer.class).intValue()); // size now 3 Assert.assertEquals(3,e.getValue(context,Integer.class).intValue()); // size now 3
Class clazz = parser.parseExpression("listOfInteger[1].getClass()").getValue(context,Class.class); // element type correctly Integer Class clazz = parser.parseExpression("listOfInteger[1].getClass()").getValue(context,Class.class); // element type correctly Integer
assertEquals(Integer.class,clazz); Assert.assertEquals(Integer.class,clazz);
} }
@ -103,7 +109,7 @@ public class ExpressionTestsUsingCoreConversionService extends ExpressionTestCas
return this.service.canConvert(sourceType, typeDescriptor); return this.service.canConvert(sourceType, typeDescriptor);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("cast")
public <T> T convertValue(Object value, Class<T> targetType) throws EvaluationException { public <T> T convertValue(Object value, Class<T> targetType) throws EvaluationException {
return (T) this.service.convert(value,TypeDescriptor.valueOf(targetType)); return (T) this.service.convert(value,TypeDescriptor.valueOf(targetType));
} }

View File

@ -20,11 +20,17 @@ import java.io.PrintStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.ParseException; import org.springframework.expression.ParseException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ast.FormatHelper; import org.springframework.expression.spel.ast.FormatHelper;
import org.springframework.expression.spel.support.ReflectionHelper; import org.springframework.expression.spel.support.ReflectionHelper;
import org.springframework.expression.spel.support.ReflectivePropertyResolver;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeConverter; import org.springframework.expression.spel.support.StandardTypeConverter;
import org.springframework.expression.spel.support.ReflectionHelper.ArgsMatchKind; import org.springframework.expression.spel.support.ReflectionHelper.ArgsMatchKind;
@ -35,20 +41,23 @@ import org.springframework.expression.spel.support.ReflectionHelper.ArgsMatchKin
*/ */
public class HelperTests extends ExpressionTestCase { public class HelperTests extends ExpressionTestCase {
@Test
public void testFormatHelperForClassName() { public void testFormatHelperForClassName() {
assertEquals("java.lang.String",FormatHelper.formatClassNameForMessage(String.class)); Assert.assertEquals("java.lang.String",FormatHelper.formatClassNameForMessage(String.class));
assertEquals("java.lang.String[]",FormatHelper.formatClassNameForMessage(new String[1].getClass())); Assert.assertEquals("java.lang.String[]",FormatHelper.formatClassNameForMessage(new String[1].getClass()));
assertEquals("int[]",FormatHelper.formatClassNameForMessage(new int[1].getClass())); Assert.assertEquals("int[]",FormatHelper.formatClassNameForMessage(new int[1].getClass()));
assertEquals("int[][]",FormatHelper.formatClassNameForMessage(new int[1][2].getClass())); Assert.assertEquals("int[][]",FormatHelper.formatClassNameForMessage(new int[1][2].getClass()));
assertEquals("null",FormatHelper.formatClassNameForMessage(null)); Assert.assertEquals("null",FormatHelper.formatClassNameForMessage(null));
} }
@Test
public void testFormatHelperForMethod() { public void testFormatHelperForMethod() {
assertEquals("foo(java.lang.String)",FormatHelper.formatMethodForMessage("foo", String.class)); Assert.assertEquals("foo(java.lang.String)",FormatHelper.formatMethodForMessage("foo", String.class));
assertEquals("goo(java.lang.String,int[])",FormatHelper.formatMethodForMessage("goo", String.class,new int[1].getClass())); Assert.assertEquals("goo(java.lang.String,int[])",FormatHelper.formatMethodForMessage("goo", String.class,new int[1].getClass()));
assertEquals("boo()",FormatHelper.formatMethodForMessage("boo")); Assert.assertEquals("boo()",FormatHelper.formatMethodForMessage("boo"));
} }
@Test
public void testUtilities() throws ParseException { public void testUtilities() throws ParseException {
SpelExpression expr = (SpelExpression)parser.parseExpression("3+4+5+6+7-2"); SpelExpression expr = (SpelExpression)parser.parseExpression("3+4+5+6+7-2");
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
@ -75,16 +84,18 @@ public class HelperTests extends ExpressionTestCase {
// CompoundExpression value:2 // CompoundExpression value:2
// IntLiteral value:2 // IntLiteral value:2
// ===> Expression '3+4+5+6+7-2' - AST end // ===> Expression '3+4+5+6+7-2' - AST end
assertTrue(s.indexOf("===> Expression '3+4+5+6+7-2' - AST start")!=-1); Assert.assertTrue(s.indexOf("===> Expression '3+4+5+6+7-2' - AST start")!=-1);
assertTrue(s.indexOf(" OperatorPlus value:((((3 + 4) + 5) + 6) + 7) #children:2")!=-1); Assert.assertTrue(s.indexOf(" OperatorPlus value:((((3 + 4) + 5) + 6) + 7) #children:2")!=-1);
} }
@Test
public void testTypedValue() { public void testTypedValue() {
TypedValue tValue = new TypedValue("hello"); TypedValue tValue = new TypedValue("hello");
assertEquals(String.class,tValue.getTypeDescriptor().getType()); Assert.assertEquals(String.class,tValue.getTypeDescriptor().getType());
assertEquals("TypedValue: hello of type java.lang.String",tValue.toString()); Assert.assertEquals("TypedValue: hello of type java.lang.String",tValue.toString());
} }
@Test
public void testReflectionHelperCompareArguments_ExactMatching() { public void testReflectionHelperCompareArguments_ExactMatching() {
StandardTypeConverter typeConverter = new StandardTypeConverter(); StandardTypeConverter typeConverter = new StandardTypeConverter();
@ -95,6 +106,7 @@ public class HelperTests extends ExpressionTestCase {
checkMatch(new Class[]{String.class,Integer.class},new Class[]{String.class,Integer.class},typeConverter,ArgsMatchKind.EXACT); checkMatch(new Class[]{String.class,Integer.class},new Class[]{String.class,Integer.class},typeConverter,ArgsMatchKind.EXACT);
} }
@Test
public void testReflectionHelperCompareArguments_CloseMatching() { public void testReflectionHelperCompareArguments_CloseMatching() {
StandardTypeConverter typeConverter = new StandardTypeConverter(); StandardTypeConverter typeConverter = new StandardTypeConverter();
@ -108,6 +120,7 @@ public class HelperTests extends ExpressionTestCase {
checkMatch(new Class[]{String.class,Sub.class},new Class[]{String.class,Super.class},typeConverter,ArgsMatchKind.CLOSE); checkMatch(new Class[]{String.class,Sub.class},new Class[]{String.class,Super.class},typeConverter,ArgsMatchKind.CLOSE);
} }
@Test
public void testReflectionHelperCompareArguments_RequiresConversionMatching() { public void testReflectionHelperCompareArguments_RequiresConversionMatching() {
// TODO these are failing - for investigation // TODO these are failing - for investigation
StandardTypeConverter typeConverter = new StandardTypeConverter(); StandardTypeConverter typeConverter = new StandardTypeConverter();
@ -125,6 +138,7 @@ public class HelperTests extends ExpressionTestCase {
checkMatch(new Class[]{Integer.TYPE,Sub.class,Boolean.TYPE},new Class[]{Integer.class, Super.class,Boolean.class},typeConverter,ArgsMatchKind.REQUIRES_CONVERSION,0,2); checkMatch(new Class[]{Integer.TYPE,Sub.class,Boolean.TYPE},new Class[]{Integer.class, Super.class,Boolean.class},typeConverter,ArgsMatchKind.REQUIRES_CONVERSION,0,2);
} }
@Test
public void testReflectionHelperCompareArguments_NotAMatch() { public void testReflectionHelperCompareArguments_NotAMatch() {
StandardTypeConverter typeConverter = new StandardTypeConverter(); StandardTypeConverter typeConverter = new StandardTypeConverter();
@ -132,6 +146,7 @@ public class HelperTests extends ExpressionTestCase {
checkMatch(new Class[]{Super.class,String.class},new Class[]{Sub.class,String.class},typeConverter,null); checkMatch(new Class[]{Super.class,String.class},new Class[]{Sub.class,String.class},typeConverter,null);
} }
@Test
public void testReflectionHelperCompareArguments_Varargs_ExactMatching() { public void testReflectionHelperCompareArguments_Varargs_ExactMatching() {
StandardTypeConverter tc = new StandardTypeConverter(); StandardTypeConverter tc = new StandardTypeConverter();
Class<?> stringArrayClass = new String[0].getClass(); Class<?> stringArrayClass = new String[0].getClass();
@ -184,6 +199,7 @@ public class HelperTests extends ExpressionTestCase {
// what happens on (Integer,String) passed to (Integer[]) ? // what happens on (Integer,String) passed to (Integer[]) ?
} }
@Test
public void testConvertArguments() throws Exception { public void testConvertArguments() throws Exception {
StandardTypeConverter tc = new StandardTypeConverter(); StandardTypeConverter tc = new StandardTypeConverter();
@ -208,6 +224,7 @@ public class HelperTests extends ExpressionTestCase {
checkArguments(args, "3","false","3.0"); checkArguments(args, "3","false","3.0");
} }
@Test
public void testConvertArguments2() throws EvaluationException { public void testConvertArguments2() throws EvaluationException {
StandardTypeConverter tc = new StandardTypeConverter(); StandardTypeConverter tc = new StandardTypeConverter();
@ -230,9 +247,9 @@ public class HelperTests extends ExpressionTestCase {
args = new Object[]{3,false,3.0f}; args = new Object[]{3,false,3.0f};
try { try {
ReflectionHelper.convertAllArguments(new Class[]{String.class,String[].class}, true, null, args); ReflectionHelper.convertAllArguments(new Class[]{String.class,String[].class}, true, null, args);
fail("Should have failed because no converter supplied"); Assert.fail("Should have failed because no converter supplied");
} catch (SpelException se) { } catch (SpelEvaluationException se) {
assertEquals(SpelMessages.TYPE_CONVERSION_ERROR,se.getMessageUnformatted()); Assert.assertEquals(SpelMessages.TYPE_CONVERSION_ERROR,se.getMessageUnformatted());
} }
// null value // null value
@ -241,21 +258,78 @@ public class HelperTests extends ExpressionTestCase {
checkArguments(args,"3",null,"3.0"); checkArguments(args,"3",null,"3.0");
} }
@Test
public void testSetupArguments() { public void testSetupArguments() {
Object[] newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(new Class[]{new String[0].getClass()},"a","b","c"); Object[] newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(new Class[]{new String[0].getClass()},"a","b","c");
assertEquals(1,newArray.length); Assert.assertEquals(1,newArray.length);
Object firstParam = newArray[0]; Object firstParam = newArray[0];
assertEquals(String.class,firstParam.getClass().getComponentType()); Assert.assertEquals(String.class,firstParam.getClass().getComponentType());
Object[] firstParamArray = (Object[])firstParam; Object[] firstParamArray = (Object[])firstParam;
assertEquals(3,firstParamArray.length); Assert.assertEquals(3,firstParamArray.length);
assertEquals("a",firstParamArray[0]); Assert.assertEquals("a",firstParamArray[0]);
assertEquals("b",firstParamArray[1]); Assert.assertEquals("b",firstParamArray[1]);
assertEquals("c",firstParamArray[2]); Assert.assertEquals("c",firstParamArray[2]);
} }
@Test
public void testReflectivePropertyResolver() throws Exception {
ReflectivePropertyResolver rpr = new ReflectivePropertyResolver();
Tester t = new Tester();
t.setProperty("hello");
EvaluationContext ctx = new StandardEvaluationContext(t);
Assert.assertTrue(rpr.canRead(ctx, t, "property"));
Assert.assertEquals("hello",rpr.read(ctx, t, "property").getValue());
Assert.assertEquals("hello",rpr.read(ctx, t, "property").getValue()); // cached accessor used
Assert.assertTrue(rpr.canRead(ctx, t, "field"));
Assert.assertEquals(3,rpr.read(ctx, t, "field").getValue());
Assert.assertEquals(3,rpr.read(ctx, t, "field").getValue()); // cached accessor used
Assert.assertTrue(rpr.canWrite(ctx, t, "property"));
rpr.write(ctx, t, "property","goodbye");
rpr.write(ctx, t, "property","goodbye"); // cached accessor used
Assert.assertTrue(rpr.canWrite(ctx, t, "field"));
rpr.write(ctx, t, "field",12);
rpr.write(ctx, t, "field",12);
// Attempted write as first activity on this field and property to drive testing
// of populating type descriptor cache
rpr.write(ctx,t,"field2",3);
rpr.write(ctx, t, "property2","doodoo");
Assert.assertEquals(3,rpr.read(ctx,t,"field2").getValue());
// Attempted read as first activity on this field and property (no canRead before them)
Assert.assertEquals(0,rpr.read(ctx,t,"field3").getValue());
Assert.assertEquals("doodoo",rpr.read(ctx,t,"property3").getValue());
// Access through is method
// Assert.assertEquals(0,rpr.read(ctx,t,"field3").getValue());
Assert.assertEquals(false,rpr.read(ctx,t,"property4").getValue());
Assert.assertTrue(rpr.canRead(ctx,t,"property4"));
}
// test classes // test classes
static class Tester {
String property;
public int field = 3;
public int field2;
public int field3 = 0;
String property2;
String property3 = "doodoo";
boolean property4 = false;
public String getProperty() { return property; }
public void setProperty(String value) { property = value; }
public void setProperty2(String value) { property2 = value; }
public String getProperty3() { return property3; }
public boolean isProperty4() { return property4; }
}
static class Super { static class Super {
} }
@ -273,25 +347,25 @@ public class HelperTests extends ExpressionTestCase {
private void checkMatch(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter,ArgsMatchKind expectedMatchKind,int... argsForConversion) { private void checkMatch(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter,ArgsMatchKind expectedMatchKind,int... argsForConversion) {
ReflectionHelper.ArgumentsMatchInfo matchInfo = ReflectionHelper.compareArguments(expectedTypes, inputTypes, typeConverter); ReflectionHelper.ArgumentsMatchInfo matchInfo = ReflectionHelper.compareArguments(expectedTypes, inputTypes, typeConverter);
if (expectedMatchKind==null) { if (expectedMatchKind==null) {
assertNull("Did not expect them to match in any way", matchInfo); Assert.assertNull("Did not expect them to match in any way", matchInfo);
} else { } else {
assertNotNull("Should not be a null match", matchInfo); Assert.assertNotNull("Should not be a null match", matchInfo);
} }
if (expectedMatchKind==ArgsMatchKind.EXACT) { if (expectedMatchKind==ArgsMatchKind.EXACT) {
assertTrue(matchInfo.isExactMatch()); Assert.assertTrue(matchInfo.isExactMatch());
assertNull(matchInfo.argsRequiringConversion); Assert.assertNull(matchInfo.argsRequiringConversion);
} else if (expectedMatchKind==ArgsMatchKind.CLOSE) { } else if (expectedMatchKind==ArgsMatchKind.CLOSE) {
assertTrue(matchInfo.isCloseMatch()); Assert.assertTrue(matchInfo.isCloseMatch());
assertNull(matchInfo.argsRequiringConversion); Assert.assertNull(matchInfo.argsRequiringConversion);
} else if (expectedMatchKind==ArgsMatchKind.REQUIRES_CONVERSION) { } else if (expectedMatchKind==ArgsMatchKind.REQUIRES_CONVERSION) {
assertTrue("expected to be a match requiring conversion, but was "+matchInfo,matchInfo.isMatchRequiringConversion()); Assert.assertTrue("expected to be a match requiring conversion, but was "+matchInfo,matchInfo.isMatchRequiringConversion());
if (argsForConversion==null) { if (argsForConversion==null) {
fail("there are arguments that need conversion"); Assert.fail("there are arguments that need conversion");
} }
assertEquals("The array of args that need conversion is different length to that expected",argsForConversion.length, matchInfo.argsRequiringConversion.length); Assert.assertEquals("The array of args that need conversion is different length to that expected",argsForConversion.length, matchInfo.argsRequiringConversion.length);
for (int a=0;a<argsForConversion.length;a++) { for (int a=0;a<argsForConversion.length;a++) {
assertEquals(argsForConversion[a],matchInfo.argsRequiringConversion[a]); Assert.assertEquals(argsForConversion[a],matchInfo.argsRequiringConversion[a]);
} }
} }
} }
@ -302,37 +376,37 @@ public class HelperTests extends ExpressionTestCase {
private void checkMatch2(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter,ArgsMatchKind expectedMatchKind,int... argsForConversion) { private void checkMatch2(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter,ArgsMatchKind expectedMatchKind,int... argsForConversion) {
ReflectionHelper.ArgumentsMatchInfo matchInfo = ReflectionHelper.compareArgumentsVarargs(expectedTypes, inputTypes, typeConverter); ReflectionHelper.ArgumentsMatchInfo matchInfo = ReflectionHelper.compareArgumentsVarargs(expectedTypes, inputTypes, typeConverter);
if (expectedMatchKind==null) { if (expectedMatchKind==null) {
assertNull("Did not expect them to match in any way: "+matchInfo, matchInfo); Assert.assertNull("Did not expect them to match in any way: "+matchInfo, matchInfo);
} else { } else {
assertNotNull("Should not be a null match", matchInfo); Assert.assertNotNull("Should not be a null match", matchInfo);
} }
if (expectedMatchKind==ArgsMatchKind.EXACT) { if (expectedMatchKind==ArgsMatchKind.EXACT) {
assertTrue(matchInfo.isExactMatch()); Assert.assertTrue(matchInfo.isExactMatch());
assertNull(matchInfo.argsRequiringConversion); Assert.assertNull(matchInfo.argsRequiringConversion);
} else if (expectedMatchKind==ArgsMatchKind.CLOSE) { } else if (expectedMatchKind==ArgsMatchKind.CLOSE) {
assertTrue(matchInfo.isCloseMatch()); Assert.assertTrue(matchInfo.isCloseMatch());
assertNull(matchInfo.argsRequiringConversion); Assert.assertNull(matchInfo.argsRequiringConversion);
} else if (expectedMatchKind==ArgsMatchKind.REQUIRES_CONVERSION) { } else if (expectedMatchKind==ArgsMatchKind.REQUIRES_CONVERSION) {
assertTrue("expected to be a match requiring conversion, but was "+matchInfo,matchInfo.isMatchRequiringConversion()); Assert.assertTrue("expected to be a match requiring conversion, but was "+matchInfo,matchInfo.isMatchRequiringConversion());
if (argsForConversion==null) { if (argsForConversion==null) {
fail("there are arguments that need conversion"); Assert.fail("there are arguments that need conversion");
} }
assertEquals("The array of args that need conversion is different length to that expected",argsForConversion.length, matchInfo.argsRequiringConversion.length); Assert.assertEquals("The array of args that need conversion is different length to that expected",argsForConversion.length, matchInfo.argsRequiringConversion.length);
for (int a=0;a<argsForConversion.length;a++) { for (int a=0;a<argsForConversion.length;a++) {
assertEquals(argsForConversion[a],matchInfo.argsRequiringConversion[a]); Assert.assertEquals(argsForConversion[a],matchInfo.argsRequiringConversion[a]);
} }
} }
} }
private void checkArguments(Object[] args, Object... expected) { private void checkArguments(Object[] args, Object... expected) {
assertEquals(expected.length,args.length); Assert.assertEquals(expected.length,args.length);
for (int i=0;i<expected.length;i++) { for (int i=0;i<expected.length;i++) {
checkArgument(expected[i],args[i]); checkArgument(expected[i],args[i]);
} }
} }
private void checkArgument(Object expected, Object actual) { private void checkArgument(Object expected, Object actual) {
assertEquals(expected,actual); Assert.assertEquals(expected,actual);
} }
} }

View File

@ -17,6 +17,9 @@ package org.springframework.expression.spel;
import java.util.ArrayList; import java.util.ArrayList;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
/** /**
@ -28,90 +31,106 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
*/ */
public class InProgressTests extends ExpressionTestCase { public class InProgressTests extends ExpressionTestCase {
@Test
public void testRelOperatorsBetween01() { public void testRelOperatorsBetween01() {
evaluate("1 between listOneFive", "true", Boolean.class); evaluate("1 between listOneFive", "true", Boolean.class);
// evaluate("1 between {1, 5}", "true", Boolean.class); // no inline list building at the moment // evaluate("1 between {1, 5}", "true", Boolean.class); // no inline list building at the moment
} }
@Test
public void testRelOperatorsBetweenErrors01() { public void testRelOperatorsBetweenErrors01() {
evaluateAndCheckError("1 between T(String)", SpelMessages.BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST, 12); evaluateAndCheckError("1 between T(String)", SpelMessages.BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST, 10);
} }
@Test
public void testRelOperatorsBetweenErrors03() { public void testRelOperatorsBetweenErrors03() {
evaluateAndCheckError("1 between listOfNumbersUpToTen", SpelMessages.BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST, 10); evaluateAndCheckError("1 between listOfNumbersUpToTen", SpelMessages.BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST, 10);
} }
// PROJECTION // PROJECTION
@Test
public void testProjection01() { public void testProjection01() {
evaluate("listOfNumbersUpToTen.![#this<5?'y':'n']","[y, y, y, y, n, n, n, n, n, n]",ArrayList.class); evaluate("listOfNumbersUpToTen.![#this<5?'y':'n']","[y, y, y, y, n, n, n, n, n, n]",ArrayList.class);
// inline list creation not supported at the moment // inline list creation not supported at the moment
// evaluate("{1,2,3,4,5,6,7,8,9,10}.!{#isEven(#this)}", "[n, y, n, y, n, y, n, y, n, y]", ArrayList.class); // evaluate("{1,2,3,4,5,6,7,8,9,10}.!{#isEven(#this)}", "[n, y, n, y, n, y, n, y, n, y]", ArrayList.class);
} }
@Test
public void testProjection02() { public void testProjection02() {
// inline map creation not supported at the moment // inline map creation not supported at the moment
// evaluate("#{'a':'y','b':'n','c':'y'}.![value=='y'?key:null].nonnull().sort()", "[a, c]", ArrayList.class); // evaluate("#{'a':'y','b':'n','c':'y'}.![value=='y'?key:null].nonnull().sort()", "[a, c]", ArrayList.class);
evaluate("mapOfNumbersUpToTen.![key>5?value:null]", "[null, null, null, null, null, six, seven, eight, nine, ten]", ArrayList.class); evaluate("mapOfNumbersUpToTen.![key>5?value:null]", "[null, null, null, null, null, six, seven, eight, nine, ten]", ArrayList.class);
} }
@Test
public void testProjection05() { public void testProjection05() {
evaluateAndCheckError("'abc'.![true]", SpelMessages.PROJECTION_NOT_SUPPORTED_ON_TYPE); evaluateAndCheckError("'abc'.![true]", SpelMessages.PROJECTION_NOT_SUPPORTED_ON_TYPE);
} }
@Test
public void testProjection06() throws Exception { public void testProjection06() throws Exception {
SpelExpression expr = (SpelExpression)parser.parseExpression("'abc'.![true]"); SpelExpression expr = (SpelExpression)parser.parseExpression("'abc'.![true]");
assertEquals("'abc'.![true]",expr.toStringAST()); Assert.assertEquals("'abc'.![true]",expr.toStringAST());
assertFalse(expr.isWritable(new StandardEvaluationContext())); Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
} }
// SELECTION // SELECTION
@Test
public void testSelection02() { public void testSelection02() {
evaluate("testMap.keySet().?[#this matches '.*o.*']", "[monday]", ArrayList.class); evaluate("testMap.keySet().?[#this matches '.*o.*']", "[monday]", ArrayList.class);
evaluate("testMap.keySet().?[#this matches '.*r.*'].contains('saturday')", "true", Boolean.class); evaluate("testMap.keySet().?[#this matches '.*r.*'].contains('saturday')", "true", Boolean.class);
evaluate("testMap.keySet().?[#this matches '.*r.*'].size()", "3", Integer.class); evaluate("testMap.keySet().?[#this matches '.*r.*'].size()", "3", Integer.class);
} }
@Test
public void testSelectionError_NonBooleanSelectionCriteria() { public void testSelectionError_NonBooleanSelectionCriteria() {
evaluateAndCheckError("listOfNumbersUpToTen.?['nonboolean']", evaluateAndCheckError("listOfNumbersUpToTen.?['nonboolean']",
SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN); SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);
} }
@Test
public void testSelection03() { public void testSelection03() {
evaluate("mapOfNumbersUpToTen.?[key>5].size()", "5", Integer.class); evaluate("mapOfNumbersUpToTen.?[key>5].size()", "5", Integer.class);
// evaluate("listOfNumbersUpToTen.?{#this>5}", "5", ArrayList.class); // evaluate("listOfNumbersUpToTen.?{#this>5}", "5", ArrayList.class);
} }
@Test
public void testSelection04() { public void testSelection04() {
evaluateAndCheckError("mapOfNumbersUpToTen.?['hello'].size()",SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN); evaluateAndCheckError("mapOfNumbersUpToTen.?['hello'].size()",SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);
} }
@Test
public void testSelectionFirst01() { public void testSelectionFirst01() {
evaluate("listOfNumbersUpToTen.^[#isEven(#this) == 'y']", "2", Integer.class); evaluate("listOfNumbersUpToTen.^[#isEven(#this) == 'y']", "2", Integer.class);
} }
@Test
public void testSelectionFirst02() { public void testSelectionFirst02() {
evaluate("mapOfNumbersUpToTen.^[key>5].size()", "1", Integer.class); evaluate("mapOfNumbersUpToTen.^[key>5].size()", "1", Integer.class);
} }
@Test
public void testSelectionLast01() { public void testSelectionLast01() {
evaluate("listOfNumbersUpToTen.$[#isEven(#this) == 'y']", "10", Integer.class); evaluate("listOfNumbersUpToTen.$[#isEven(#this) == 'y']", "10", Integer.class);
} }
@Test
public void testSelectionLast02() { public void testSelectionLast02() {
evaluate("mapOfNumbersUpToTen.$[key>5].size()", "1", Integer.class); evaluate("mapOfNumbersUpToTen.$[key>5].size()", "1", Integer.class);
} }
@Test
public void testSelectionAST() throws Exception { public void testSelectionAST() throws Exception {
SpelExpression expr = (SpelExpression)parser.parseExpression("'abc'.^[true]"); SpelExpression expr = (SpelExpression)parser.parseExpression("'abc'.^[true]");
assertEquals("'abc'.^[true]",expr.toStringAST()); Assert.assertEquals("'abc'.^[true]",expr.toStringAST());
assertFalse(expr.isWritable(new StandardEvaluationContext())); Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
expr = (SpelExpression)parser.parseExpression("'abc'.?[true]"); expr = (SpelExpression)parser.parseExpression("'abc'.?[true]");
assertEquals("'abc'.?[true]",expr.toStringAST()); Assert.assertEquals("'abc'.?[true]",expr.toStringAST());
assertFalse(expr.isWritable(new StandardEvaluationContext())); Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
expr = (SpelExpression)parser.parseExpression("'abc'.$[true]"); expr = (SpelExpression)parser.parseExpression("'abc'.$[true]");
assertEquals("'abc'.$[true]",expr.toStringAST()); Assert.assertEquals("'abc'.$[true]",expr.toStringAST());
assertFalse(expr.isWritable(new StandardEvaluationContext())); Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
} }
// Constructor invocation // Constructor invocation

View File

@ -16,8 +16,9 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.TestCase; import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.common.LiteralExpression; import org.springframework.expression.common.LiteralExpression;
@ -26,8 +27,9 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
/** /**
* @author Andy Clement * @author Andy Clement
*/ */
public class LiteralExpressionTests extends TestCase { public class LiteralExpressionTests {
@Test
public void testGetValue() throws Exception { public void testGetValue() throws Exception {
LiteralExpression lEx = new LiteralExpression("somevalue"); LiteralExpression lEx = new LiteralExpression("somevalue");
checkString("somevalue", lEx.getValue()); checkString("somevalue", lEx.getValue());
@ -35,34 +37,36 @@ public class LiteralExpressionTests extends TestCase {
EvaluationContext ctx = new StandardEvaluationContext(); EvaluationContext ctx = new StandardEvaluationContext();
checkString("somevalue", lEx.getValue(ctx)); checkString("somevalue", lEx.getValue(ctx));
checkString("somevalue", lEx.getValue(ctx, String.class)); checkString("somevalue", lEx.getValue(ctx, String.class));
assertEquals("somevalue", lEx.getExpressionString()); Assert.assertEquals("somevalue", lEx.getExpressionString());
assertFalse(lEx.isWritable(new StandardEvaluationContext())); Assert.assertFalse(lEx.isWritable(new StandardEvaluationContext()));
} }
@Test
public void testSetValue() { public void testSetValue() {
try { try {
LiteralExpression lEx = new LiteralExpression("somevalue"); LiteralExpression lEx = new LiteralExpression("somevalue");
lEx.setValue(new StandardEvaluationContext(), "flibble"); lEx.setValue(new StandardEvaluationContext(), "flibble");
fail("Should have got an exception that the value cannot be set"); Assert.fail("Should have got an exception that the value cannot be set");
} }
catch (EvaluationException ee) { catch (EvaluationException ee) {
// success, not allowed - whilst here, check the expression value in the exception // success, not allowed - whilst here, check the expression value in the exception
assertEquals(ee.getExpressionString(), "somevalue"); Assert.assertEquals(ee.getExpressionString(), "somevalue");
} }
} }
@Test
public void testGetValueType() throws Exception { public void testGetValueType() throws Exception {
LiteralExpression lEx = new LiteralExpression("somevalue"); LiteralExpression lEx = new LiteralExpression("somevalue");
assertEquals(String.class, lEx.getValueType()); Assert.assertEquals(String.class, lEx.getValueType());
assertEquals(String.class, lEx.getValueType(new StandardEvaluationContext())); Assert.assertEquals(String.class, lEx.getValueType(new StandardEvaluationContext()));
} }
private void checkString(String expectedString, Object value) { private void checkString(String expectedString, Object value) {
if (!(value instanceof String)) { if (!(value instanceof String)) {
fail("Result was not a string, it was of type " + value.getClass() + " (value=" + value + ")"); Assert.fail("Result was not a string, it was of type " + value.getClass() + " (value=" + value + ")");
} }
if (!((String) value).equals(expectedString)) { if (!((String) value).equals(expectedString)) {
fail("Did not get expected result. Should have been '" + expectedString + "' but was '" + value + "'"); Assert.fail("Did not get expected result. Should have been '" + expectedString + "' but was '" + value + "'");
} }
} }

View File

@ -16,6 +16,9 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
/** /**
@ -25,47 +28,58 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
*/ */
public class LiteralTests extends ExpressionTestCase { public class LiteralTests extends ExpressionTestCase {
@Test
public void testLiteralBoolean01() { public void testLiteralBoolean01() {
evaluate("false", "false", Boolean.class); evaluate("false", "false", Boolean.class);
} }
@Test
public void testLiteralBoolean02() { public void testLiteralBoolean02() {
evaluate("true", "true", Boolean.class); evaluate("true", "true", Boolean.class);
} }
@Test
public void testLiteralInteger01() { public void testLiteralInteger01() {
evaluate("1", "1", Integer.class); evaluate("1", "1", Integer.class);
} }
@Test
public void testLiteralInteger02() { public void testLiteralInteger02() {
evaluate("1415", "1415", Integer.class); evaluate("1415", "1415", Integer.class);
} }
@Test
public void testLiteralString01() { public void testLiteralString01() {
evaluate("'Hello World'", "Hello World", String.class); evaluate("'Hello World'", "Hello World", String.class);
} }
@Test
public void testLiteralString02() { public void testLiteralString02() {
evaluate("'joe bloggs'", "joe bloggs", String.class); evaluate("'joe bloggs'", "joe bloggs", String.class);
} }
@Test
public void testLiteralString03() { public void testLiteralString03() {
evaluate("'hello'", "hello", String.class); evaluate("'hello'", "hello", String.class);
} }
@Test
public void testLiteralString04() { public void testLiteralString04() {
evaluate("'Tony''s Pizza'", "Tony's Pizza", String.class); evaluate("'Tony''s Pizza'", "Tony's Pizza", String.class);
evaluate("'Tony\\r''s Pizza'", "Tony\\r's Pizza", String.class); evaluate("'Tony\\r''s Pizza'", "Tony\\r's Pizza", String.class);
} }
@Test
public void testLiteralString05() { public void testLiteralString05() {
evaluate("\"Hello World\"", "Hello World", String.class); evaluate("\"Hello World\"", "Hello World", String.class);
} }
@Test
public void testLiteralString06() { public void testLiteralString06() {
evaluate("\"Hello ' World\"", "Hello ' World", String.class); evaluate("\"Hello ' World\"", "Hello ' World", String.class);
} }
@Test
public void testHexIntLiteral01() { public void testHexIntLiteral01() {
evaluate("0x7FFFF", "524287", Integer.class); evaluate("0x7FFFF", "524287", Integer.class);
evaluate("0x7FFFFL", 524287L, Long.class); evaluate("0x7FFFFL", 524287L, Long.class);
@ -73,18 +87,21 @@ public class LiteralTests extends ExpressionTestCase {
evaluate("0X7FFFFl", 524287L, Long.class); evaluate("0X7FFFFl", 524287L, Long.class);
} }
@Test
public void testLongIntLiteral01() { public void testLongIntLiteral01() {
evaluate("0xCAFEBABEL", 3405691582L, Long.class); evaluate("0xCAFEBABEL", 3405691582L, Long.class);
} }
@Test
public void testLongIntInteractions01() { public void testLongIntInteractions01() {
evaluate("0x20 * 2L", 64L, Long.class); evaluate("0x20 * 2L", 64L, Long.class);
// ask for the result to be made into an Integer // ask for the result to be made into an Integer
evaluateAndAskForReturnType("0x20 * 2L", 64, Integer.class); evaluateAndAskForReturnType("0x20 * 2L", 64, Integer.class);
// ask for the result to be made into an Integer knowing that it will not fit // ask for the result to be made into an Integer knowing that it will not fit
evaluateAndCheckError("0x1220 * 0xffffffffL", Integer.class, SpelMessages.TYPE_CONVERSION_ERROR, -1); evaluateAndCheckError("0x1220 * 0xffffffffL", Integer.class, SpelMessages.TYPE_CONVERSION_ERROR, 0);
} }
@Test
public void testSignedIntLiterals() { public void testSignedIntLiterals() {
evaluate("-1", -1, Integer.class); evaluate("-1", -1, Integer.class);
evaluate("-0xa", -10, Integer.class); evaluate("-0xa", -10, Integer.class);
@ -92,6 +109,7 @@ public class LiteralTests extends ExpressionTestCase {
evaluate("-0x20l", -32L, Long.class); evaluate("-0x20l", -32L, Long.class);
} }
@Test
public void testLiteralReal01_CreatingDoubles() { public void testLiteralReal01_CreatingDoubles() {
evaluate("1.25", 1.25d, Double.class); evaluate("1.25", 1.25d, Double.class);
evaluate("2.99", 2.99d, Double.class); evaluate("2.99", 2.99d, Double.class);
@ -104,46 +122,51 @@ public class LiteralTests extends ExpressionTestCase {
evaluate("-3.141D", -3.141d, Double.class); evaluate("-3.141D", -3.141d, Double.class);
} }
@Test
public void testLiteralReal02_CreatingFloats() { public void testLiteralReal02_CreatingFloats() {
// For now, everything becomes a double... // For now, everything becomes a double...
evaluate("1.25f", 1.25d, Double.class); evaluate("1.25f", 1.25d, Double.class);
evaluate("2.99f", 2.99d, Double.class); evaluate("2.5f", 2.5d, Double.class);
evaluate("-3.141f", -3.141d, Double.class); evaluate("-3.5f", -3.5d, Double.class);
evaluate("1.25F", 1.25d, Double.class); evaluate("1.25F", 1.25d, Double.class);
evaluate("2.99F", 2.99d, Double.class); evaluate("2.5F", 2.5d, Double.class);
evaluate("-3.141F", -3.141d, Double.class); evaluate("-3.5F", -3.5d, Double.class);
} }
@Test
public void testLiteralReal03_UsingExponents() { public void testLiteralReal03_UsingExponents() {
evaluate("6.0221415E+23", "6.0221415E23", Double.class); evaluate("6.0221415E+23", "6.0221415E23", Double.class);
evaluate("6.0221415e+23", "6.0221415E23", Double.class); evaluate("6.0221415e+23", "6.0221415E23", Double.class);
evaluate("6.0221415E+23d", "6.0221415E23", Double.class); evaluate("6.0221415E+23d", "6.0221415E23", Double.class);
evaluate("6.0221415e+23D", "6.0221415E23", Double.class); evaluate("6.0221415e+23D", "6.0221415E23", Double.class);
evaluate("6.0221415E+23f", "6.0221415E23", Double.class); evaluate("6E2f", 600.0d, Double.class);
evaluate("6.0221415e+23F", "6.0221415E23", Double.class);
} }
@Test
public void testLiteralReal04_BadExpressions() { public void testLiteralReal04_BadExpressions() {
parseAndCheckError("6.1e23e22", SpelMessages.PARSE_PROBLEM, 6, "mismatched input 'e22' expecting EOF"); parseAndCheckError("6.1e23e22", SpelMessages.MORE_INPUT, 6, "e22");
parseAndCheckError("6.1f23e22", SpelMessages.PARSE_PROBLEM, 4, "mismatched input '23e22' expecting EOF"); parseAndCheckError("6.1f23e22", SpelMessages.MORE_INPUT, 4, "23e22");
} }
@Test
public void testLiteralNull01() { public void testLiteralNull01() {
evaluate("null", null, null); evaluate("null", null, null);
} }
@Test
public void testConversions() { public void testConversions() {
// getting the expression type to be what we want - either: // getting the expression type to be what we want - either:
evaluate("new Integer(37).byteValue()", (byte) 37, Byte.class); // calling byteValue() on Integer.class evaluate("new Integer(37).byteValue()", (byte) 37, Byte.class); // calling byteValue() on Integer.class
evaluateAndAskForReturnType("new Integer(37)", (byte) 37, Byte.class); // relying on registered type converters evaluateAndAskForReturnType("new Integer(37)", (byte) 37, Byte.class); // relying on registered type converters
} }
@Test
public void testNotWritable() throws Exception { public void testNotWritable() throws Exception {
SpelExpression expr = (SpelExpression)parser.parseExpression("37"); SpelExpression expr = (SpelExpression)parser.parseExpression("37");
assertFalse(expr.isWritable(new StandardEvaluationContext())); Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
expr = (SpelExpression)parser.parseExpression("37L"); expr = (SpelExpression)parser.parseExpression("37L");
assertFalse(expr.isWritable(new StandardEvaluationContext())); Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
expr = (SpelExpression)parser.parseExpression("true"); expr = (SpelExpression)parser.parseExpression("true");
assertFalse(expr.isWritable(new StandardEvaluationContext())); Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
} }
} }

View File

@ -18,13 +18,17 @@ package org.springframework.expression.spel;
import java.util.Map; import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.PropertyAccessor; import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
import org.springframework.expression.spel.ast.CommonTypeDescriptors; import org.springframework.expression.spel.ast.CommonTypeDescriptors;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
/** /**
@ -34,32 +38,36 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
*/ */
public class MapAccessTests extends ExpressionTestCase { public class MapAccessTests extends ExpressionTestCase {
@Test
public void testSimpleMapAccess01() { public void testSimpleMapAccess01() {
evaluate("testMap.get('monday')", "montag", String.class); evaluate("testMap.get('monday')", "montag", String.class);
} }
@Test
public void testMapAccessThroughIndexer() { public void testMapAccessThroughIndexer() {
evaluate("testMap['monday']", "montag", String.class); evaluate("testMap['monday']", "montag", String.class);
} }
@Test
public void testCustomMapAccessor() throws Exception { public void testCustomMapAccessor() throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext ctx = TestScenarioCreator.getTestEvaluationContext();
ctx.addPropertyAccessor(new MapAccessor()); ctx.addPropertyAccessor(new MapAccessor());
Expression expr = parser.parseExpression("testMap.monday"); Expression expr = parser.parseExpression("testMap.monday");
Object value = expr.getValue(ctx, String.class); Object value = expr.getValue(ctx, String.class);
assertEquals("montag", value); Assert.assertEquals("montag", value);
} }
@Test
public void testVariableMapAccess() throws Exception { public void testVariableMapAccess() throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext ctx = TestScenarioCreator.getTestEvaluationContext();
ctx.setVariable("day", "saturday"); ctx.setVariable("day", "saturday");
Expression expr = parser.parseExpression("testMap[#day]"); Expression expr = parser.parseExpression("testMap[#day]");
Object value = expr.getValue(ctx, String.class); Object value = expr.getValue(ctx, String.class);
assertEquals("samstag", value); Assert.assertEquals("samstag", value);
} }

View File

@ -16,14 +16,16 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import org.junit.Test;
/** /**
* Tests invocation of methods. * Tests invocation of methods.
* *
* @author Andy Clement * @author Andy Clement
*/ */
@SuppressWarnings("unused")
public class MethodInvocationTests extends ExpressionTestCase { public class MethodInvocationTests extends ExpressionTestCase {
@Test
public void testSimpleAccess01() { public void testSimpleAccess01() {
evaluate("getPlaceOfBirth().getCity()", "SmilJan", String.class); evaluate("getPlaceOfBirth().getCity()", "SmilJan", String.class);
} }
@ -39,6 +41,7 @@ public class MethodInvocationTests extends ExpressionTestCase {
// evaluate("new int[]{4,3,2,1,2,3}.distinct().count()", 4, Integer.class); // evaluate("new int[]{4,3,2,1,2,3}.distinct().count()", 4, Integer.class);
// } // }
@Test
public void testStringClass() { public void testStringClass() {
evaluate("new java.lang.String('hello').charAt(2)", 'l', Character.class); evaluate("new java.lang.String('hello').charAt(2)", 'l', Character.class);
evaluate("new java.lang.String('hello').charAt(2).equals('l'.charAt(0))", true, Boolean.class); evaluate("new java.lang.String('hello').charAt(2).equals('l'.charAt(0))", true, Boolean.class);
@ -46,11 +49,13 @@ public class MethodInvocationTests extends ExpressionTestCase {
evaluate("' abcba '.trim()", "abcba", String.class); evaluate("' abcba '.trim()", "abcba", String.class);
} }
@Test
public void testNonExistentMethods() { public void testNonExistentMethods() {
// name is ok but madeup() does not exist // name is ok but madeup() does not exist
evaluateAndCheckError("name.madeup()", SpelMessages.METHOD_NOT_FOUND, 5); evaluateAndCheckError("name.madeup()", SpelMessages.METHOD_NOT_FOUND, 5);
} }
@Test
public void testWidening01() { public void testWidening01() {
// widening of int 3 to double 3 is OK // widening of int 3 to double 3 is OK
evaluate("new Double(3.0d).compareTo(8)", -1, Integer.class); evaluate("new Double(3.0d).compareTo(8)", -1, Integer.class);
@ -58,12 +63,14 @@ public class MethodInvocationTests extends ExpressionTestCase {
evaluate("new Double(3.0d).compareTo(2)", 1, Integer.class); evaluate("new Double(3.0d).compareTo(2)", 1, Integer.class);
} }
@Test
public void testArgumentConversion01() { public void testArgumentConversion01() {
// Rely on Double>String conversion for calling startsWith() // Rely on Double>String conversion for calling startsWith()
evaluate("new String('hello 2.0 to you').startsWith(7.0d)", false, Boolean.class); evaluate("new String('hello 2.0 to you').startsWith(7.0d)", false, Boolean.class);
evaluate("new String('7.0 foobar').startsWith(7.0d)", true, Boolean.class); evaluate("new String('7.0 foobar').startsWith(7.0d)", true, Boolean.class);
} }
@Test
public void testVarargsInvocation01() { public void testVarargsInvocation01() {
// Calling 'public int aVarargsMethod(String... strings)' // Calling 'public int aVarargsMethod(String... strings)'
evaluate("aVarargsMethod('a','b','c')", 3, Integer.class); evaluate("aVarargsMethod('a','b','c')", 3, Integer.class);
@ -75,6 +82,7 @@ public class MethodInvocationTests extends ExpressionTestCase {
// evaluate("aVarargsMethod(new String[]{'a','b','c'})", 3, Integer.class); // evaluate("aVarargsMethod(new String[]{'a','b','c'})", 3, Integer.class);
} }
@Test
public void testVarargsInvocation02() { public void testVarargsInvocation02() {
// Calling 'public int aVarargsMethod2(int i, String... strings)' - returns int+length_of_strings // Calling 'public int aVarargsMethod2(int i, String... strings)' - returns int+length_of_strings
evaluate("aVarargsMethod2(5,'a','b','c')", 8, Integer.class); evaluate("aVarargsMethod2(5,'a','b','c')", 8, Integer.class);
@ -86,6 +94,7 @@ public class MethodInvocationTests extends ExpressionTestCase {
// evaluate("aVarargsMethod2(8,new String[]{'a','b','c'})", 11, Integer.class); // evaluate("aVarargsMethod2(8,new String[]{'a','b','c'})", 11, Integer.class);
} }
@Test
public void testInvocationOnNullContextObject() { public void testInvocationOnNullContextObject() {
evaluateAndCheckError("null.toString()",SpelMessages.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED); evaluateAndCheckError("null.toString()",SpelMessages.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED);
} }

View File

@ -16,6 +16,9 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.OperatorOverloader; import org.springframework.expression.OperatorOverloader;
@ -49,6 +52,7 @@ public class OperatorOverloaderTests extends ExpressionTestCase {
} }
@Test
public void testSimpleOperations() throws Exception { public void testSimpleOperations() throws Exception {
// no built in support for this: // no built in support for this:
evaluateAndCheckError("'abc'+true",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("'abc'+true",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
@ -57,9 +61,9 @@ public class OperatorOverloaderTests extends ExpressionTestCase {
eContext.setOperatorOverloader(new StringAndBooleanAddition()); eContext.setOperatorOverloader(new StringAndBooleanAddition());
SpelExpression expr = (SpelExpression)parser.parseExpression("'abc'+true"); SpelExpression expr = (SpelExpression)parser.parseExpression("'abc'+true");
assertEquals("abctrue",expr.getValue(eContext)); Assert.assertEquals("abctrue",expr.getValue(eContext));
expr = (SpelExpression)parser.parseExpression("'abc'-true"); expr = (SpelExpression)parser.parseExpression("'abc'-true");
assertEquals("abc",expr.getValue(eContext)); Assert.assertEquals("abc",expr.getValue(eContext));
} }
} }

View File

@ -16,6 +16,9 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.spel.ast.Operator; import org.springframework.expression.spel.ast.Operator;
/** /**
@ -25,14 +28,17 @@ import org.springframework.expression.spel.ast.Operator;
*/ */
public class OperatorTests extends ExpressionTestCase { public class OperatorTests extends ExpressionTestCase {
@Test
public void testIntegerLiteral() { public void testIntegerLiteral() {
evaluate("3", 3, Integer.class); evaluate("3", 3, Integer.class);
} }
@Test
public void testRealLiteral() { public void testRealLiteral() {
evaluate("3.5", 3.5d, Double.class); evaluate("3.5", 3.5d, Double.class);
} }
@Test
public void testLessThan() { public void testLessThan() {
evaluate("3 < 5", true, Boolean.class); evaluate("3 < 5", true, Boolean.class);
evaluate("5 < 3", false, Boolean.class); evaluate("5 < 3", false, Boolean.class);
@ -44,6 +50,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("'def' < 'abc'",false,Boolean.class); evaluate("'def' < 'abc'",false,Boolean.class);
} }
@Test
public void testLessThanOrEqual() { public void testLessThanOrEqual() {
evaluate("3 <= 5", true, Boolean.class); evaluate("3 <= 5", true, Boolean.class);
evaluate("5 <= 3", false, Boolean.class); evaluate("5 <= 3", false, Boolean.class);
@ -59,6 +66,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("'abc' <= 'abc'",true,Boolean.class); evaluate("'abc' <= 'abc'",true,Boolean.class);
} }
@Test
public void testEqual() { public void testEqual() {
evaluate("3 == 5", false, Boolean.class); evaluate("3 == 5", false, Boolean.class);
evaluate("5 == 3", false, Boolean.class); evaluate("5 == 3", false, Boolean.class);
@ -68,6 +76,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("'abc' == null", false, Boolean.class); evaluate("'abc' == null", false, Boolean.class);
} }
@Test
public void testNotEqual() { public void testNotEqual() {
evaluate("3 != 5", true, Boolean.class); evaluate("3 != 5", true, Boolean.class);
evaluate("5 != 3", true, Boolean.class); evaluate("5 != 3", true, Boolean.class);
@ -76,6 +85,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("3.0f != 3.0f", false, Boolean.class); evaluate("3.0f != 3.0f", false, Boolean.class);
} }
@Test
public void testGreaterThanOrEqual() { public void testGreaterThanOrEqual() {
evaluate("3 >= 5", false, Boolean.class); evaluate("3 >= 5", false, Boolean.class);
evaluate("5 >= 3", true, Boolean.class); evaluate("5 >= 3", true, Boolean.class);
@ -92,6 +102,7 @@ public class OperatorTests extends ExpressionTestCase {
} }
@Test
public void testGreaterThan() { public void testGreaterThan() {
evaluate("3 > 5", false, Boolean.class); evaluate("3 > 5", false, Boolean.class);
evaluate("5 > 3", true, Boolean.class); evaluate("5 > 3", true, Boolean.class);
@ -103,18 +114,29 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("'def' > 'abc'",true,Boolean.class); evaluate("'def' > 'abc'",true,Boolean.class);
} }
@Test
public void testMultiplyStringInt() { public void testMultiplyStringInt() {
evaluate("'a' * 5", "aaaaa", String.class); evaluate("'a' * 5", "aaaaa", String.class);
} }
@Test
public void testMultiplyDoubleDoubleGivesDouble() { public void testMultiplyDoubleDoubleGivesDouble() {
evaluate("3.0d * 5.0d", 15.0d, Double.class); evaluate("3.0d * 5.0d", 15.0d, Double.class);
} }
@Test
public void testMathOperatorAdd02() { public void testMathOperatorAdd02() {
evaluate("'hello' + ' ' + 'world'", "hello world", String.class); evaluate("'hello' + ' ' + 'world'", "hello world", String.class);
} }
@Test
public void testMathOperatorsInChains() {
evaluate("1+2+3",6,Integer.class);
evaluate("2*3*4",24,Integer.class);
evaluate("12-1-2",9,Integer.class);
}
@Test
public void testIntegerArithmetic() { public void testIntegerArithmetic() {
evaluate("2 + 4", "6", Integer.class); evaluate("2 + 4", "6", Integer.class);
evaluate("5 - 4", "1", Integer.class); evaluate("5 - 4", "1", Integer.class);
@ -125,6 +147,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("3 % 2", 1, Integer.class); evaluate("3 % 2", 1, Integer.class);
} }
@Test
public void testPlus() throws Exception { public void testPlus() throws Exception {
evaluate("7 + 2", "9", Integer.class); evaluate("7 + 2", "9", Integer.class);
evaluate("3.0f + 5.0f", 8.0d, Double.class); evaluate("3.0f + 5.0f", 8.0d, Double.class);
@ -136,9 +159,9 @@ public class OperatorTests extends ExpressionTestCase {
// AST: // AST:
SpelExpression expr = (SpelExpression)parser.parseExpression("+3"); SpelExpression expr = (SpelExpression)parser.parseExpression("+3");
assertEquals("+3",expr.toStringAST()); Assert.assertEquals("+3",expr.toStringAST());
expr = (SpelExpression)parser.parseExpression("2+3"); expr = (SpelExpression)parser.parseExpression("2+3");
assertEquals("(2 + 3)",expr.toStringAST()); Assert.assertEquals("(2 + 3)",expr.toStringAST());
// use as a unary operator // use as a unary operator
evaluate("+5d",5d,Double.class); evaluate("+5d",5d,Double.class);
@ -153,15 +176,16 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("5 + new Integer('37')",42,Integer.class); evaluate("5 + new Integer('37')",42,Integer.class);
} }
@Test
public void testMinus() throws Exception { public void testMinus() throws Exception {
evaluate("'c' - 2", "a", String.class); evaluate("'c' - 2", "a", String.class);
evaluate("3.0f - 5.0f", -2.0d, Double.class); evaluate("3.0f - 5.0f", -2.0d, Double.class);
evaluateAndCheckError("'ab' - 2", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("'ab' - 2", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
evaluateAndCheckError("2-'ab'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("2-'ab'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
SpelExpression expr = (SpelExpression)parser.parseExpression("-3"); SpelExpression expr = (SpelExpression)parser.parseExpression("-3");
assertEquals("-3",expr.toStringAST()); Assert.assertEquals("-3",expr.toStringAST());
expr = (SpelExpression)parser.parseExpression("2-3"); expr = (SpelExpression)parser.parseExpression("2-3");
assertEquals("(2 - 3)",expr.toStringAST()); Assert.assertEquals("(2 - 3)",expr.toStringAST());
evaluate("-5d",-5d,Double.class); evaluate("-5d",-5d,Double.class);
evaluate("-5L",-5L,Long.class); evaluate("-5L",-5L,Long.class);
@ -169,28 +193,33 @@ public class OperatorTests extends ExpressionTestCase {
evaluateAndCheckError("-'abc'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("-'abc'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
} }
@Test
public void testModulus() { public void testModulus() {
evaluate("3%2",1,Integer.class); evaluate("3%2",1,Integer.class);
evaluate("3L%2L",1L,Long.class); evaluate("3L%2L",1L,Long.class);
evaluate("3.0d%2.0d",1d,Double.class); evaluate("3.0f%2.0f",1d,Double.class);
evaluate("5.0f % 3.1f", 1.9d, Double.class); evaluate("5.0d % 3.1d", 1.9d, Double.class);
evaluateAndCheckError("'abc'%'def'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("'abc'%'def'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
} }
@Test
public void testDivide() { public void testDivide() {
evaluate("3.0f / 5.0f", 0.6d, Double.class); evaluate("3.0f / 5.0f", 0.6d, Double.class);
evaluate("4L/2L",2L,Long.class); evaluate("4L/2L",2L,Long.class);
evaluateAndCheckError("'abc'/'def'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("'abc'/'def'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
} }
@Test
public void testMathOperatorDivide_ConvertToDouble() { public void testMathOperatorDivide_ConvertToDouble() {
evaluateAndAskForReturnType("8/4", new Double(2.0), Double.class); evaluateAndAskForReturnType("8/4", new Double(2.0), Double.class);
} }
@Test
public void testMathOperatorDivide04_ConvertToFloat() { public void testMathOperatorDivide04_ConvertToFloat() {
evaluateAndAskForReturnType("8/4", new Float(2.0), Float.class); evaluateAndAskForReturnType("8/4", new Float(2.0), Float.class);
} }
@Test
public void testDoubles() { public void testDoubles() {
evaluate("3.0d == 5.0d", false, Boolean.class); evaluate("3.0d == 5.0d", false, Boolean.class);
evaluate("3.0d == 3.0d", true, Boolean.class); evaluate("3.0d == 3.0d", true, Boolean.class);
@ -203,49 +232,52 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("6.0d % 3.5d", 2.5d, Double.class); evaluate("6.0d % 3.5d", 2.5d, Double.class);
} }
@Test
public void testOperatorNames() throws Exception { public void testOperatorNames() throws Exception {
Operator node = getOperatorNode((SpelExpression)parser.parseExpression("1==3")); Operator node = getOperatorNode((SpelExpression)parser.parseExpression("1==3"));
assertEquals("==",node.getOperatorName()); Assert.assertEquals("==",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("1!=3")); node = getOperatorNode((SpelExpression)parser.parseExpression("1!=3"));
assertEquals("!=",node.getOperatorName()); Assert.assertEquals("!=",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3/3")); node = getOperatorNode((SpelExpression)parser.parseExpression("3/3"));
assertEquals("/",node.getOperatorName()); Assert.assertEquals("/",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3+3")); node = getOperatorNode((SpelExpression)parser.parseExpression("3+3"));
assertEquals("+",node.getOperatorName()); Assert.assertEquals("+",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3-3")); node = getOperatorNode((SpelExpression)parser.parseExpression("3-3"));
assertEquals("-",node.getOperatorName()); Assert.assertEquals("-",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3<4")); node = getOperatorNode((SpelExpression)parser.parseExpression("3<4"));
assertEquals("<",node.getOperatorName()); Assert.assertEquals("<",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3<=4")); node = getOperatorNode((SpelExpression)parser.parseExpression("3<=4"));
assertEquals("<=",node.getOperatorName()); Assert.assertEquals("<=",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3*4")); node = getOperatorNode((SpelExpression)parser.parseExpression("3*4"));
assertEquals("*",node.getOperatorName()); Assert.assertEquals("*",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3%4")); node = getOperatorNode((SpelExpression)parser.parseExpression("3%4"));
assertEquals("%",node.getOperatorName()); Assert.assertEquals("%",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3>=4")); node = getOperatorNode((SpelExpression)parser.parseExpression("3>=4"));
assertEquals(">=",node.getOperatorName()); Assert.assertEquals(">=",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3 between 4")); node = getOperatorNode((SpelExpression)parser.parseExpression("3 between 4"));
assertEquals("between",node.getOperatorName()); Assert.assertEquals("between",node.getOperatorName());
node = getOperatorNode((SpelExpression)parser.parseExpression("3 ^ 4")); node = getOperatorNode((SpelExpression)parser.parseExpression("3 ^ 4"));
assertEquals("^",node.getOperatorName()); Assert.assertEquals("^",node.getOperatorName());
} }
@Test
public void testOperatorOverloading() { public void testOperatorOverloading() {
evaluateAndCheckError("'a' * '2'", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("'a' * '2'", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
evaluateAndCheckError("'a' ^ '2'", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("'a' ^ '2'", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
} }
@Test
public void testPower() { public void testPower() {
evaluate("3^2",9,Integer.class); evaluate("3^2",9,Integer.class);
evaluate("3.0d^2.0d",9.0d,Double.class); evaluate("3.0d^2.0d",9.0d,Double.class);
@ -253,14 +285,16 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("(2^32)^2",9223372036854775807L,Long.class); evaluate("(2^32)^2",9223372036854775807L,Long.class);
} }
@Test
public void testMixedOperands_FloatsAndDoubles() { public void testMixedOperands_FloatsAndDoubles() {
evaluate("3.0d + 5.0f", 8.0d, Double.class); evaluate("3.0d + 5.0f", 8.0d, Double.class);
evaluate("3.0D - 5.0f", -2.0d, Double.class); evaluate("3.0D - 5.0f", -2.0d, Double.class);
evaluate("3.0f * 5.0d", 15.0d, Double.class); evaluate("3.0f * 5.0d", 15.0d, Double.class);
evaluate("3.0f / 5.0D", 0.6d, Double.class); evaluate("3.0f / 5.0D", 0.6d, Double.class);
evaluate("5.0D % 3.1f", 1.9d, Double.class); evaluate("5.0D % 3f", 2.0d, Double.class);
} }
@Test
public void testMixedOperands_DoublesAndInts() { public void testMixedOperands_DoublesAndInts() {
evaluate("3.0d + 5", 8.0d, Double.class); evaluate("3.0d + 5", 8.0d, Double.class);
evaluate("3.0D - 5", -2.0d, Double.class); evaluate("3.0D - 5", -2.0d, Double.class);
@ -271,6 +305,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("5.5D % 3", 2.5, Double.class); evaluate("5.5D % 3", 2.5, Double.class);
} }
@Test
public void testStrings() { public void testStrings() {
evaluate("'abc' == 'abc'",true,Boolean.class); evaluate("'abc' == 'abc'",true,Boolean.class);
evaluate("'abc' == 'def'",false,Boolean.class); evaluate("'abc' == 'def'",false,Boolean.class);
@ -278,6 +313,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("'abc' != 'def'",true,Boolean.class); evaluate("'abc' != 'def'",true,Boolean.class);
} }
@Test
public void testLongs() { public void testLongs() {
evaluate("3L == 4L", false, Boolean.class); evaluate("3L == 4L", false, Boolean.class);
evaluate("3L == 3L", true, Boolean.class); evaluate("3L == 3L", true, Boolean.class);

View File

@ -16,15 +16,16 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import org.junit.Test;
/** /**
* Tests the messages and exceptions that come out for badly formed expressions * Tests the messages and exceptions that come out for badly formed expressions
* *
* @author Andy Clement * @author Andy Clement
*/ */
public class ParserErrorMessagesTests extends ExpressionTestCase { public class ParserErrorMessagesTests extends ExpressionTestCase {
// TODO extract expected insert messages into constants (just in case of changes)?
// TODO review poor messages, marked // POOR below
@Test
public void testBrokenExpression01() { public void testBrokenExpression01() {
// will not fit into an int, needs L suffix // will not fit into an int, needs L suffix
parseAndCheckError("0xCAFEBABE", SpelMessages.NOT_AN_INTEGER); parseAndCheckError("0xCAFEBABE", SpelMessages.NOT_AN_INTEGER);
@ -32,26 +33,30 @@ public class ParserErrorMessagesTests extends ExpressionTestCase {
parseAndCheckError("0xCAFEBABECAFEBABEL", SpelMessages.NOT_A_LONG); parseAndCheckError("0xCAFEBABECAFEBABEL", SpelMessages.NOT_A_LONG);
} }
@Test
public void testBrokenExpression02() { public void testBrokenExpression02() {
// rogue 'G' on the end // rogue 'G' on the end
parseAndCheckError("0xB0BG", SpelMessages.PARSE_PROBLEM, 5, "mismatched input 'G' expecting EOF"); parseAndCheckError("0xB0BG", SpelMessages.MORE_INPUT, 5, "G");
} }
@Test
public void testBrokenExpression04() { public void testBrokenExpression04() {
// missing right operand // missing right operand
parseAndCheckError("true or ", SpelMessages.PARSE_PROBLEM, -1, "no viable alternative at input '<EOF>'"); // POOR parseAndCheckError("true or ", SpelMessages.RIGHT_OPERAND_PROBLEM, 5);
} }
@Test
public void testBrokenExpression05() { public void testBrokenExpression05() {
// missing right operand // missing right operand
parseAndCheckError("1 + ", SpelMessages.PARSE_PROBLEM, -1, "no viable alternative at input '<EOF>'"); // POOR parseAndCheckError("1 + ", SpelMessages.RIGHT_OPERAND_PROBLEM, 2);
} }
@Test
public void testBrokenExpression07() { public void testBrokenExpression07() {
// T() can only take an identifier (possibly qualified), not a literal // T() can only take an identifier (possibly qualified), not a literal
// message ought to say identifier rather than ID // message ought to say identifier rather than ID
parseAndCheckError("null instanceof T('a')", SpelMessages.PARSE_PROBLEM, 18, parseAndCheckError("null instanceof T('a')", SpelMessages.NOT_EXPECTED_TOKEN, 18,
"mismatched input ''a'' expecting ID"); // POOR "identifier","literal_string");
} }
} }

View File

@ -16,10 +16,11 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.TestCase; import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.ParseException; import org.springframework.expression.ParseException;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
/** /**
* Parse some expressions and check we get the AST we expect. Rather than inspecting each node in the AST, we ask it to * Parse some expressions and check we get the AST we expect. Rather than inspecting each node in the AST, we ask it to
@ -27,105 +28,129 @@ import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
* *
* @author Andy Clement * @author Andy Clement
*/ */
public class ParsingTests extends TestCase { public class ParsingTests {
private SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); private SpelExpressionParser parser = new SpelExpressionParser();
// literals // literals
@Test
public void testLiteralBoolean01() { public void testLiteralBoolean01() {
parseCheck("false"); parseCheck("false");
} }
@Test
public void testLiteralLong01() { public void testLiteralLong01() {
parseCheck("37L", "37"); parseCheck("37L", "37");
} }
@Test
public void testLiteralBoolean02() { public void testLiteralBoolean02() {
parseCheck("true"); parseCheck("true");
} }
@Test
public void testLiteralBoolean03() { public void testLiteralBoolean03() {
parseCheck("!true"); parseCheck("!true");
} }
@Test
public void testLiteralInteger01() { public void testLiteralInteger01() {
parseCheck("1"); parseCheck("1");
} }
@Test
public void testLiteralInteger02() { public void testLiteralInteger02() {
parseCheck("1415"); parseCheck("1415");
} }
@Test
public void testLiteralString01() { public void testLiteralString01() {
parseCheck("'hello'"); parseCheck("'hello'");
} }
@Test
public void testLiteralString02() { public void testLiteralString02() {
parseCheck("'joe bloggs'"); parseCheck("'joe bloggs'");
} }
@Test
public void testLiteralString03() { public void testLiteralString03() {
parseCheck("'Tony''s Pizza'", "'Tony's Pizza'"); parseCheck("'Tony''s Pizza'", "'Tony's Pizza'");
} }
@Test
public void testLiteralReal01() { public void testLiteralReal01() {
parseCheck("6.0221415E+23", "6.0221415E23"); parseCheck("6.0221415E+23", "6.0221415E23");
} }
@Test
public void testLiteralHex01() { public void testLiteralHex01() {
parseCheck("0x7FFFFFFF", "2147483647"); parseCheck("0x7FFFFFFF", "2147483647");
} }
@Test
public void testLiteralDate01() { public void testLiteralDate01() {
parseCheck("date('1974/08/24')"); parseCheck("date('1974/08/24')");
} }
@Test
public void testLiteralDate02() { public void testLiteralDate02() {
parseCheck("date('19740824T131030','yyyyMMddTHHmmss')"); parseCheck("date('19740824T131030','yyyyMMddTHHmmss')");
} }
@Test
public void testLiteralNull01() { public void testLiteralNull01() {
parseCheck("null"); parseCheck("null");
} }
// boolean operators // boolean operators
@Test
public void testBooleanOperatorsOr01() { public void testBooleanOperatorsOr01() {
parseCheck("false or false", "(false or false)"); parseCheck("false or false", "(false or false)");
} }
@Test
public void testBooleanOperatorsOr02() { public void testBooleanOperatorsOr02() {
parseCheck("false or true", "(false or true)"); parseCheck("false or true", "(false or true)");
} }
@Test
public void testBooleanOperatorsOr03() { public void testBooleanOperatorsOr03() {
parseCheck("true or false", "(true or false)"); parseCheck("true or false", "(true or false)");
} }
@Test
public void testBooleanOperatorsOr04() { public void testBooleanOperatorsOr04() {
parseCheck("true or false", "(true or false)"); parseCheck("true or false", "(true or false)");
} }
@Test
public void testBooleanOperatorsMix01() { public void testBooleanOperatorsMix01() {
parseCheck("false or true and false", "(false or (true and false))"); parseCheck("false or true and false", "(false or (true and false))");
} }
// relational operators // relational operators
@Test
public void testRelOperatorsGT01() { public void testRelOperatorsGT01() {
parseCheck("3>6", "(3 > 6)"); parseCheck("3>6", "(3 > 6)");
} }
@Test
public void testRelOperatorsLT01() { public void testRelOperatorsLT01() {
parseCheck("3<6", "(3 < 6)"); parseCheck("3<6", "(3 < 6)");
} }
@Test
public void testRelOperatorsLE01() { public void testRelOperatorsLE01() {
parseCheck("3<=6", "(3 <= 6)"); parseCheck("3<=6", "(3 <= 6)");
} }
@Test
public void testRelOperatorsGE01() { public void testRelOperatorsGE01() {
parseCheck("3>=6", "(3 >= 6)"); parseCheck("3>=6", "(3 >= 6)");
} }
@Test
public void testRelOperatorsGE02() { public void testRelOperatorsGE02() {
parseCheck("3>=3", "(3 >= 3)"); parseCheck("3>=3", "(3 >= 3)");
} }
@ -142,6 +167,7 @@ public class ParsingTests extends TestCase {
// parseCheck("'efg' between {'abc', 'xyz'}", "('efg' between {'abc','xyz'})"); // parseCheck("'efg' between {'abc', 'xyz'}", "('efg' between {'abc','xyz'})");
// }// true // }// true
@Test
public void testRelOperatorsIs01() { public void testRelOperatorsIs01() {
parseCheck("'xyz' instanceof int", "('xyz' instanceof int)"); parseCheck("'xyz' instanceof int", "('xyz' instanceof int)");
}// false }// false
@ -150,44 +176,54 @@ public class ParsingTests extends TestCase {
// parseCheck("{1, 2, 3, 4, 5} instanceof List", "({1,2,3,4,5} instanceof List)"); // parseCheck("{1, 2, 3, 4, 5} instanceof List", "({1,2,3,4,5} instanceof List)");
// }// true // }// true
@Test
public void testRelOperatorsMatches01() { public void testRelOperatorsMatches01() {
parseCheck("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "('5.0067' matches '^-?\\d+(\\.\\d{2})?$')"); parseCheck("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "('5.0067' matches '^-?\\d+(\\.\\d{2})?$')");
}// false }// false
@Test
public void testRelOperatorsMatches02() { public void testRelOperatorsMatches02() {
parseCheck("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "('5.00' matches '^-?\\d+(\\.\\d{2})?$')"); parseCheck("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "('5.00' matches '^-?\\d+(\\.\\d{2})?$')");
}// true }// true
// mathematical operators // mathematical operators
@Test
public void testMathOperatorsAdd01() { public void testMathOperatorsAdd01() {
parseCheck("2+4", "(2 + 4)"); parseCheck("2+4", "(2 + 4)");
} }
@Test
public void testMathOperatorsAdd02() { public void testMathOperatorsAdd02() {
parseCheck("'a'+'b'", "('a' + 'b')"); parseCheck("'a'+'b'", "('a' + 'b')");
} }
@Test
public void testMathOperatorsAdd03() { public void testMathOperatorsAdd03() {
parseCheck("'hello'+' '+'world'", "(('hello' + ' ') + 'world')"); parseCheck("'hello'+' '+'world'", "(('hello' + ' ') + 'world')");
} }
@Test
public void testMathOperatorsSubtract01() { public void testMathOperatorsSubtract01() {
parseCheck("5-4", "(5 - 4)"); parseCheck("5-4", "(5 - 4)");
} }
@Test
public void testMathOperatorsMultiply01() { public void testMathOperatorsMultiply01() {
parseCheck("7*4", "(7 * 4)"); parseCheck("7*4", "(7 * 4)");
} }
@Test
public void testMathOperatorsDivide01() { public void testMathOperatorsDivide01() {
parseCheck("8/4", "(8 / 4)"); parseCheck("8/4", "(8 / 4)");
} }
@Test
public void testMathOperatorModulus01() { public void testMathOperatorModulus01() {
parseCheck("7 % 4", "(7 % 4)"); parseCheck("7 % 4", "(7 % 4)");
} }
// mixed operators // mixed operators
@Test
public void testMixedOperators01() { public void testMixedOperators01() {
parseCheck("true and 5>3", "(true and (5 > 3))"); parseCheck("true and 5>3", "(true and (5 > 3))");
} }
@ -239,14 +275,17 @@ public class ParsingTests extends TestCase {
// }// normalized to '.' for separator in QualifiedIdentifier // }// normalized to '.' for separator in QualifiedIdentifier
// properties // properties
@Test
public void testProperties01() { public void testProperties01() {
parseCheck("name"); parseCheck("name");
} }
@Test
public void testProperties02() { public void testProperties02() {
parseCheck("placeofbirth.CitY"); parseCheck("placeofbirth.CitY");
} }
@Test
public void testProperties03() { public void testProperties03() {
parseCheck("a.b.c.d.e"); parseCheck("a.b.c.d.e");
} }
@ -278,19 +317,23 @@ public class ParsingTests extends TestCase {
// } // }
// methods // methods
@Test
public void testMethods01() { public void testMethods01() {
parseCheck("echo(12)"); parseCheck("echo(12)");
} }
@Test
public void testMethods02() { public void testMethods02() {
parseCheck("echo(name)"); parseCheck("echo(name)");
} }
@Test
public void testMethods03() { public void testMethods03() {
parseCheck("age.doubleItAndAdd(12)"); parseCheck("age.doubleItAndAdd(12)");
} }
// constructors // constructors
@Test
public void testConstructors01() { public void testConstructors01() {
parseCheck("new String('hello')"); parseCheck("new String('hello')");
} }
@ -309,14 +352,17 @@ public class ParsingTests extends TestCase {
// } // }
// variables and functions // variables and functions
@Test
public void testVariables01() { public void testVariables01() {
parseCheck("#foo"); parseCheck("#foo");
} }
@Test
public void testFunctions01() { public void testFunctions01() {
parseCheck("#fn(1,2,3)"); parseCheck("#fn(1,2,3)");
} }
@Test
public void testFunctions02() { public void testFunctions02() {
parseCheck("#fn('hello')"); parseCheck("#fn('hello')");
} }
@ -342,6 +388,7 @@ public class ParsingTests extends TestCase {
// } // }
// assignment // assignment
@Test
public void testAssignmentToVariables01() { public void testAssignmentToVariables01() {
parseCheck("#var1='value1'"); parseCheck("#var1='value1'");
} }
@ -349,6 +396,7 @@ public class ParsingTests extends TestCase {
// ternary operator // ternary operator
@Test
public void testTernaryOperator01() { public void testTernaryOperator01() {
parseCheck("1>2?3:4","(1 > 2) ? 3 : 4"); parseCheck("1>2?3:4","(1 > 2) ? 3 : 4");
} }
@ -369,10 +417,12 @@ public class ParsingTests extends TestCase {
// } // 120 // } // 120
// Type references // Type references
@Test
public void testTypeReferences01() { public void testTypeReferences01() {
parseCheck("T(java.lang.String)"); parseCheck("T(java.lang.String)");
} }
@Test
public void testTypeReferences02() { public void testTypeReferences02() {
parseCheck("T(String)"); parseCheck("T(String)");
} }
@ -401,12 +451,12 @@ public class ParsingTests extends TestCase {
SpelUtilities.printAbstractSyntaxTree(System.err, e); SpelUtilities.printAbstractSyntaxTree(System.err, e);
} }
if (e == null) { if (e == null) {
fail("Parsed exception was null"); Assert.fail("Parsed exception was null");
} }
assertEquals("String form of AST does not match expected output", expectedStringFormOfAST, e.toStringAST()); Assert.assertEquals("String form of AST does not match expected output", expectedStringFormOfAST, e.toStringAST());
} catch (ParseException ee) { } catch (ParseException ee) {
ee.printStackTrace(); ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage()); Assert.fail("Unexpected Exception: " + ee.getMessage());
} }
} }

View File

@ -16,27 +16,31 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.TestCase; import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser; import org.springframework.expression.ExpressionParser;
///CLOVER:OFF
/** /**
* Tests the evaluation of real expressions in a real context. * Tests the evaluation of real expressions in a real context.
* *
* @author Andy Clement * @author Andy Clement
*/ */
public class PerformanceTests extends TestCase { public class PerformanceTests {
public static final int ITERATIONS = 10000; public static final int ITERATIONS = 10000;
public static final boolean report = true; public static final boolean report = true;
private static SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); private static ExpressionParser parser = SpelExpressionParserFactory.getParser();
private static EvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext(); private static EvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
@Test
public void testPerformanceOfPropertyAccess() throws Exception { public void testPerformanceOfPropertyAccess() throws Exception {
long starttime = 0; long starttime = 0;
long endtime = 0; long endtime = 0;
@ -45,18 +49,18 @@ public class PerformanceTests extends TestCase {
for (int i = 0; i < ITERATIONS; i++) { for (int i = 0; i < ITERATIONS; i++) {
Expression expr = parser.parseExpression("placeOfBirth.city"); Expression expr = parser.parseExpression("placeOfBirth.city");
if (expr == null) { if (expr == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
Object value = expr.getValue(eContext); expr.getValue(eContext);
} }
starttime = System.currentTimeMillis(); starttime = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) { for (int i = 0; i < ITERATIONS; i++) {
Expression expr = parser.parseExpression("placeOfBirth.city"); Expression expr = parser.parseExpression("placeOfBirth.city");
if (expr == null) { if (expr == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
Object value = expr.getValue(eContext); expr.getValue(eContext);
} }
endtime = System.currentTimeMillis(); endtime = System.currentTimeMillis();
long freshParseTime = endtime - starttime; long freshParseTime = endtime - starttime;
@ -66,11 +70,11 @@ public class PerformanceTests extends TestCase {
Expression expr = parser.parseExpression("placeOfBirth.city"); Expression expr = parser.parseExpression("placeOfBirth.city");
if (expr == null) { if (expr == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
starttime = System.currentTimeMillis(); starttime = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) { for (int i = 0; i < ITERATIONS; i++) {
Object value = expr.getValue(eContext); expr.getValue(eContext);
} }
endtime = System.currentTimeMillis(); endtime = System.currentTimeMillis();
long reuseTime = endtime - starttime; long reuseTime = endtime - starttime;
@ -80,7 +84,7 @@ public class PerformanceTests extends TestCase {
if (reuseTime > freshParseTime) { if (reuseTime > freshParseTime) {
System.out.println("Fresh parse every time, ITERATIONS iterations = " + freshParseTime + "ms"); System.out.println("Fresh parse every time, ITERATIONS iterations = " + freshParseTime + "ms");
System.out.println("Reuse SpelExpression, ITERATIONS iterations = " + reuseTime + "ms"); System.out.println("Reuse SpelExpression, ITERATIONS iterations = " + reuseTime + "ms");
fail("Should have been quicker to reuse!"); Assert.fail("Should have been quicker to reuse!");
} }
} }
@ -92,18 +96,18 @@ public class PerformanceTests extends TestCase {
for (int i = 0; i < ITERATIONS; i++) { for (int i = 0; i < ITERATIONS; i++) {
Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()"); Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()");
if (expr == null) { if (expr == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
Object value = expr.getValue(eContext); expr.getValue(eContext);
} }
starttime = System.currentTimeMillis(); starttime = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) { for (int i = 0; i < ITERATIONS; i++) {
Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()"); Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()");
if (expr == null) { if (expr == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
Object value = expr.getValue(eContext); expr.getValue(eContext);
} }
endtime = System.currentTimeMillis(); endtime = System.currentTimeMillis();
long freshParseTime = endtime - starttime; long freshParseTime = endtime - starttime;
@ -113,11 +117,11 @@ public class PerformanceTests extends TestCase {
Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()"); Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()");
if (expr == null) { if (expr == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
starttime = System.currentTimeMillis(); starttime = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) { for (int i = 0; i < ITERATIONS; i++) {
Object value = expr.getValue(eContext); expr.getValue(eContext);
} }
endtime = System.currentTimeMillis(); endtime = System.currentTimeMillis();
long reuseTime = endtime - starttime; long reuseTime = endtime - starttime;
@ -128,7 +132,7 @@ public class PerformanceTests extends TestCase {
if (reuseTime > freshParseTime) { if (reuseTime > freshParseTime) {
System.out.println("Fresh parse every time, ITERATIONS iterations = " + freshParseTime + "ms"); System.out.println("Fresh parse every time, ITERATIONS iterations = " + freshParseTime + "ms");
System.out.println("Reuse SpelExpression, ITERATIONS iterations = " + reuseTime + "ms"); System.out.println("Reuse SpelExpression, ITERATIONS iterations = " + reuseTime + "ms");
fail("Should have been quicker to reuse!"); Assert.fail("Should have been quicker to reuse!");
} }
} }

View File

@ -16,16 +16,21 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.PropertyAccessor; import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
import org.springframework.expression.spel.ast.CommonTypeDescriptors; import org.springframework.expression.spel.ast.CommonTypeDescriptors;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
///CLOVER:OFF
/** /**
* Tests accessing of properties. * Tests accessing of properties.
* *
@ -33,18 +38,22 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
*/ */
public class PropertyAccessTests extends ExpressionTestCase { public class PropertyAccessTests extends ExpressionTestCase {
@Test
public void testSimpleAccess01() { public void testSimpleAccess01() {
evaluate("name", "Nikola Tesla", String.class); evaluate("name", "Nikola Tesla", String.class);
} }
@Test
public void testSimpleAccess02() { public void testSimpleAccess02() {
evaluate("placeOfBirth.city", "SmilJan", String.class); evaluate("placeOfBirth.city", "SmilJan", String.class);
} }
@Test
public void testSimpleAccess03() { public void testSimpleAccess03() {
evaluate("stringArrayOfThreeItems.length", "3", Integer.class); evaluate("stringArrayOfThreeItems.length", "3", Integer.class);
} }
@Test
public void testNonExistentPropertiesAndMethods() { public void testNonExistentPropertiesAndMethods() {
// madeup does not exist as a property // madeup does not exist as a property
evaluateAndCheckError("madeup", SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE, 0); evaluateAndCheckError("madeup", SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE, 0);
@ -57,36 +66,38 @@ public class PropertyAccessTests extends ExpressionTestCase {
* The standard reflection resolver cannot find properties on null objects but some * The standard reflection resolver cannot find properties on null objects but some
* supplied resolver might be able to - so null shouldn't crash the reflection resolver. * supplied resolver might be able to - so null shouldn't crash the reflection resolver.
*/ */
@Test
public void testAccessingOnNullObject() throws Exception { public void testAccessingOnNullObject() throws Exception {
SpelExpression expr = (SpelExpression)parser.parseExpression("madeup"); SpelExpression expr = (SpelExpression)parser.parseExpression("madeup");
EvaluationContext context = new StandardEvaluationContext(null); EvaluationContext context = new StandardEvaluationContext(null);
try { try {
expr.getValue(context); expr.getValue(context);
fail("Should have failed - default property resolver cannot resolve on null"); Assert.fail("Should have failed - default property resolver cannot resolve on null");
} catch (Exception e) { } catch (Exception e) {
checkException(e,SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL); checkException(e,SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL);
} }
assertFalse(expr.isWritable(context)); Assert.assertFalse(expr.isWritable(context));
try { try {
expr.setValue(context,"abc"); expr.setValue(context,"abc");
fail("Should have failed - default property resolver cannot resolve on null"); Assert.fail("Should have failed - default property resolver cannot resolve on null");
} catch (Exception e) { } catch (Exception e) {
checkException(e,SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL); checkException(e,SpelMessages.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL);
} }
} }
private void checkException(Exception e, SpelMessages expectedMessage) { private void checkException(Exception e, SpelMessages expectedMessage) {
if (e instanceof SpelException) { if (e instanceof SpelEvaluationException) {
SpelMessages sm = ((SpelException)e).getMessageUnformatted(); SpelMessages sm = ((SpelEvaluationException)e).getMessageUnformatted();
assertEquals("Expected exception type did not occur",expectedMessage,sm); Assert.assertEquals("Expected exception type did not occur",expectedMessage,sm);
} else { } else {
fail("Should be a SpelException "+e); Assert.fail("Should be a SpelException "+e);
} }
} }
@Test
// Adding a new property accessor just for a particular type // Adding a new property accessor just for a particular type
public void testAddingSpecificPropertyAccessor() throws Exception { public void testAddingSpecificPropertyAccessor() throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
// Even though this property accessor is added after the reflection one, it specifically // Even though this property accessor is added after the reflection one, it specifically
@ -95,22 +106,22 @@ public class PropertyAccessTests extends ExpressionTestCase {
ctx.addPropertyAccessor(new StringyPropertyAccessor()); ctx.addPropertyAccessor(new StringyPropertyAccessor());
Expression expr = parser.parseExpression("new String('hello').flibbles"); Expression expr = parser.parseExpression("new String('hello').flibbles");
Integer i = expr.getValue(ctx, Integer.class); Integer i = expr.getValue(ctx, Integer.class);
assertEquals((int) i, 7); Assert.assertEquals((int) i, 7);
// The reflection one will be used for other properties... // The reflection one will be used for other properties...
expr = parser.parseExpression("new String('hello').CASE_INSENSITIVE_ORDER"); expr = parser.parseExpression("new String('hello').CASE_INSENSITIVE_ORDER");
Object o = expr.getValue(ctx); Object o = expr.getValue(ctx);
assertNotNull(o); Assert.assertNotNull(o);
expr = parser.parseExpression("new String('hello').flibbles"); expr = parser.parseExpression("new String('hello').flibbles");
expr.setValue(ctx, 99); expr.setValue(ctx, 99);
i = expr.getValue(ctx, Integer.class); i = expr.getValue(ctx, Integer.class);
assertEquals((int) i, 99); Assert.assertEquals((int) i, 99);
// Cannot set it to a string value // Cannot set it to a string value
try { try {
expr.setValue(ctx, "not allowed"); expr.setValue(ctx, "not allowed");
fail("Should not have been allowed"); Assert.fail("Should not have been allowed");
} catch (EvaluationException e) { } catch (EvaluationException e) {
// success - message will be: EL1063E:(pos 20): A problem occurred whilst attempting to set the property // success - message will be: EL1063E:(pos 20): A problem occurred whilst attempting to set the property
// 'flibbles': 'Cannot set flibbles to an object of type 'class java.lang.String'' // 'flibbles': 'Cannot set flibbles to an object of type 'class java.lang.String''

View File

@ -18,6 +18,9 @@ package org.springframework.expression.spel;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
@ -29,7 +32,7 @@ import org.springframework.expression.MethodResolver;
import org.springframework.expression.PropertyAccessor; import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypeConverter; import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.ReflectionHelper; import org.springframework.expression.spel.support.ReflectionHelper;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
@ -41,28 +44,30 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
*/ */
public class ScenariosForSpringSecurity extends ExpressionTestCase { public class ScenariosForSpringSecurity extends ExpressionTestCase {
@Test
public void testScenario01_Roles() throws Exception { public void testScenario01_Roles() throws Exception {
try { try {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
Expression expr = parser.parseExpression("hasAnyRole('MANAGER','TELLER')"); Expression expr = parser.parseExpression("hasAnyRole('MANAGER','TELLER')");
ctx.setRootObject(new Person("Ben")); ctx.setRootObject(new Person("Ben"));
Boolean value = expr.getValue(ctx,Boolean.class); Boolean value = expr.getValue(ctx,Boolean.class);
assertFalse(value); Assert.assertFalse(value);
ctx.setRootObject(new Manager("Luke")); ctx.setRootObject(new Manager("Luke"));
value = expr.getValue(ctx,Boolean.class); value = expr.getValue(ctx,Boolean.class);
assertTrue(value); Assert.assertTrue(value);
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
ee.printStackTrace(); ee.printStackTrace();
fail("Unexpected SpelException: " + ee.getMessage()); Assert.fail("Unexpected SpelException: " + ee.getMessage());
} }
} }
@Test
public void testScenario02_ComparingNames() throws Exception { public void testScenario02_ComparingNames() throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
ctx.addPropertyAccessor(new SecurityPrincipalAccessor()); ctx.addPropertyAccessor(new SecurityPrincipalAccessor());
@ -73,11 +78,11 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
ctx.setRootObject(new Person("Andy")); ctx.setRootObject(new Person("Andy"));
Boolean value = expr.getValue(ctx,Boolean.class); Boolean value = expr.getValue(ctx,Boolean.class);
assertTrue(value); Assert.assertTrue(value);
ctx.setRootObject(new Person("Christian")); ctx.setRootObject(new Person("Christian"));
value = expr.getValue(ctx,Boolean.class); value = expr.getValue(ctx,Boolean.class);
assertFalse(value); Assert.assertFalse(value);
// (2) Or register an accessor that can understand 'p' and return the right person // (2) Or register an accessor that can understand 'p' and return the right person
expr = parser.parseExpression("p.name == principal.name"); expr = parser.parseExpression("p.name == principal.name");
@ -88,15 +93,16 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
pAccessor.setPerson(new Person("Andy")); pAccessor.setPerson(new Person("Andy"));
value = expr.getValue(ctx,Boolean.class); value = expr.getValue(ctx,Boolean.class);
assertTrue(value); Assert.assertTrue(value);
pAccessor.setPerson(new Person("Christian")); pAccessor.setPerson(new Person("Christian"));
value = expr.getValue(ctx,Boolean.class); value = expr.getValue(ctx,Boolean.class);
assertFalse(value); Assert.assertFalse(value);
} }
@Test
public void testScenario03_Arithmetic() throws Exception { public void testScenario03_Arithmetic() throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
// Might be better with a as a variable although it would work as a property too... // Might be better with a as a variable although it would work as a property too...
@ -108,17 +114,18 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
ctx.setVariable("a",1.0d); // referenced as #a in the expression ctx.setVariable("a",1.0d); // referenced as #a in the expression
ctx.setRootObject(new Supervisor("Ben")); // so non-qualified references 'hasRole()' 'hasIpAddress()' are invoked against it ctx.setRootObject(new Supervisor("Ben")); // so non-qualified references 'hasRole()' 'hasIpAddress()' are invoked against it
value = expr.getValue(ctx,Boolean.class); value = expr.getValue(ctx,Boolean.class);
assertTrue(value); Assert.assertTrue(value);
ctx.setRootObject(new Manager("Luke")); ctx.setRootObject(new Manager("Luke"));
ctx.setVariable("a",1.043d); ctx.setVariable("a",1.043d);
value = expr.getValue(ctx,Boolean.class); value = expr.getValue(ctx,Boolean.class);
assertFalse(value); Assert.assertFalse(value);
} }
// Here i'm going to change which hasRole() executes and make it one of my own Java methods // Here i'm going to change which hasRole() executes and make it one of my own Java methods
@Test
public void testScenario04_ControllingWhichMethodsRun() throws Exception { public void testScenario04_ControllingWhichMethodsRun() throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = new StandardEvaluationContext(); StandardEvaluationContext ctx = new StandardEvaluationContext();
ctx.setRootObject(new Supervisor("Ben")); // so non-qualified references 'hasRole()' 'hasIpAddress()' are invoked against it); ctx.setRootObject(new Supervisor("Ben")); // so non-qualified references 'hasRole()' 'hasIpAddress()' are invoked against it);
@ -133,7 +140,7 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
ctx.setVariable("a",1.0d); // referenced as #a in the expression ctx.setVariable("a",1.0d); // referenced as #a in the expression
value = expr.getValue(ctx,Boolean.class); value = expr.getValue(ctx,Boolean.class);
assertTrue(value); Assert.assertTrue(value);
// ctx.setRootObject(new Manager("Luke")); // ctx.setRootObject(new Manager("Luke"));
// ctx.setVariable("a",1.043d); // ctx.setVariable("a",1.043d);

View File

@ -20,6 +20,9 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Set;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ParseException; import org.springframework.expression.ParseException;
@ -37,22 +40,27 @@ public class SetValueTests extends ExpressionTestCase {
private final static boolean DEBUG = false; private final static boolean DEBUG = false;
@Test
public void testSetProperty() { public void testSetProperty() {
setValue("wonNobelPrize", true); setValue("wonNobelPrize", true);
} }
@Test
public void testSetNestedProperty() { public void testSetNestedProperty() {
setValue("placeOfBirth.city", "Wien"); setValue("placeOfBirth.city", "Wien");
} }
@Test
public void testSetArrayElementValue() { public void testSetArrayElementValue() {
setValue("inventions[0]", "Just the telephone"); setValue("inventions[0]", "Just the telephone");
} }
@Test
public void testSetElementOfNull() { public void testSetElementOfNull() {
setValueExpectError("new org.springframework.expression.spel.testresources.Inventor().inventions[1]",SpelMessages.CANNOT_INDEX_INTO_NULL_VALUE); setValueExpectError("new org.springframework.expression.spel.testresources.Inventor().inventions[1]",SpelMessages.CANNOT_INDEX_INTO_NULL_VALUE);
} }
@Test
public void testSetArrayElementValueAllPrimitiveTypes() { public void testSetArrayElementValueAllPrimitiveTypes() {
setValue("arrayContainer.ints[1]", 3); setValue("arrayContainer.ints[1]", 3);
setValue("arrayContainer.floats[1]", 3.0f); setValue("arrayContainer.floats[1]", 3.0f);
@ -64,6 +72,7 @@ public class SetValueTests extends ExpressionTestCase {
setValue("arrayContainer.chars[1]", (char) 3); setValue("arrayContainer.chars[1]", (char) 3);
} }
@Test
public void testSetArrayElementValueAllPrimitiveTypesErrors() { public void testSetArrayElementValueAllPrimitiveTypesErrors() {
// none of these sets are possible due to (expected) conversion problems // none of these sets are possible due to (expected) conversion problems
setValueExpectError("arrayContainer.ints[1]", "wibble"); setValueExpectError("arrayContainer.ints[1]", "wibble");
@ -76,62 +85,74 @@ public class SetValueTests extends ExpressionTestCase {
setValueExpectError("arrayContainer.chars[1]", "NaC"); setValueExpectError("arrayContainer.chars[1]", "NaC");
} }
@Test
public void testSetArrayElementNestedValue() { public void testSetArrayElementNestedValue() {
setValue("placesLived[0].city", "Wien"); setValue("placesLived[0].city", "Wien");
} }
@Test
public void testSetListElementValue() { public void testSetListElementValue() {
setValue("placesLivedList[0]", new PlaceOfBirth("Wien")); setValue("placesLivedList[0]", new PlaceOfBirth("Wien"));
} }
public void testSetGenericListElementValueTypeCoersionFail() { @Test
public void testSetGenericListElementValueTypeCoersionfail() {
// no type converter registered for String > PlaceOfBirth // no type converter registered for String > PlaceOfBirth
setValueExpectError("placesLivedList[0]", "Wien"); setValueExpectError("placesLivedList[0]", "Wien");
} }
@Test
public void testSetGenericListElementValueTypeCoersionOK() { public void testSetGenericListElementValueTypeCoersionOK() {
setValue("booleanList[0]", "true", Boolean.TRUE); setValue("booleanList[0]", "true", Boolean.TRUE);
} }
@Test
public void testSetListElementNestedValue() { public void testSetListElementNestedValue() {
setValue("placesLived[0].city", "Wien"); setValue("placesLived[0].city", "Wien");
} }
@Test
public void testSetArrayElementInvalidIndex() { public void testSetArrayElementInvalidIndex() {
setValueExpectError("placesLived[23]", "Wien"); setValueExpectError("placesLived[23]", "Wien");
setValueExpectError("placesLivedList[23]", "Wien"); setValueExpectError("placesLivedList[23]", "Wien");
} }
@Test
public void testSetMapElements() { public void testSetMapElements() {
setValue("testMap['montag']","lundi"); setValue("testMap['montag']","lundi");
} }
@Test
public void testIndexingIntoUnsupportedType() { public void testIndexingIntoUnsupportedType() {
setValueExpectError("'hello'[3]", 'p'); setValueExpectError("'hello'[3]", 'p');
} }
@Test
public void testSetPropertyTypeCoersion() { public void testSetPropertyTypeCoersion() {
setValue("publicBoolean", "true", Boolean.TRUE); setValue("publicBoolean", "true", Boolean.TRUE);
} }
@Test
public void testSetPropertyTypeCoersionThroughSetter() { public void testSetPropertyTypeCoersionThroughSetter() {
setValue("SomeProperty", "true", Boolean.TRUE); setValue("SomeProperty", "true", Boolean.TRUE);
} }
@Test
public void testAssign() throws Exception { public void testAssign() throws Exception {
StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
Expression e = parse("publicName='Andy'"); Expression e = parse("publicName='Andy'");
assertFalse(e.isWritable(eContext)); Assert.assertFalse(e.isWritable(eContext));
assertEquals("Andy",e.getValue(eContext)); Assert.assertEquals("Andy",e.getValue(eContext));
} }
/* /*
* Testing the coercion of both the keys and the values to the correct type * Testing the coercion of both the keys and the values to the correct type
*/ */
@Test
public void testSetGenericMapElementRequiresCoercion() throws Exception { public void testSetGenericMapElementRequiresCoercion() throws Exception {
StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
Expression e = parse("mapOfStringToBoolean[42]"); Expression e = parse("mapOfStringToBoolean[42]");
assertNull(e.getValue(eContext)); Assert.assertNull(e.getValue(eContext));
// Key should be coerced to string representation of 42 // Key should be coerced to string representation of 42
e.setValue(eContext, "true"); e.setValue(eContext, "true");
@ -139,18 +160,18 @@ public class SetValueTests extends ExpressionTestCase {
// All keys should be strings // All keys should be strings
Set ks = parse("mapOfStringToBoolean.keySet()").getValue(eContext,Set.class); Set ks = parse("mapOfStringToBoolean.keySet()").getValue(eContext,Set.class);
for (Object o: ks) { for (Object o: ks) {
assertEquals(String.class,o.getClass()); Assert.assertEquals(String.class,o.getClass());
} }
// All values should be booleans // All values should be booleans
Collection vs = parse("mapOfStringToBoolean.values()").getValue(eContext,Collection.class); Collection vs = parse("mapOfStringToBoolean.values()").getValue(eContext,Collection.class);
for (Object o: vs) { for (Object o: vs) {
assertEquals(Boolean.class,o.getClass()); Assert.assertEquals(Boolean.class,o.getClass());
} }
// One final test check coercion on the key for a map lookup // One final test check coercion on the key for a map lookup
Object o = e.getValue(eContext); Object o = e.getValue(eContext);
assertEquals(Boolean.TRUE,o); Assert.assertEquals(Boolean.TRUE,o);
} }
@ -165,17 +186,17 @@ public class SetValueTests extends ExpressionTestCase {
try { try {
Expression e = parser.parseExpression(expression); Expression e = parser.parseExpression(expression);
if (e == null) { if (e == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
if (DEBUG) { if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, e); SpelUtilities.printAbstractSyntaxTree(System.out, e);
} }
StandardEvaluationContext lContext = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext lContext = TestScenarioCreator.getTestEvaluationContext();
e.setValue(lContext, value); e.setValue(lContext, value);
fail("expected an error"); Assert.fail("expected an error");
} catch (ParseException pe) { } catch (ParseException pe) {
pe.printStackTrace(); pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage()); Assert.fail("Unexpected Exception: " + pe.getMessage());
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
// success! // success!
} }
@ -185,21 +206,21 @@ public class SetValueTests extends ExpressionTestCase {
try { try {
Expression e = parser.parseExpression(expression); Expression e = parser.parseExpression(expression);
if (e == null) { if (e == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
if (DEBUG) { if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, e); SpelUtilities.printAbstractSyntaxTree(System.out, e);
} }
StandardEvaluationContext lContext = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext lContext = TestScenarioCreator.getTestEvaluationContext();
assertTrue("Expression is not writeable but should be", e.isWritable(lContext)); Assert.assertTrue("Expression is not writeable but should be", e.isWritable(lContext));
e.setValue(lContext, value); e.setValue(lContext, value);
assertEquals("Retrieved value was not equal to set value", value, e.getValue(lContext)); Assert.assertEquals("Retrieved value was not equal to set value", value, e.getValue(lContext));
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
ee.printStackTrace(); ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage()); Assert.fail("Unexpected Exception: " + ee.getMessage());
} catch (ParseException pe) { } catch (ParseException pe) {
pe.printStackTrace(); pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage()); Assert.fail("Unexpected Exception: " + pe.getMessage());
} }
} }
@ -211,26 +232,26 @@ public class SetValueTests extends ExpressionTestCase {
try { try {
Expression e = parser.parseExpression(expression); Expression e = parser.parseExpression(expression);
if (e == null) { if (e == null) {
fail("Parser returned null for expression"); Assert.fail("Parser returned null for expression");
} }
if (DEBUG) { if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, e); SpelUtilities.printAbstractSyntaxTree(System.out, e);
} }
StandardEvaluationContext lContext = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext lContext = TestScenarioCreator.getTestEvaluationContext();
assertTrue("Expression is not writeable but should be", e.isWritable(lContext)); Assert.assertTrue("Expression is not writeable but should be", e.isWritable(lContext));
e.setValue(lContext, value); e.setValue(lContext, value);
Object a = expectedValue; Object a = expectedValue;
Object b = e.getValue(lContext); Object b = e.getValue(lContext);
if (!a.equals(b)) { if (!a.equals(b)) {
fail("Not the same: ["+a+"] type="+a.getClass()+" ["+b+"] type="+b.getClass()); Assert.fail("Not the same: ["+a+"] type="+a.getClass()+" ["+b+"] type="+b.getClass());
// assertEquals("Retrieved value was not equal to set value", expectedValue, e.getValue(lContext)); // Assert.assertEquals("Retrieved value was not equal to set value", expectedValue, e.getValue(lContext));
} }
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
ee.printStackTrace(); ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage()); Assert.fail("Unexpected Exception: " + ee.getMessage());
} catch (ParseException pe) { } catch (ParseException pe) {
pe.printStackTrace(); pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage()); Assert.fail("Unexpected Exception: " + pe.getMessage());
} }
} }
} }

View File

@ -24,11 +24,14 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser; import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext; import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.testresources.Inventor; import org.springframework.expression.spel.testresources.Inventor;
import org.springframework.expression.spel.testresources.PlaceOfBirth; import org.springframework.expression.spel.testresources.PlaceOfBirth;
@ -68,6 +71,7 @@ public class SpelDocumentationTests extends ExpressionTestCase {
public Inventor[] Members = new Inventor[1]; public Inventor[] Members = new Inventor[1];
public List Members2 = new ArrayList(); public List Members2 = new ArrayList();
public Map<String,Object> officers = new HashMap<String,Object>(); public Map<String,Object> officers = new HashMap<String,Object>();
@SuppressWarnings("unchecked")
IEEE() { IEEE() {
officers.put("president",pupin); officers.put("president",pupin);
List linv = new ArrayList(); List linv = new ArrayList();
@ -85,18 +89,22 @@ public class SpelDocumentationTests extends ExpressionTestCase {
public void setName(String n) { this.name = n; } public void setName(String n) { this.name = n; }
} }
@Test
public void testMethodInvocation() { public void testMethodInvocation() {
evaluate("'Hello World'.concat('!')","Hello World!",String.class); evaluate("'Hello World'.concat('!')","Hello World!",String.class);
} }
@Test
public void testBeanPropertyAccess() { public void testBeanPropertyAccess() {
evaluate("new String('Hello World'.bytes)","Hello World",String.class); evaluate("new String('Hello World'.bytes)","Hello World",String.class);
} }
@Test
public void testArrayLengthAccess() { public void testArrayLengthAccess() {
evaluate("'Hello World'.bytes.length",11,Integer.class); evaluate("'Hello World'.bytes.length",11,Integer.class);
} }
@Test
public void testRootObject() throws Exception { public void testRootObject() throws Exception {
GregorianCalendar c = new GregorianCalendar(); GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9); c.set(1856, 7, 9);
@ -104,65 +112,70 @@ public class SpelDocumentationTests extends ExpressionTestCase {
// The constructor arguments are name, birthday, and nationaltiy. // The constructor arguments are name, birthday, and nationaltiy.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian"); Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
ExpressionParser parser = new SpelAntlrExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("name"); Expression exp = parser.parseExpression("name");
EvaluationContext context = new StandardEvaluationContext(); EvaluationContext context = new StandardEvaluationContext();
context.setRootObject(tesla); context.setRootObject(tesla);
String name = (String) exp.getValue(context); String name = (String) exp.getValue(context);
assertEquals("Nikola Tesla",name); Assert.assertEquals("Nikola Tesla",name);
} }
@Test
public void testEqualityCheck() throws Exception { public void testEqualityCheck() throws Exception {
ExpressionParser parser = new SpelAntlrExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext(); EvaluationContext context = new StandardEvaluationContext();
context.setRootObject(tesla); context.setRootObject(tesla);
Expression exp = parser.parseExpression("name == 'Nikola Tesla'"); Expression exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean isEqual = exp.getValue(context, Boolean.class); // evaluates to true boolean isEqual = exp.getValue(context, Boolean.class); // evaluates to true
assertTrue(isEqual); Assert.assertTrue(isEqual);
} }
// Section 7.4.1 // Section 7.4.1
@Test
public void testXMLBasedConfig() { public void testXMLBasedConfig() {
evaluate("(T(java.lang.Math).random() * 100.0 )>0",true,Boolean.class); evaluate("(T(java.lang.Math).random() * 100.0 )>0",true,Boolean.class);
} }
// Section 7.5 // Section 7.5
@Test
public void testLiterals() throws Exception { public void testLiterals() throws Exception {
ExpressionParser parser = new SpelAntlrExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue(); // evals to "Hello World" String helloWorld = (String) parser.parseExpression("'Hello World'").getValue(); // evals to "Hello World"
assertEquals("Hello World",helloWorld); Assert.assertEquals("Hello World",helloWorld);
double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue(); double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();
assertEquals(6.0221415E+23,avogadrosNumber); Assert.assertEquals(6.0221415E+23,avogadrosNumber);
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue(); // evals to 2147483647 int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue(); // evals to 2147483647
assertEquals(Integer.MAX_VALUE,maxValue); Assert.assertEquals(Integer.MAX_VALUE,maxValue);
boolean trueValue = (Boolean) parser.parseExpression("true").getValue(); boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
assertTrue(trueValue); Assert.assertTrue(trueValue);
Object nullValue = parser.parseExpression("null").getValue(); Object nullValue = parser.parseExpression("null").getValue();
assertNull(nullValue); Assert.assertNull(nullValue);
} }
@Test
public void testPropertyAccess() throws Exception { public void testPropertyAccess() throws Exception {
EvaluationContext context = TestScenarioCreator.getTestEvaluationContext(); EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context); // 1856 int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context); // 1856
assertEquals(1856,year); Assert.assertEquals(1856,year);
String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context); String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);
assertEquals("SmilJan",city); Assert.assertEquals("SmilJan",city);
} }
@Test
public void testPropertyNavigation() throws Exception { public void testPropertyNavigation() throws Exception {
ExpressionParser parser = new SpelAntlrExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
// Inventions Array // Inventions Array
StandardEvaluationContext teslaContext = TestScenarioCreator.getTestEvaluationContext(); StandardEvaluationContext teslaContext = TestScenarioCreator.getTestEvaluationContext();
@ -170,7 +183,7 @@ public class SpelDocumentationTests extends ExpressionTestCase {
// evaluates to "Induction motor" // evaluates to "Induction motor"
String invention = parser.parseExpression("inventions[3]").getValue(teslaContext, String.class); String invention = parser.parseExpression("inventions[3]").getValue(teslaContext, String.class);
assertEquals("Induction motor",invention); Assert.assertEquals("Induction motor",invention);
// Members List // Members List
StandardEvaluationContext societyContext = new StandardEvaluationContext(); StandardEvaluationContext societyContext = new StandardEvaluationContext();
@ -180,15 +193,16 @@ public class SpelDocumentationTests extends ExpressionTestCase {
// evaluates to "Nikola Tesla" // evaluates to "Nikola Tesla"
String name = parser.parseExpression("Members[0].Name").getValue(societyContext, String.class); String name = parser.parseExpression("Members[0].Name").getValue(societyContext, String.class);
assertEquals("Nikola Tesla",name); Assert.assertEquals("Nikola Tesla",name);
// List and Array navigation // List and Array navigation
// evaluates to "Wireless communication" // evaluates to "Wireless communication"
invention = parser.parseExpression("Members[0].Inventions[6]").getValue(societyContext, String.class); invention = parser.parseExpression("Members[0].Inventions[6]").getValue(societyContext, String.class);
assertEquals("Wireless communication",invention); Assert.assertEquals("Wireless communication",invention);
} }
@Test
public void testDictionaryAccess() throws Exception { public void testDictionaryAccess() throws Exception {
StandardEvaluationContext societyContext = new StandardEvaluationContext(); StandardEvaluationContext societyContext = new StandardEvaluationContext();
societyContext.setRootObject(new IEEE()); societyContext.setRootObject(new IEEE());
@ -200,7 +214,7 @@ public class SpelDocumentationTests extends ExpressionTestCase {
// setting values // setting values
Inventor i = parser.parseExpression("officers['advisors'][0]").getValue(societyContext,Inventor.class); Inventor i = parser.parseExpression("officers['advisors'][0]").getValue(societyContext,Inventor.class);
assertEquals("Nikola Tesla",i.getName()); Assert.assertEquals("Nikola Tesla",i.getName());
parser.parseExpression("officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext, "Croatia"); parser.parseExpression("officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext, "Croatia");
@ -208,48 +222,52 @@ public class SpelDocumentationTests extends ExpressionTestCase {
// 7.5.3 // 7.5.3
@Test
public void testMethodInvocation2() throws Exception { public void testMethodInvocation2() throws Exception {
// string literal, evaluates to "bc" // string literal, evaluates to "bc"
String c = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class); String c = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);
assertEquals("bc",c); Assert.assertEquals("bc",c);
StandardEvaluationContext societyContext = new StandardEvaluationContext(); StandardEvaluationContext societyContext = new StandardEvaluationContext();
societyContext.setRootObject(new IEEE()); societyContext.setRootObject(new IEEE());
// evaluates to true // evaluates to true
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(societyContext, Boolean.class); boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(societyContext, Boolean.class);
assertTrue(isMember); Assert.assertTrue(isMember);
} }
// 7.5.4.1 // 7.5.4.1
@Test
public void testRelationalOperators() throws Exception { public void testRelationalOperators() throws Exception {
boolean result = parser.parseExpression("2 == 2").getValue(Boolean.class); boolean result = parser.parseExpression("2 == 2").getValue(Boolean.class);
assertTrue(result); Assert.assertTrue(result);
// evaluates to false // evaluates to false
result = parser.parseExpression("2 < -5.0").getValue(Boolean.class); result = parser.parseExpression("2 < -5.0").getValue(Boolean.class);
assertFalse(result); Assert.assertFalse(result);
// evaluates to true // evaluates to true
result = parser.parseExpression("'black' < 'block'").getValue(Boolean.class); result = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);
assertTrue(result); Assert.assertTrue(result);
} }
@Test
public void testOtherOperators() throws Exception { public void testOtherOperators() throws Exception {
// evaluates to false // evaluates to false
boolean falseValue = parser.parseExpression("'xyz' instanceof T(int)").getValue(Boolean.class); boolean falseValue = parser.parseExpression("'xyz' instanceof T(int)").getValue(Boolean.class);
assertFalse(falseValue); Assert.assertFalse(falseValue);
// evaluates to true // evaluates to true
boolean trueValue = parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class); boolean trueValue = parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
assertTrue(trueValue); Assert.assertTrue(trueValue);
//evaluates to false //evaluates to false
falseValue = parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class); falseValue = parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
assertFalse(falseValue); Assert.assertFalse(falseValue);
} }
// 7.5.4.2 // 7.5.4.2
@Test
public void testLogicalOperators() throws Exception { public void testLogicalOperators() throws Exception {
StandardEvaluationContext societyContext = new StandardEvaluationContext(); StandardEvaluationContext societyContext = new StandardEvaluationContext();
@ -259,7 +277,7 @@ public class SpelDocumentationTests extends ExpressionTestCase {
// evaluates to false // evaluates to false
boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class); boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class);
assertFalse(falseValue); Assert.assertFalse(falseValue);
// evaluates to true // evaluates to true
String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')"; String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
@ -268,71 +286,73 @@ public class SpelDocumentationTests extends ExpressionTestCase {
// evaluates to true // evaluates to true
trueValue = parser.parseExpression("true or false").getValue(Boolean.class); trueValue = parser.parseExpression("true or false").getValue(Boolean.class);
assertTrue(trueValue); Assert.assertTrue(trueValue);
// evaluates to true // evaluates to true
expression = "isMember('Nikola Tesla') or isMember('Albert Einstien')"; expression = "isMember('Nikola Tesla') or isMember('Albert Einstien')";
trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
assertTrue(trueValue); Assert.assertTrue(trueValue);
// -- NOT -- // -- NOT --
// evaluates to false // evaluates to false
falseValue = parser.parseExpression("!true").getValue(Boolean.class); falseValue = parser.parseExpression("!true").getValue(Boolean.class);
assertFalse(falseValue); Assert.assertFalse(falseValue);
// -- AND and NOT -- // -- AND and NOT --
expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')"; expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
assertFalse(falseValue); Assert.assertFalse(falseValue);
} }
// 7.5.4.3 // 7.5.4.3
@Test
public void testNumericalOperators() throws Exception { public void testNumericalOperators() throws Exception {
// Addition // Addition
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2 int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
assertEquals(2,two); Assert.assertEquals(2,two);
String testString = parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class); // 'test string' String testString = parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class); // 'test string'
assertEquals("test string",testString); Assert.assertEquals("test string",testString);
// Subtraction // Subtraction
int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4 int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4
assertEquals(4,four); Assert.assertEquals(4,four);
double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000 double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000
assertEquals(-9000.0d,d); Assert.assertEquals(-9000.0d,d);
// Multiplication // Multiplication
int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6 int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6
assertEquals(6,six); Assert.assertEquals(6,six);
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0 double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0
assertEquals(24.0d,twentyFour); Assert.assertEquals(24.0d,twentyFour);
// Division // Division
int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2 int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2
assertEquals(-2,minusTwo); Assert.assertEquals(-2,minusTwo);
double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0 double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0
assertEquals(1.0d,one); Assert.assertEquals(1.0d,one);
// Modulus // Modulus
int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3 int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3
assertEquals(3,three); Assert.assertEquals(3,three);
int oneInt = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1 int oneInt = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1
assertEquals(1,oneInt); Assert.assertEquals(1,oneInt);
// Operator precedence // Operator precedence
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21 int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21
assertEquals(-21,minusTwentyOne); Assert.assertEquals(-21,minusTwentyOne);
} }
// 7.5.5 // 7.5.5
@Test
public void testAssignment() throws Exception { public void testAssignment() throws Exception {
Inventor inventor = new Inventor(); Inventor inventor = new Inventor();
StandardEvaluationContext inventorContext = new StandardEvaluationContext(); StandardEvaluationContext inventorContext = new StandardEvaluationContext();
@ -340,37 +360,40 @@ public class SpelDocumentationTests extends ExpressionTestCase {
parser.parseExpression("foo").setValue(inventorContext, "Alexander Seovic2"); parser.parseExpression("foo").setValue(inventorContext, "Alexander Seovic2");
assertEquals("Alexander Seovic2",parser.parseExpression("foo").getValue(inventorContext,String.class)); Assert.assertEquals("Alexander Seovic2",parser.parseExpression("foo").getValue(inventorContext,String.class));
// alternatively // alternatively
String aleks = parser.parseExpression("foo = 'Alexandar Seovic'").getValue(inventorContext, String.class); String aleks = parser.parseExpression("foo = 'Alexandar Seovic'").getValue(inventorContext, String.class);
assertEquals("Alexandar Seovic",parser.parseExpression("foo").getValue(inventorContext,String.class)); Assert.assertEquals("Alexandar Seovic",parser.parseExpression("foo").getValue(inventorContext,String.class));
assertEquals("Alexandar Seovic",aleks); Assert.assertEquals("Alexandar Seovic",aleks);
} }
// 7.5.6 // 7.5.6
@Test
public void testTypes() throws Exception { public void testTypes() throws Exception {
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class); Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
assertEquals(Date.class,dateClass); Assert.assertEquals(Date.class,dateClass);
boolean trueValue = parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR").getValue(Boolean.class); boolean trueValue = parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR").getValue(Boolean.class);
assertTrue(trueValue); Assert.assertTrue(trueValue);
} }
// 7.5.7 // 7.5.7
@Test
public void testConstructors() throws Exception { public void testConstructors() throws Exception {
StandardEvaluationContext societyContext = new StandardEvaluationContext(); StandardEvaluationContext societyContext = new StandardEvaluationContext();
societyContext.setRootObject(new IEEE()); societyContext.setRootObject(new IEEE());
Inventor einstein = Inventor einstein =
parser.parseExpression("new org.springframework.expression.spel.testresources.Inventor('Albert Einstein',new java.util.Date(), 'German')").getValue(Inventor.class); parser.parseExpression("new org.springframework.expression.spel.testresources.Inventor('Albert Einstein',new java.util.Date(), 'German')").getValue(Inventor.class);
assertEquals("Albert Einstein", einstein.getName()); Assert.assertEquals("Albert Einstein", einstein.getName());
//create new inventor instance within add method of List //create new inventor instance within add method of List
parser.parseExpression("Members2.add(new org.springframework.expression.spel.testresources.Inventor('Albert Einstein', 'German'))").getValue(societyContext); parser.parseExpression("Members2.add(new org.springframework.expression.spel.testresources.Inventor('Albert Einstein', 'German'))").getValue(societyContext);
} }
// 7.5.8 // 7.5.8
@Test
public void testVariables() throws Exception { public void testVariables() throws Exception {
Inventor tesla = new Inventor("Nikola Tesla", "Serbian"); Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
StandardEvaluationContext context = new StandardEvaluationContext(); StandardEvaluationContext context = new StandardEvaluationContext();
@ -380,42 +403,46 @@ public class SpelDocumentationTests extends ExpressionTestCase {
parser.parseExpression("foo = #newName").getValue(context); parser.parseExpression("foo = #newName").getValue(context);
assertEquals("Mike Tesla",tesla.getFoo()); Assert.assertEquals("Mike Tesla",tesla.getFoo());
} }
@SuppressWarnings("unchecked")
@Test
public void testSpecialVariables() throws Exception { public void testSpecialVariables() throws Exception {
// create an array of integers // create an array of integers
List<Integer> primes = new ArrayList<Integer>(); List<Integer> primes = new ArrayList<Integer>();
primes.addAll(Arrays.asList(2,3,5,7,11,13,17)); primes.addAll(Arrays.asList(2,3,5,7,11,13,17));
// create parser and set variable 'primes' as the array of integers // create parser and set variable 'primes' as the array of integers
ExpressionParser parser = new SpelAntlrExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext(); StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("primes",primes); context.setVariable("primes",primes);
// all prime numbers > 10 from the list (using selection ?{...}) // all prime numbers > 10 from the list (using selection ?{...})
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context); List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context);
assertEquals("[11, 13, 17]",primesGreaterThanTen.toString()); Assert.assertEquals("[11, 13, 17]",primesGreaterThanTen.toString());
} }
// 7.5.9 // 7.5.9
@Test
public void testFunctions() throws Exception { public void testFunctions() throws Exception {
ExpressionParser parser = new SpelAntlrExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext(); StandardEvaluationContext context = new StandardEvaluationContext();
context.registerFunction("reverseString", context.registerFunction("reverseString",
StringUtils.class.getDeclaredMethod("reverseString", new Class[] { String.class })); StringUtils.class.getDeclaredMethod("reverseString", new Class[] { String.class }));
String helloWorldReversed = parser.parseExpression("#reverseString('hello world')").getValue(context, String.class); String helloWorldReversed = parser.parseExpression("#reverseString('hello world')").getValue(context, String.class);
assertEquals("dlrow olleh",helloWorldReversed); Assert.assertEquals("dlrow olleh",helloWorldReversed);
} }
// 7.5.10 // 7.5.10
@Test
public void testTernary() throws Exception { public void testTernary() throws Exception {
String falseString = parser.parseExpression("false ? 'trueExp' : 'falseExp'").getValue(String.class); String falseString = parser.parseExpression("false ? 'trueExp' : 'falseExp'").getValue(String.class);
assertEquals("falseExp",falseString); Assert.assertEquals("falseExp",falseString);
StandardEvaluationContext societyContext = new StandardEvaluationContext(); StandardEvaluationContext societyContext = new StandardEvaluationContext();
societyContext.setRootObject(new IEEE()); societyContext.setRootObject(new IEEE());
@ -428,26 +455,29 @@ public class SpelDocumentationTests extends ExpressionTestCase {
"+ Name + ' Society' : #queryName + ' is not a member of the ' + Name + ' Society'"; "+ Name + ' Society' : #queryName + ' is not a member of the ' + Name + ' Society'";
String queryResultString = parser.parseExpression(expression).getValue(societyContext, String.class); String queryResultString = parser.parseExpression(expression).getValue(societyContext, String.class);
assertEquals("Nikola Tesla is a member of the IEEE Society",queryResultString); Assert.assertEquals("Nikola Tesla is a member of the IEEE Society",queryResultString);
// queryResultString = "Nikola Tesla is a member of the IEEE Society" // queryResultString = "Nikola Tesla is a member of the IEEE Society"
} }
// 7.5.11 // 7.5.11
@SuppressWarnings("unchecked")
@Test
public void testSelection() throws Exception { public void testSelection() throws Exception {
StandardEvaluationContext societyContext = new StandardEvaluationContext(); StandardEvaluationContext societyContext = new StandardEvaluationContext();
societyContext.setRootObject(new IEEE()); societyContext.setRootObject(new IEEE());
List<Inventor> list = (List<Inventor>) parser.parseExpression("Members2.?[nationality == 'Serbian']").getValue(societyContext); List<Inventor> list = (List<Inventor>) parser.parseExpression("Members2.?[nationality == 'Serbian']").getValue(societyContext);
assertEquals(1,list.size()); Assert.assertEquals(1,list.size());
assertEquals("Nikola Tesla",list.get(0).getName()); Assert.assertEquals("Nikola Tesla",list.get(0).getName());
} }
// 7.5.12 // 7.5.12
@Test
public void testTemplating() throws Exception { public void testTemplating() throws Exception {
String randomPhrase = String randomPhrase =
parser.parseExpression("random number is ${T(java.lang.Math).random()}", new TemplatedParserContext()).getValue(String.class); parser.parseExpression("random number is ${T(java.lang.Math).random()}", new TemplatedParserContext()).getValue(String.class);
assertTrue(randomPhrase.startsWith("random number")); Assert.assertTrue(randomPhrase.startsWith("random number"));
} }
static class TemplatedParserContext implements ParserContext { static class TemplatedParserContext implements ParserContext {

View File

@ -16,12 +16,15 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext; import org.springframework.expression.ParserContext;
import org.springframework.expression.PropertyAccessor; import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.ReflectivePropertyResolver; import org.springframework.expression.spel.support.ReflectivePropertyResolver;
/** /**
@ -31,10 +34,12 @@ import org.springframework.expression.spel.support.ReflectivePropertyResolver;
*/ */
public class SpringEL300Tests extends ExpressionTestCase { public class SpringEL300Tests extends ExpressionTestCase {
@Test
public void testNPE_SPR5661() { public void testNPE_SPR5661() {
evaluate("joinThreeStrings('a',null,'c')", "anullc", String.class); evaluate("joinThreeStrings('a',null,'c')", "anullc", String.class);
} }
@Test
public void testNPE_SPR5673() throws Exception { public void testNPE_SPR5673() throws Exception {
ParserContext hashes = TemplateExpressionParsingTests.HASH_DELIMITED_PARSER_CONTEXT; ParserContext hashes = TemplateExpressionParsingTests.HASH_DELIMITED_PARSER_CONTEXT;
ParserContext dollars = TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT; ParserContext dollars = TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT;
@ -69,20 +74,21 @@ public class SpringEL300Tests extends ExpressionTestCase {
checkTemplateParsingError("Hello ${","No ending suffix '}' for expression starting at character 6: ${"); checkTemplateParsingError("Hello ${","No ending suffix '}' for expression starting at character 6: ${");
} }
@Test
public void testAccessingNullPropertyViaReflection_SPR5663() throws AccessException { public void testAccessingNullPropertyViaReflection_SPR5663() throws AccessException {
PropertyAccessor propertyAccessor = new ReflectivePropertyResolver(); PropertyAccessor propertyAccessor = new ReflectivePropertyResolver();
EvaluationContext context = TestScenarioCreator.getTestEvaluationContext(); EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
assertFalse(propertyAccessor.canRead(context, null, "abc")); Assert.assertFalse(propertyAccessor.canRead(context, null, "abc"));
assertFalse(propertyAccessor.canWrite(context, null, "abc")); Assert.assertFalse(propertyAccessor.canWrite(context, null, "abc"));
try { try {
propertyAccessor.read(context, null, "abc"); propertyAccessor.read(context, null, "abc");
fail("Should have failed with an AccessException"); Assert.fail("Should have failed with an AccessException");
} catch (AccessException ae) { } catch (AccessException ae) {
// success // success
} }
try { try {
propertyAccessor.write(context, null, "abc","foo"); propertyAccessor.write(context, null, "abc","foo");
fail("Should have failed with an AccessException"); Assert.fail("Should have failed with an AccessException");
} catch (AccessException ae) { } catch (AccessException ae) {
// success // success
} }
@ -96,9 +102,9 @@ public class SpringEL300Tests extends ExpressionTestCase {
} }
private void checkTemplateParsing(String expression, ParserContext context, String expectedValue) throws Exception { private void checkTemplateParsing(String expression, ParserContext context, String expectedValue) throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
Expression expr = parser.parseExpression(expression,context); Expression expr = parser.parseExpression(expression,context);
assertEquals(expectedValue,expr.getValue(TestScenarioCreator.getTestEvaluationContext())); Assert.assertEquals(expectedValue,expr.getValue(TestScenarioCreator.getTestEvaluationContext()));
} }
private void checkTemplateParsingError(String expression,String expectedMessage) throws Exception { private void checkTemplateParsingError(String expression,String expectedMessage) throws Exception {
@ -106,15 +112,15 @@ public class SpringEL300Tests extends ExpressionTestCase {
} }
private void checkTemplateParsingError(String expression,ParserContext context, String expectedMessage) throws Exception { private void checkTemplateParsingError(String expression,ParserContext context, String expectedMessage) throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
try { try {
parser.parseExpression(expression,context); parser.parseExpression(expression,context);
fail("Should have failed"); Assert.fail("Should have failed");
} catch (Exception e) { } catch (Exception e) {
if (!e.getMessage().equals(expectedMessage)) { if (!e.getMessage().equals(expectedMessage)) {
e.printStackTrace(); e.printStackTrace();
} }
assertEquals(expectedMessage,e.getMessage()); Assert.assertEquals(expectedMessage,e.getMessage());
} }
} }

View File

@ -17,8 +17,9 @@ package org.springframework.expression.spel;
import java.util.List; import java.util.List;
import junit.framework.TestCase; import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.support.StandardTypeLocator; import org.springframework.expression.spel.support.StandardTypeLocator;
@ -27,31 +28,32 @@ import org.springframework.expression.spel.support.StandardTypeLocator;
* *
* @author Andy Clement * @author Andy Clement
*/ */
public class StandardTypeLocatorTests extends TestCase { public class StandardTypeLocatorTests {
@Test
public void testImports() throws EvaluationException { public void testImports() throws EvaluationException {
StandardTypeLocator locator = new StandardTypeLocator(); StandardTypeLocator locator = new StandardTypeLocator();
assertEquals(Integer.class,locator.findType("java.lang.Integer")); Assert.assertEquals(Integer.class,locator.findType("java.lang.Integer"));
assertEquals(String.class,locator.findType("java.lang.String")); Assert.assertEquals(String.class,locator.findType("java.lang.String"));
List<String> prefixes = locator.getImportPrefixes(); List<String> prefixes = locator.getImportPrefixes();
assertEquals(1,prefixes.size()); Assert.assertEquals(1,prefixes.size());
assertTrue(prefixes.contains("java.lang")); Assert.assertTrue(prefixes.contains("java.lang"));
assertFalse(prefixes.contains("java.util")); Assert.assertFalse(prefixes.contains("java.util"));
assertEquals(Boolean.class,locator.findType("Boolean")); Assert.assertEquals(Boolean.class,locator.findType("Boolean"));
// currently does not know about java.util by default // currently does not know about java.util by default
// assertEquals(java.util.List.class,locator.findType("List")); // assertEquals(java.util.List.class,locator.findType("List"));
try { try {
locator.findType("URL"); locator.findType("URL");
fail("Should have failed"); Assert.fail("Should have failed");
} catch (EvaluationException ee) { } catch (EvaluationException ee) {
SpelException sEx = (SpelException)ee; SpelEvaluationException sEx = (SpelEvaluationException)ee;
assertEquals(SpelMessages.TYPE_NOT_FOUND,sEx.getMessageUnformatted()); Assert.assertEquals(SpelMessages.TYPE_NOT_FOUND,sEx.getMessageUnformatted());
} }
locator.registerImport("java.net"); locator.registerImport("java.net");
assertEquals(java.net.URL.class,locator.findType("URL")); Assert.assertEquals(java.net.URL.class,locator.findType("URL"));
} }

Some files were not shown because too many files have changed in this diff Show More