Hand written SpEL parser. Removed antlr dependency. tests upgraded to JUnit4 - 93% coverage.
This commit is contained in:
@@ -17,66 +17,51 @@
|
||||
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
|
||||
* @since 3.0
|
||||
*/
|
||||
public class EvaluationException extends Exception {
|
||||
|
||||
private String expressionString;
|
||||
|
||||
public class EvaluationException extends ExpressionException {
|
||||
|
||||
/**
|
||||
* Creates a new expression exception.
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
public EvaluationException(Throwable cause) {
|
||||
super(cause);
|
||||
* Creates a new expression evaluation exception.
|
||||
* @param position the position in the expression where the problem occurred
|
||||
* @param message description of the problem that occurred
|
||||
*/
|
||||
public EvaluationException(int position, String message) {
|
||||
super(position, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new expression parsing exception.
|
||||
* @param expressionString the expression string that could not be parsed
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
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
|
||||
*/
|
||||
* Creates a new expression evaluation exception.
|
||||
* @param expressionString the expression that could not be evaluated
|
||||
* @param message description of the problem that occurred
|
||||
*/
|
||||
public EvaluationException(String expressionString, String message) {
|
||||
super(message);
|
||||
this.expressionString = expressionString;
|
||||
super(expressionString, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new expression exception. The expressionString field should be set by a later call to
|
||||
* setExpressionString().
|
||||
* @param message a descriptive message
|
||||
*/
|
||||
* Creates a new expression evaluation exception.
|
||||
* @param position the position in the expression where the problem occurred
|
||||
* @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) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
public final String getExpressionString() {
|
||||
return this.expressionString;
|
||||
public EvaluationException(String message, Throwable cause) {
|
||||
super(message,cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,9 +25,6 @@ package org.springframework.expression;
|
||||
*/
|
||||
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
|
||||
* between the two operands and so should be invoked to handle it.
|
||||
|
||||
@@ -17,57 +17,40 @@
|
||||
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
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ParseException extends Exception {
|
||||
|
||||
private String expressionString;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new expression exception.
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
public ParseException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
public class ParseException extends ExpressionException {
|
||||
|
||||
/**
|
||||
* Creates a new expression parsing exception.
|
||||
* @param expressionString the expression string that could not be parsed
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
public ParseException(String expressionString, Throwable cause) {
|
||||
this(expressionString, "Exception occurred whilst handling '" + expressionString + "'", cause);
|
||||
* @param position the position in the expression string where the problem occurred
|
||||
* @param message description of the problem that occurred
|
||||
*/
|
||||
public ParseException(String expressionString, int position, String message) {
|
||||
super(expressionString, position, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new expression exception.
|
||||
* @param expressionString the expression string
|
||||
* @param message a descriptive message
|
||||
* Creates a new expression parsing exception.
|
||||
* @param position the position in the expression string where the problem occurred
|
||||
* @param message description of the problem that occurred
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
public ParseException(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 ParseException(String expressionString, String message) {
|
||||
*/
|
||||
public ParseException(int position, String message, Throwable cause) {
|
||||
super(message);
|
||||
this.expressionString = expressionString;
|
||||
}
|
||||
|
||||
|
||||
public final String getExpressionString() {
|
||||
return this.expressionString;
|
||||
|
||||
/**
|
||||
* Creates a new expression parsing exception.
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -43,7 +43,7 @@ import org.springframework.expression.TypedValue;
|
||||
public class ExpressionState {
|
||||
|
||||
private final EvaluationContext relatedContext;
|
||||
|
||||
|
||||
private final Stack<VariableScope> variableScopes = new Stack<VariableScope>();
|
||||
|
||||
private final Stack<TypedValue> contextObjects = new Stack<TypedValue>();
|
||||
@@ -158,7 +158,7 @@ public class ExpressionState {
|
||||
else {
|
||||
String leftType = (left==null?"null":left.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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +169,7 @@ public class ExpressionState {
|
||||
public EvaluationContext getEvaluationContext() {
|
||||
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
|
||||
* of the parameters clash with those in a higher level scope, those in the higher level scope will not be accessible whilst
|
||||
|
||||
@@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,41 +25,32 @@ import org.springframework.expression.EvaluationException;
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class SpelException extends EvaluationException {
|
||||
public class SpelEvaluationException extends EvaluationException {
|
||||
|
||||
private SpelMessages message;
|
||||
private int position = -1;
|
||||
private Object[] inserts;
|
||||
|
||||
public SpelException(int position, Throwable cause, SpelMessages message, Object... inserts) {
|
||||
super(cause);
|
||||
this.position = position;
|
||||
public SpelEvaluationException(SpelMessages message, Object... inserts) {
|
||||
super(message.formatMessage(0, inserts)); // TODO poor position information, can the callers not really supply something?
|
||||
this.message = message;
|
||||
this.inserts = inserts;
|
||||
}
|
||||
|
||||
public SpelException(Throwable cause, SpelMessages message, Object... inserts) {
|
||||
super(cause);
|
||||
public SpelEvaluationException(int position, SpelMessages message, Object... inserts) {
|
||||
super(position, message.formatMessage(position, inserts));
|
||||
this.message = message;
|
||||
this.inserts = inserts;
|
||||
}
|
||||
|
||||
public SpelException(int position, SpelMessages message, Object... inserts) {
|
||||
super((Throwable)null);
|
||||
this.position = position;
|
||||
public SpelEvaluationException(int position, Throwable cause,
|
||||
SpelMessages message, Object... inserts) {
|
||||
super(position,message.formatMessage(position,inserts),cause);
|
||||
this.message = message;
|
||||
this.inserts = inserts;
|
||||
}
|
||||
|
||||
public SpelException(SpelMessages message, Object... inserts) {
|
||||
super((Throwable)null);
|
||||
this.message = message;
|
||||
this.inserts = inserts;
|
||||
}
|
||||
|
||||
public SpelException(String expressionString, int position, Throwable cause, SpelMessages message, Object... inserts) {
|
||||
super(expressionString, cause);
|
||||
this.position = position;
|
||||
public SpelEvaluationException(Throwable cause, SpelMessages message, Object... inserts) {
|
||||
super(message.formatMessage(0,inserts),cause);
|
||||
this.message = message;
|
||||
this.inserts = inserts;
|
||||
}
|
||||
@@ -75,13 +66,6 @@ public class SpelException extends EvaluationException {
|
||||
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
|
||||
*/
|
||||
@@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,23 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
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
|
||||
* @since 3.0
|
||||
*/
|
||||
public class WrappedSpelException extends RuntimeException {
|
||||
public class SpelExpressionParserFactory {
|
||||
|
||||
public WrappedSpelException(SpelException e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpelException getCause() {
|
||||
return (SpelException) super.getCause();
|
||||
public static ExpressionParser getParser() {
|
||||
return new SpelExpressionParser();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,69 +36,58 @@ import java.text.MessageFormat;
|
||||
* @since 3.0
|
||||
*/
|
||||
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}"), //
|
||||
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"), //
|
||||
TYPE_NOT_FOUND(Kind.ERROR, 1004, "Type cannot be found ''{0}''"), //
|
||||
VARIABLE_NOT_FOUND(Kind.ERROR, 1005, "Variable named ''{0}'' cannot be found"), //
|
||||
LOCAL_VARIABLE_NOT_DEFINED(Kind.ERROR, 1006, "Local variable named ''{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, 1008, "Field or property ''{0}'' cannot be found on null"), //
|
||||
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, 1010, "Field or property ''{0}'' cannot be set on null"), //
|
||||
CONSTRUCTOR_INVOCATION_PROBLEM(Kind.ERROR, 1003, "A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"), //
|
||||
METHOD_NOT_FOUND(Kind.ERROR, 1004, "Method call: Method {0} cannot be found on {1} type"), //
|
||||
TYPE_NOT_FOUND(Kind.ERROR, 1005, "Type cannot be found ''{0}''"), //
|
||||
FUNCTION_NOT_DEFINED(Kind.ERROR, 1006, "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(Kind.ERROR, 1008, "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(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"), //
|
||||
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, 1013, "Cannot index into a null value"),
|
||||
|
||||
NOT_COMPARABLE(Kind.ERROR, 1014, "Cannot compare instances of {0} and {1}"), //
|
||||
NOT_COMPARABLE_CANNOT_COERCE(Kind.ERROR, 1015, "Cannot compare instances of {0} and {1} because they cannot be coerced to the same type"), //
|
||||
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1016, "Incorrect number of arguments for function, {0} supplied but function takes {1}"), //
|
||||
INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1017, "Cannot perform selection on input data of type ''{0}''"), //
|
||||
RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1018, "Result of selection criteria is not boolean"), //
|
||||
NULL_OPERAND_TO_OPERATOR(Kind.ERROR, 1019, "Operand evaluated to null and that is not supported for this operator"), //
|
||||
BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST(Kind.ERROR, 1020, "Right operand for the 'between' operator has to be a two-element list"), //
|
||||
UNABLE_TO_ACCESS_FIELD(Kind.ERROR, 1021, "Unable to access field ''{0}'' on type ''{1}''"), //
|
||||
UNABLE_TO_ACCESS_PROPERTY_THROUGH_GETTER(Kind.ERROR, 1022, "Unable to access property ''{0}'' through getter on type ''{1}''"), //
|
||||
UNABLE_TO_ACCESS_PROPERTY_THROUGH_SETTER(Kind.ERROR, 1023, "Unable to access property ''{0}'' through setter on type ''{1}''"), //
|
||||
INVALID_PATTERN(Kind.ERROR, 1024, "Pattern is not valid ''{0}''"), //
|
||||
RECOGNITION_ERROR(Kind.ERROR, 1025, "Recognition error: {0}"), // TODO poor message when a recognition exception occurs
|
||||
PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1026, "Projection is not supported on the type ''{0}''"), //
|
||||
ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1027, "The argument list of a lambda expression should never have getValue() called upon it"), //
|
||||
MAPENTRY_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1028, "A map entry should never have getValue() called upon it"), //
|
||||
EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1029, "A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"), //
|
||||
EXCEPTION_DURING_CONSTRUCTOR_INVOCATION(Kind.ERROR, 1030, "A problem occurred whilst attempting to construct ''{0}'': ''{1}''"), //
|
||||
DATE_CANNOT_BE_PARSED(Kind.ERROR, 1031, "Unable to parse date ''{0}'' using format ''{1}''"), //
|
||||
FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1032, "The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"), //
|
||||
EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1033, "A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"), //
|
||||
|
||||
// indexing
|
||||
ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1034, "The array has ''{0}'' elements, index ''{1}'' is invalid"), //
|
||||
COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1035, "The collection has ''{0}'' elements, index ''{1}'' is invalid"), //
|
||||
STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1036, "The string has ''{0}'' characters, index ''{1}'' is invalid"), //
|
||||
INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1037, "Indexing into type ''{0}'' is not supported"), //
|
||||
|
||||
INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1038, "The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"), //
|
||||
EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1039, "A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"), //
|
||||
OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1040, "The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"), //
|
||||
UNEXPECTED_PROBLEM_INVOKING_OPERATOR(Kind.ERROR, 1041, "Unexpected problem invoking operator ''{0}'' between objects of type ''{1}'' and ''{2}'': {3}"), //
|
||||
PROBLEM_LOCATING_METHOD(Kind.ERROR, 1042, "Problem locating method {0} cannot on type {1}"),
|
||||
PROBLEM_LOCATING_CONSTRUCTOR(Kind.ERROR, 1043, "A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"), //
|
||||
SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1044, "setValue(ExpressionState, Object) not implemented for ''{0}'' (''{1}''"), //
|
||||
PROBLEM_DURING_TYPE_CONVERSION(Kind.ERROR, 1045, "Problem occurred during type conversion: {0}"), //
|
||||
MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1046, "Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"), //
|
||||
EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1047, "A problem occurred whilst attempting to set the property ''{0}'': {1}"), //
|
||||
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."),//
|
||||
CANNOT_INDEX_INTO_NULL_VALUE(Kind.ERROR, 1012, "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}"), //
|
||||
INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1015, "Cannot perform selection on input data of type ''{0}''"), //
|
||||
RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1016, "Result of selection criteria is not boolean"), //
|
||||
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_PATTERN(Kind.ERROR, 1018, "Pattern is not valid ''{0}''"), //
|
||||
PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1019, "Projection is not supported on the type ''{0}''"), //
|
||||
ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1020, "The argument list of a lambda expression should never have getValue() called upon it"), //
|
||||
EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1021, "A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"), //
|
||||
FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1022, "The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"), //
|
||||
EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1023, "A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"), //
|
||||
ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1024, "The array has ''{0}'' elements, index ''{1}'' is invalid"), //
|
||||
COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1025, "The collection has ''{0}'' elements, index ''{1}'' is invalid"), //
|
||||
STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1026, "The string has ''{0}'' characters, index ''{1}'' is invalid"), //
|
||||
INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1027, "Indexing into type ''{0}'' is not supported"), //
|
||||
INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1028, "The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"), //
|
||||
EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1029, "A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"), //
|
||||
OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1030, "The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"), //
|
||||
PROBLEM_LOCATING_METHOD(Kind.ERROR, 1031, "Problem locating method {0} cannot on type {1}"),
|
||||
SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1032, "setValue(ExpressionState, Object) not supported for ''{0}''"), //
|
||||
MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1033, "Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"), //
|
||||
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"), //
|
||||
NOT_A_LONG(Kind.ERROR, 1036, "The value ''{0}'' cannot be parsed as a long"), //
|
||||
INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1037, "First operand to matches operator must be a string. ''{0}'' is not"), //
|
||||
INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1038, "Second operand to matches operator must be a string. ''{0}'' is not"), //
|
||||
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."),//
|
||||
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}''"),
|
||||
RIGHT_OPERAND_PROBLEM(Kind.ERROR,1042, "Problem parsing right operand"),
|
||||
NOT_EXPECTED_TOKEN(Kind.ERROR,1043,"Unexpected token. Expected ''{0}'' but was ''{1}''"),
|
||||
OOD(Kind.ERROR,1044,"Unexpectedly ran out of input"), //
|
||||
NON_TERMINATING_DOUBLE_QUOTED_STRING(Kind.ERROR,1045,"Cannot find terminating \" for string"),//
|
||||
NON_TERMINATING_QUOTED_STRING(Kind.ERROR,1046,"Cannot find terminating ' for string"), //
|
||||
MISSING_LEADING_ZERO_FOR_NUMBER(Kind.ERROR,1047,"A real number must be prefixed by zero, it cannot start with just ''.''"), //
|
||||
REAL_CANNOT_BE_LONG(Kind.ERROR,1048,"Real number cannot be suffixed with a long (L or l) suffix"),//
|
||||
UNEXPECTED_DATA_AFTER_DOT(Kind.ERROR,1049,"Unexpected data after ''.'': ''{0}''"),//
|
||||
MISSING_CONSTRUCTOR_ARGS(Kind.ERROR,1050,"The arguments '(...)' for the constructor call are missing"),//
|
||||
RUN_OUT_OF_ARGUMENTS(Kind.ERROR,1051,"Unexpected ran out of arguments"),//
|
||||
;
|
||||
|
||||
private Kind kind;
|
||||
@@ -125,12 +114,12 @@ public enum SpelMessages {
|
||||
StringBuilder formattedMessage = new StringBuilder();
|
||||
formattedMessage.append("EL").append(code);
|
||||
switch (kind) {
|
||||
case WARNING:
|
||||
formattedMessage.append("W");
|
||||
break;
|
||||
case INFO:
|
||||
formattedMessage.append("I");
|
||||
break;
|
||||
// case WARNING:
|
||||
// formattedMessage.append("W");
|
||||
// break;
|
||||
// case INFO:
|
||||
// formattedMessage.append("I");
|
||||
// break;
|
||||
case ERROR:
|
||||
formattedMessage.append("E");
|
||||
break;
|
||||
|
||||
@@ -79,4 +79,9 @@ public interface SpelNode {
|
||||
*/
|
||||
int getStartPosition();
|
||||
|
||||
/**
|
||||
* @return the end position of this Ast node in the expression string
|
||||
*/
|
||||
int getEndPosition();
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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];
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
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.spel.ExpressionState;
|
||||
@@ -31,13 +30,13 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
public class Assign extends SpelNodeImpl {
|
||||
|
||||
public Assign(Token payload) {
|
||||
super(payload);
|
||||
public Assign(int pos,SpelNodeImpl... operands) {
|
||||
super(pos,operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
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());
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
@@ -29,8 +28,8 @@ public class BooleanLiteral extends Literal {
|
||||
|
||||
private final BooleanTypedValue value;
|
||||
|
||||
public BooleanLiteral(Token payload, boolean value) {
|
||||
super(payload);
|
||||
public BooleanLiteral(String payload, int pos, boolean value) {
|
||||
super(payload, pos);
|
||||
this.value = BooleanTypedValue.forValue(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,17 +22,16 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface CommonTypeDescriptors {
|
||||
// TODO push into TypeDescriptor?
|
||||
static TypeDescriptor BOOLEAN_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Boolean.class);
|
||||
static TypeDescriptor INTEGER_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Integer.class);
|
||||
static TypeDescriptor CHARACTER_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Character.class);
|
||||
static TypeDescriptor LONG_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Long.class);
|
||||
static TypeDescriptor SHORT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Short.class);
|
||||
static TypeDescriptor BYTE_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Byte.class);
|
||||
static TypeDescriptor FLOAT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Float.class);
|
||||
static TypeDescriptor DOUBLE_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Double.class);
|
||||
static TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
|
||||
static TypeDescriptor CLASS_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Class.class);
|
||||
static TypeDescriptor OBJECT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Object.class);
|
||||
|
||||
// need a better home for these - TypeDescriptor?
|
||||
static TypeDescriptor<Boolean> BOOLEAN_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Boolean.class);
|
||||
static TypeDescriptor<Integer> INTEGER_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Integer.class);
|
||||
static TypeDescriptor<Character> CHARACTER_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Character.class);
|
||||
static TypeDescriptor<Long> LONG_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Long.class);
|
||||
static TypeDescriptor<Short> SHORT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Short.class);
|
||||
static TypeDescriptor<Byte> BYTE_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Byte.class);
|
||||
static TypeDescriptor<Float> FLOAT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Float.class);
|
||||
static TypeDescriptor<Double> DOUBLE_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Double.class);
|
||||
static TypeDescriptor<String> STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
|
||||
static TypeDescriptor<Class> CLASS_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Class.class);
|
||||
static TypeDescriptor<Object> OBJECT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Object.class);
|
||||
}
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
|
||||
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.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()'
|
||||
@@ -30,9 +29,13 @@ import org.springframework.expression.spel.SpelException;
|
||||
*/
|
||||
public class CompoundExpression extends SpelNodeImpl {
|
||||
|
||||
public CompoundExpression(Token payload) {
|
||||
super(payload);
|
||||
public CompoundExpression(int pos,SpelNodeImpl... expressionComponents) {
|
||||
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
|
||||
@@ -45,20 +48,20 @@ public class CompoundExpression extends SpelNodeImpl {
|
||||
TypedValue result = null;
|
||||
SpelNodeImpl nextNode = null;
|
||||
try {
|
||||
nextNode = getChild(0);
|
||||
nextNode = children[0];
|
||||
result = nextNode.getValueInternal(state);
|
||||
for (int i = 1; i < getChildCount(); i++) {
|
||||
try {
|
||||
state.pushActiveContextObject(result);
|
||||
nextNode = getChild(i);
|
||||
nextNode = children[i];
|
||||
result = nextNode.getValueInternal(state);
|
||||
} finally {
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
}
|
||||
} catch (SpelException ee) {
|
||||
} catch (SpelEvaluationException ee) {
|
||||
// Correct the position for the error before rethrowing
|
||||
ee.setPosition(nextNode.getCharPositionInLine());
|
||||
ee.setPosition(nextNode.getStartPosition());
|
||||
throw ee;
|
||||
}
|
||||
return result;
|
||||
@@ -70,11 +73,11 @@ public class CompoundExpression extends SpelNodeImpl {
|
||||
getChild(0).setValue(state, value);
|
||||
return;
|
||||
}
|
||||
TypedValue ctx = getChild(0).getValueInternal(state);
|
||||
TypedValue ctx = children[0].getValueInternal(state);
|
||||
for (int i = 1; i < getChildCount() - 1; i++) {
|
||||
try {
|
||||
state.pushActiveContextObject(ctx);
|
||||
ctx = getChild(i).getValueInternal(state);
|
||||
ctx = children[i].getValueInternal(state);
|
||||
} finally {
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
@@ -92,11 +95,11 @@ public class CompoundExpression extends SpelNodeImpl {
|
||||
if (getChildCount() == 1) {
|
||||
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++) {
|
||||
try {
|
||||
state.pushActiveContextObject(ctx);
|
||||
ctx = getChild(i).getValueInternal(state);
|
||||
ctx = children[i].getValueInternal(state);
|
||||
} finally {
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
@@ -113,6 +116,7 @@ public class CompoundExpression extends SpelNodeImpl {
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
if (i>0) { sb.append("."); }
|
||||
sb.append(getChild(i).toStringAST());
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.expression.spel.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.ConstructorExecutor;
|
||||
import org.springframework.expression.ConstructorResolver;
|
||||
@@ -26,10 +25,11 @@ import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
// 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
|
||||
* an array is constructed, an initializer can be specified.
|
||||
@@ -42,7 +42,7 @@ import org.springframework.expression.spel.SpelMessages;
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
*/
|
||||
public class ConstructorReference extends SpelNodeImpl {
|
||||
|
||||
// TODO is this caching safe - passing the expression around will mean this executor is also being passed around
|
||||
@@ -51,8 +51,13 @@ public class ConstructorReference extends SpelNodeImpl {
|
||||
*/
|
||||
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];
|
||||
Class<?>[] argumentTypes = new Class[getChildCount() - 1];
|
||||
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();
|
||||
arguments[i] = value;
|
||||
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
|
||||
String typename = (String) getChild(0).getValueInternal(state).getValue();
|
||||
String typename = (String) children[0].getValueInternal(state).getValue();
|
||||
executorToUse = findExecutorForConstructor(typename, argumentTypes, state);
|
||||
try {
|
||||
this.cachedExecutor = executorToUse;
|
||||
TypedValue result = executorToUse.execute(state.getEvaluationContext(), arguments);
|
||||
return result;
|
||||
} 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 state the current state of the expression
|
||||
* @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(
|
||||
String typename, Class<?>[] argumentTypes, ExpressionState state) throws SpelException {
|
||||
String typename, Class<?>[] argumentTypes, ExpressionState state) throws SpelEvaluationException {
|
||||
|
||||
EvaluationContext eContext = state.getEvaluationContext();
|
||||
List<ConstructorResolver> cResolvers = eContext.getConstructorResolvers();
|
||||
@@ -125,14 +132,13 @@ public class ConstructorReference extends SpelNodeImpl {
|
||||
if (cEx != null) {
|
||||
return cEx;
|
||||
}
|
||||
}
|
||||
catch (AccessException ex) {
|
||||
throw new SpelException(ex, SpelMessages.PROBLEM_LOCATING_CONSTRUCTOR, typename,
|
||||
} catch (AccessException ex) {
|
||||
throw new SpelEvaluationException(getStartPosition(),ex, SpelMessages.CONSTRUCTOR_INVOCATION_PROBLEM, typename,
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,33 +16,42 @@
|
||||
|
||||
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.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
|
||||
* @since 3.0
|
||||
*/
|
||||
public class Dot extends SpelNodeImpl {
|
||||
// TODO Keep Dot for the positional information or remove it?
|
||||
public class Elvis extends SpelNodeImpl {
|
||||
|
||||
public Dot(Token payload) {
|
||||
super(payload);
|
||||
public Elvis(int pos, SpelNodeImpl... args) {
|
||||
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
|
||||
public String toStringAST() {
|
||||
return ".";
|
||||
}
|
||||
|
||||
@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();
|
||||
return new StringBuilder().append(getChild(0).toStringAST()).append(" ?: ").append(getChild(1).toStringAST()).toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,14 +20,13 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.TypedValue;
|
||||
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.support.ReflectionHelper;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -48,26 +47,28 @@ public class FunctionReference extends SpelNodeImpl {
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
public FunctionReference(Token payload) {
|
||||
super(payload);
|
||||
this.name = payload.getText();
|
||||
public FunctionReference(String functionName, int pos, SpelNodeImpl... arguments) {
|
||||
super(pos,arguments);
|
||||
name = functionName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue o = state.lookupVariable(name);
|
||||
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
|
||||
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());
|
||||
} catch (SpelEvaluationException se) {
|
||||
se.setPosition(getStartPosition());
|
||||
throw se;
|
||||
}
|
||||
|
||||
return executeFunctionJLRMethod(state, (Method) o.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,12 +83,12 @@ public class FunctionReference extends SpelNodeImpl {
|
||||
Object[] functionArgs = getArguments(state);
|
||||
|
||||
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);
|
||||
}
|
||||
// Only static methods can be called in this way
|
||||
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()
|
||||
+ "." + m.getName(), name);
|
||||
}
|
||||
@@ -106,13 +107,13 @@ public class FunctionReference extends SpelNodeImpl {
|
||||
Object result = m.invoke(m.getClass(), functionArgs);
|
||||
return new TypedValue(result, new TypeDescriptor(new MethodParameter(m,-1)));
|
||||
} 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());
|
||||
} 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());
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
@@ -140,7 +141,7 @@ public class FunctionReference extends SpelNodeImpl {
|
||||
// Compute arguments to the function
|
||||
Object[] arguments = new Object[getChildCount()];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
arguments[i] = getChild(i).getValueInternal(state).getValue();
|
||||
arguments[i] = children[i].getValueInternal(state).getValue();
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
@@ -28,9 +27,9 @@ public class Identifier extends SpelNodeImpl {
|
||||
|
||||
private final TypedValue id;
|
||||
|
||||
public Identifier(Token payload) {
|
||||
super(payload);
|
||||
this.id = new TypedValue(payload.getText(), STRING_TYPE_DESCRIPTOR);
|
||||
public Identifier(String payload,int pos) {
|
||||
super(pos);
|
||||
this.id = new TypedValue(payload, STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,12 +20,11 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
// TODO support multidimensional arrays
|
||||
@@ -39,16 +38,17 @@ import org.springframework.expression.spel.SpelMessages;
|
||||
*/
|
||||
public class Indexer extends SpelNodeImpl {
|
||||
|
||||
public Indexer(Token payload) {
|
||||
super(payload);
|
||||
public Indexer(int pos,SpelNodeImpl expr) {
|
||||
super(pos,expr);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue context = state.getActiveContextObject();
|
||||
Object targetObject = context.getValue();
|
||||
TypeDescriptor targetObjectTypeDescriptor = context.getTypeDescriptor();
|
||||
TypedValue indexValue = getChild(0).getValueInternal(state);
|
||||
TypedValue indexValue = children[0].getValueInternal(state);
|
||||
Object index = indexValue.getValue();
|
||||
|
||||
// Indexing into a Map
|
||||
@@ -61,7 +61,7 @@ public class Indexer extends SpelNodeImpl {
|
||||
int idx = (Integer)state.convertValue(index, INTEGER_TYPE_DESCRIPTOR);
|
||||
|
||||
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()) {
|
||||
@@ -69,7 +69,7 @@ public class Indexer extends SpelNodeImpl {
|
||||
} else if (targetObject instanceof Collection) {
|
||||
Collection<?> c = (Collection<?>) targetObject;
|
||||
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;
|
||||
for (Object o : c) {
|
||||
@@ -81,16 +81,16 @@ public class Indexer extends SpelNodeImpl {
|
||||
} else if (targetObject instanceof String) {
|
||||
String ctxString = (String) targetObject;
|
||||
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);
|
||||
}
|
||||
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.asString());
|
||||
throw new SpelEvaluationException(getStartPosition(),SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.asString());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelEvaluationException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -100,10 +100,10 @@ public class Indexer extends SpelNodeImpl {
|
||||
TypedValue contextObject = state.getActiveContextObject();
|
||||
Object targetObject = contextObject.getValue();
|
||||
TypeDescriptor targetObjectTypeDescriptor = contextObject.getTypeDescriptor();
|
||||
TypedValue index = getChild(0).getValueInternal(state);
|
||||
TypedValue index = children[0].getValueInternal(state);
|
||||
|
||||
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
|
||||
if (targetObjectTypeDescriptor.isMap()) {
|
||||
@@ -121,17 +121,17 @@ public class Indexer extends SpelNodeImpl {
|
||||
int idx = (Integer)state.convertValue(index, INTEGER_TYPE_DESCRIPTOR);
|
||||
Collection c = (Collection) targetObject;
|
||||
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) {
|
||||
List list = (List)targetObject;
|
||||
Object possiblyConvertedValue = state.convertValue(newValue,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
|
||||
list.set(idx,possiblyConvertedValue);
|
||||
} 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 {
|
||||
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();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void setArrayElement(ExpressionState state, Object ctx, int idx, Object newValue, Class clazz) throws EvaluationException {
|
||||
Class<?> arrayComponentType = clazz;
|
||||
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();
|
||||
if (arrayComponentType == Integer.TYPE) {
|
||||
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) {
|
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.ARRAY_INDEX_OUT_OF_BOUNDS, arrayLength, index);
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessages.ARRAY_INDEX_OUT_OF_BOUNDS, arrayLength, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,42 +1,25 @@
|
||||
/*
|
||||
* 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.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* Expression language AST node that represents an integer literal.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class IntLiteral extends Literal {
|
||||
|
||||
private final TypedValue value;
|
||||
|
||||
IntLiteral(Token payload, int value) {
|
||||
super(payload);
|
||||
this.value = new TypedValue(value, INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* Expression language AST node that represents an integer literal.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class IntLiteral extends Literal {
|
||||
|
||||
private final TypedValue value;
|
||||
|
||||
IntLiteral(String payload, int pos, int value) {
|
||||
super(payload, pos);
|
||||
this.value = new TypedValue(value, INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,29 +16,31 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
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.WrappedSpelException;
|
||||
import org.springframework.expression.spel.SpelParseException;
|
||||
import org.springframework.expression.spel.standard.InternalParseException;
|
||||
|
||||
/**
|
||||
* Common superclass for nodes representing literals (boolean, string, number, etc).
|
||||
*
|
||||
* @author Andy Clement
|
||||
*
|
||||
*/
|
||||
public abstract class Literal extends SpelNodeImpl {
|
||||
|
||||
public Literal(Token payload) {
|
||||
super(payload);
|
||||
protected String literalValue;
|
||||
|
||||
public Literal(String payload, int pos) {
|
||||
super(pos);
|
||||
this.literalValue = payload;
|
||||
}
|
||||
|
||||
public abstract TypedValue getLiteralValue();
|
||||
|
||||
@Override
|
||||
public final TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
public final TypedValue getValueInternal(ExpressionState state) throws SpelEvaluationException {
|
||||
return getLiteralValue();
|
||||
}
|
||||
|
||||
@@ -60,37 +62,38 @@ public abstract class Literal extends SpelNodeImpl {
|
||||
* @param radix the base of number
|
||||
* @return a subtype of Literal that can represent it
|
||||
*/
|
||||
public static Literal getIntLiteral(Token numberToken, 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);
|
||||
public static Literal getIntLiteral(String numberToken, int pos, int radix) {
|
||||
try {
|
||||
int value = Integer.parseInt(numberToken, radix);
|
||||
return new IntLiteral(numberToken, pos, value);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessages.NOT_AN_INTEGER, numberToken));
|
||||
}
|
||||
}
|
||||
|
||||
if (isLong) {
|
||||
try {
|
||||
long value = Long.parseLong(numberString, radix);
|
||||
return new LongLiteral(numberToken, value);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new WrappedSpelException(new SpelException(numberToken.getCharPositionInLine(), nfe,
|
||||
SpelMessages.NOT_A_LONG, numberToken.getText()));
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
int value = Integer.parseInt(numberString, radix);
|
||||
return new IntLiteral(numberToken, value);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new WrappedSpelException(new SpelException(numberToken.getCharPositionInLine(), nfe,
|
||||
SpelMessages.NOT_AN_INTEGER, 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 {
|
||||
double value = Double.parseDouble(numberToken);
|
||||
return new RealLiteral(numberToken, pos, value);
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessages.NOT_A_REAL, numberToken));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
@@ -29,8 +28,8 @@ public class LongLiteral extends Literal {
|
||||
|
||||
private final TypedValue value;
|
||||
|
||||
LongLiteral(Token payload, long value) {
|
||||
super(payload);
|
||||
LongLiteral(String payload, int pos, long value) {
|
||||
super(payload, pos);
|
||||
this.value = new TypedValue(value, LONG_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.expression.spel.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
@@ -26,7 +25,7 @@ import org.springframework.expression.MethodExecutor;
|
||||
import org.springframework.expression.MethodResolver;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
/**
|
||||
@@ -39,11 +38,12 @@ public class MethodReference extends SpelNodeImpl {
|
||||
private final String name;
|
||||
|
||||
private volatile MethodExecutor cachedExecutor;
|
||||
private final boolean nullSafe;
|
||||
|
||||
|
||||
public MethodReference(Token payload) {
|
||||
super(payload);
|
||||
name = payload.getText();
|
||||
public MethodReference(boolean nullSafe, String methodName, int pos, SpelNodeImpl... arguments) {
|
||||
super(pos,arguments);
|
||||
name = methodName;
|
||||
this.nullSafe = nullSafe;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,11 +52,16 @@ public class MethodReference extends SpelNodeImpl {
|
||||
TypedValue currentContext = state.getActiveContextObject();
|
||||
Object[] arguments = new Object[getChildCount()];
|
||||
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) {
|
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED,
|
||||
FormatHelper.formatMethodForMessage(name, getTypes(arguments)));
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
MethodExecutor executorToUse = this.cachedExecutor;
|
||||
@@ -79,7 +84,7 @@ public class MethodReference extends SpelNodeImpl {
|
||||
return executorToUse.execute(
|
||||
state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments);
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
@@ -106,7 +111,7 @@ public class MethodReference extends SpelNodeImpl {
|
||||
}
|
||||
|
||||
private MethodExecutor findAccessorForMethod(String name, Class<?>[] argumentTypes, ExpressionState state)
|
||||
throws SpelException {
|
||||
throws SpelEvaluationException {
|
||||
|
||||
TypedValue context = state.getActiveContextObject();
|
||||
Object contextObject = context.getValue();
|
||||
@@ -123,11 +128,11 @@ public class MethodReference extends SpelNodeImpl {
|
||||
}
|
||||
}
|
||||
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()));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
@@ -25,8 +24,8 @@ import org.springframework.expression.TypedValue;
|
||||
*/
|
||||
public class NullLiteral extends Literal {
|
||||
|
||||
public NullLiteral(Token payload) {
|
||||
super(payload);
|
||||
public NullLiteral(int pos) {
|
||||
super(null,pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
@@ -27,15 +26,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OperatorEquality extends Operator {
|
||||
public class OpEQ extends Operator {
|
||||
|
||||
public OperatorEquality(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "==";
|
||||
public OpEQ(int pos, SpelNodeImpl... operands) {
|
||||
super("==", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
@@ -26,15 +25,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OperatorGreaterThanOrEqual extends Operator {
|
||||
public class OpGE extends Operator {
|
||||
|
||||
public OperatorGreaterThanOrEqual(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return ">=";
|
||||
public OpGE(int pos, SpelNodeImpl... operands) {
|
||||
super(">=", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
@@ -27,15 +26,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OperatorGreaterThan extends Operator {
|
||||
public class OpGT extends Operator {
|
||||
|
||||
public OperatorGreaterThan(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return ">";
|
||||
public OpGT(int pos, SpelNodeImpl... operands) {
|
||||
super(">", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
@@ -27,10 +26,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OperatorLessThanOrEqual extends Operator {
|
||||
public class OpLE extends Operator {
|
||||
|
||||
public OperatorLessThanOrEqual(Token payload) {
|
||||
super(payload);
|
||||
public OpLE(int pos, SpelNodeImpl... operands) {
|
||||
super("<=", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,9 +50,4 @@ public class OperatorLessThanOrEqual extends Operator {
|
||||
return BooleanTypedValue.forValue( state.getTypeComparator().compare(left, right) <= 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "<=";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
@@ -27,17 +26,12 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OperatorLessThan extends Operator {
|
||||
public class OpLT extends Operator {
|
||||
|
||||
public OperatorLessThan(Token payload) {
|
||||
super(payload);
|
||||
public OpLT(int pos, SpelNodeImpl... operands) {
|
||||
super("<", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "<";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
@@ -27,15 +26,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OperatorInequality extends Operator {
|
||||
public class OpNE extends Operator {
|
||||
|
||||
public OperatorInequality(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "!=";
|
||||
public OpNE(int pos, SpelNodeImpl... operands) {
|
||||
super("!=", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
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
|
||||
@@ -27,19 +26,24 @@ import org.antlr.runtime.Token;
|
||||
*/
|
||||
public abstract class Operator extends SpelNodeImpl {
|
||||
|
||||
public Operator(Token payload) {
|
||||
super(payload);
|
||||
String operatorName;
|
||||
|
||||
public Operator(String payload,int pos,SpelNodeImpl... operands) {
|
||||
super(pos, operands);
|
||||
this.operatorName = payload;
|
||||
}
|
||||
|
||||
public SpelNodeImpl getLeftOperand() {
|
||||
return getChild(0);
|
||||
return children[0];
|
||||
}
|
||||
|
||||
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] ')'
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
|
||||
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.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
@@ -31,13 +30,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
*/
|
||||
public class OperatorAnd extends Operator {
|
||||
|
||||
public OperatorAnd(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "and";
|
||||
public OperatorAnd(int pos, SpelNodeImpl... operands) {
|
||||
super("and", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,8 +42,8 @@ public class OperatorAnd extends Operator {
|
||||
try {
|
||||
leftValue = (Boolean)state.convertValue(getLeftOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
||||
}
|
||||
catch (SpelException ee) {
|
||||
ee.setPosition(getLeftOperand().getCharPositionInLine());
|
||||
catch (SpelEvaluationException ee) {
|
||||
ee.setPosition(getLeftOperand().getStartPosition());
|
||||
throw ee;
|
||||
}
|
||||
|
||||
@@ -60,8 +54,8 @@ public class OperatorAnd extends Operator {
|
||||
try {
|
||||
rightValue = (Boolean)state.convertValue(getRightOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
||||
}
|
||||
catch (SpelException ee) {
|
||||
ee.setPosition(getRightOperand().getCharPositionInLine());
|
||||
catch (SpelEvaluationException ee) {
|
||||
ee.setPosition(getRightOperand().getStartPosition());
|
||||
throw ee;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,10 @@ package org.springframework.expression.spel.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.TypeComparator;
|
||||
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.support.BooleanTypedValue;
|
||||
|
||||
@@ -36,13 +35,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
*/
|
||||
public class OperatorBetween extends Operator {
|
||||
|
||||
public OperatorBetween(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "between";
|
||||
public OperatorBetween(int pos, SpelNodeImpl... operands) {
|
||||
super("between", pos, operands);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +51,7 @@ public class OperatorBetween extends Operator {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
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);
|
||||
}
|
||||
List<?> l = (List<?>) right;
|
||||
@@ -66,8 +60,8 @@ public class OperatorBetween extends Operator {
|
||||
TypeComparator comparator = state.getTypeComparator();
|
||||
try {
|
||||
return BooleanTypedValue.forValue((comparator.compare(left, low) >= 0 && comparator.compare(left, high) <= 0));
|
||||
} catch (SpelException ex) {
|
||||
ex.setPosition(getCharPositionInLine());
|
||||
} catch (SpelEvaluationException ex) {
|
||||
ex.setPosition(getStartPosition());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Operation;
|
||||
@@ -31,13 +30,8 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
public class OperatorDivide extends Operator {
|
||||
|
||||
public OperatorDivide(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "/";
|
||||
public OperatorDivide(int pos, SpelNodeImpl... operands) {
|
||||
super("/", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
|
||||
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.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.support.BooleanTypedValue;
|
||||
|
||||
@@ -33,13 +32,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
*/
|
||||
public class OperatorInstanceof extends Operator {
|
||||
|
||||
public OperatorInstanceof(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "instanceof";
|
||||
public OperatorInstanceof(int pos, SpelNodeImpl... operands) {
|
||||
super("instanceof", pos, operands);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,7 +53,7 @@ public class OperatorInstanceof extends Operator {
|
||||
return BooleanTypedValue.False; // null is not an instanceof anything
|
||||
}
|
||||
if (rightValue == null || !(rightValue instanceof Class<?>)) {
|
||||
throw new SpelException(getRightOperand().getCharPositionInLine(),
|
||||
throw new SpelEvaluationException(getRightOperand().getStartPosition(),
|
||||
SpelMessages.INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND,
|
||||
(rightValue == null ? "null" : rightValue.getClass().getName()));
|
||||
}
|
||||
|
||||
@@ -20,10 +20,9 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
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.support.BooleanTypedValue;
|
||||
|
||||
@@ -36,13 +35,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
*/
|
||||
public class OperatorMatches extends Operator {
|
||||
|
||||
public OperatorMatches(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "matches";
|
||||
public OperatorMatches(int pos, SpelNodeImpl... operands) {
|
||||
super("matches", pos, operands);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,11 +53,11 @@ public class OperatorMatches extends Operator {
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
try {
|
||||
if (!(left instanceof String)) {
|
||||
throw new SpelException(leftOp.getCharPositionInLine(),
|
||||
throw new SpelEvaluationException(leftOp.getStartPosition(),
|
||||
SpelMessages.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, left);
|
||||
}
|
||||
if (!(right instanceof String)) {
|
||||
throw new SpelException(rightOp.getCharPositionInLine(),
|
||||
throw new SpelEvaluationException(rightOp.getStartPosition(),
|
||||
SpelMessages.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, right);
|
||||
}
|
||||
Pattern pattern = Pattern.compile((String) right);
|
||||
@@ -71,7 +65,7 @@ public class OperatorMatches extends Operator {
|
||||
return BooleanTypedValue.forValue(matcher.matches());
|
||||
}
|
||||
catch (PatternSyntaxException pse) {
|
||||
throw new SpelException(rightOp.getCharPositionInLine(), pse, SpelMessages.INVALID_PATTERN, right);
|
||||
throw new SpelEvaluationException(rightOp.getStartPosition(), pse, SpelMessages.INVALID_PATTERN, right);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Operation;
|
||||
import org.springframework.expression.TypedValue;
|
||||
@@ -39,8 +38,8 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
public class OperatorMinus extends Operator {
|
||||
|
||||
public OperatorMinus(Token payload) {
|
||||
super(payload);
|
||||
public OperatorMinus(int pos, SpelNodeImpl... operands) {
|
||||
super("-", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,11 +82,6 @@ public class OperatorMinus extends Operator {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "-";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
if (getRightOperand() == null) { // unary minus
|
||||
@@ -95,5 +89,9 @@ public class OperatorMinus extends Operator {
|
||||
}
|
||||
return super.toStringAST();
|
||||
}
|
||||
public SpelNodeImpl getRightOperand() {
|
||||
if (children.length<2) {return null;}
|
||||
return children[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Operation;
|
||||
import org.springframework.expression.TypedValue;
|
||||
@@ -30,13 +29,8 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
public class OperatorModulus extends Operator {
|
||||
|
||||
public OperatorModulus(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "%";
|
||||
public OperatorModulus(int pos, SpelNodeImpl... operands) {
|
||||
super("%", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Operation;
|
||||
import org.springframework.expression.TypedValue;
|
||||
@@ -39,8 +38,9 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "*";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -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 OperatorNot(Token payload) {
|
||||
super(payload);
|
||||
public OperatorNot(int pos, SpelNodeImpl operand) {
|
||||
super(pos, operand);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
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);
|
||||
}
|
||||
catch (SpelException see) {
|
||||
see.setPosition(getChild(0).getCharPositionInLine());
|
||||
catch (SpelEvaluationException see) {
|
||||
see.setPosition(getChild(0).getStartPosition());
|
||||
throw see;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -30,13 +29,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
*/
|
||||
public class OperatorOr extends Operator {
|
||||
|
||||
public OperatorOr(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "or";
|
||||
public OperatorOr(int pos, SpelNodeImpl... operands) {
|
||||
super("or", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,8 +40,8 @@ public class OperatorOr extends Operator {
|
||||
try {
|
||||
leftValue = (Boolean)state.convertValue(getLeftOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
||||
}
|
||||
catch (SpelException see) {
|
||||
see.setPosition(getLeftOperand().getCharPositionInLine());
|
||||
catch (SpelEvaluationException see) {
|
||||
see.setPosition(getLeftOperand().getStartPosition());
|
||||
throw see;
|
||||
}
|
||||
|
||||
@@ -58,8 +52,8 @@ public class OperatorOr extends Operator {
|
||||
try {
|
||||
rightValue = (Boolean)state.convertValue(getRightOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
||||
}
|
||||
catch (SpelException see) {
|
||||
see.setPosition(getRightOperand().getCharPositionInLine());
|
||||
catch (SpelEvaluationException see) {
|
||||
see.setPosition(getRightOperand().getStartPosition()); // TODO end positions here and in similar situations
|
||||
throw see;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Operation;
|
||||
import org.springframework.expression.TypedValue;
|
||||
@@ -38,8 +37,8 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
public class OperatorPlus extends Operator {
|
||||
|
||||
public OperatorPlus(Token payload) {
|
||||
super(payload);
|
||||
public OperatorPlus(int pos, SpelNodeImpl... operands) {
|
||||
super("+", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,17 +78,18 @@ public class OperatorPlus extends Operator {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "+";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
if (getRightOperand() == null) { // unary plus
|
||||
if (children.length<2) { // unary plus
|
||||
return new StringBuilder().append("+").append(getLeftOperand().toStringAST()).toString();
|
||||
}
|
||||
return super.toStringAST();
|
||||
}
|
||||
|
||||
public SpelNodeImpl getRightOperand() {
|
||||
if (children.length<2) {return null;}
|
||||
return children[1];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Operation;
|
||||
import org.springframework.expression.TypedValue;
|
||||
@@ -30,8 +29,8 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
public class OperatorPower extends Operator {
|
||||
|
||||
public OperatorPower(Token payload) {
|
||||
super(payload);
|
||||
public OperatorPower(int pos, SpelNodeImpl... operands) {
|
||||
super("^", pos, operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,9 +60,4 @@ public class OperatorPower extends Operator {
|
||||
return state.operate(Operation.POWER, operandOne, operandTwo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "^";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,12 +21,11 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
/**
|
||||
@@ -39,10 +38,14 @@ import org.springframework.expression.spel.SpelMessages;
|
||||
*/
|
||||
public class Projection extends SpelNodeImpl {
|
||||
|
||||
public Projection(Token payload) {
|
||||
super(payload);
|
||||
private final boolean nullSafe;
|
||||
|
||||
public Projection(boolean nullSafe, int pos,SpelNodeImpl expression) {
|
||||
super(pos,expression);
|
||||
this.nullSafe = nullSafe;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue op = state.getActiveContextObject();
|
||||
@@ -61,7 +64,7 @@ public class Projection extends SpelNodeImpl {
|
||||
for (Map.Entry entry : mapdata.entrySet()) {
|
||||
try {
|
||||
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 {
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
@@ -76,7 +79,7 @@ public class Projection extends SpelNodeImpl {
|
||||
try {
|
||||
state.pushActiveContextObject(new TypedValue(element,TypeDescriptor.valueOf(op.getTypeDescriptor().getType())));
|
||||
state.enterScope("index", idx);
|
||||
result.add(getChild(0).getValueInternal(state).getValue());
|
||||
result.add(children[0].getValueInternal(state).getValue());
|
||||
} finally {
|
||||
state.exitScope();
|
||||
state.popActiveContextObject();
|
||||
@@ -85,7 +88,11 @@ public class Projection extends SpelNodeImpl {
|
||||
}
|
||||
return new TypedValue(result,op.getTypeDescriptor());
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,5 +101,5 @@ public class Projection extends SpelNodeImpl {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
return sb.append("![").append(getChild(0).toStringAST()).append("]").toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -19,13 +19,12 @@ package org.springframework.expression.spel.ast;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
/**
|
||||
@@ -43,24 +42,26 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
||||
|
||||
private volatile PropertyAccessor cachedWriteAccessor;
|
||||
|
||||
public PropertyOrFieldReference(Token payload) {
|
||||
super(payload);
|
||||
this.name = payload.getText();
|
||||
private final boolean nullSafe;
|
||||
|
||||
public PropertyOrFieldReference(boolean nullSafe, String propertyOrFieldName, int pos) {
|
||||
super(pos);
|
||||
name = propertyOrFieldName;
|
||||
this.nullSafe = nullSafe;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelEvaluationException {
|
||||
return readProperty(state, this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(ExpressionState state, Object newValue) throws SpelException {
|
||||
public void setValue(ExpressionState state, Object newValue) throws SpelEvaluationException {
|
||||
writeProperty(state, this.name, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState state) throws SpelException {
|
||||
public boolean isWritable(ExpressionState state) throws SpelEvaluationException {
|
||||
return isWritableProperty(this.name, state);
|
||||
}
|
||||
|
||||
@@ -74,12 +75,16 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
||||
* @param state the evaluation state
|
||||
* @param name the name 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();
|
||||
EvaluationContext eContext = state.getEvaluationContext();
|
||||
|
||||
if (contextObject.getValue() == null && nullSafe) {
|
||||
return TypedValue.NULL_TYPED_VALUE;
|
||||
}
|
||||
|
||||
PropertyAccessor accessorToUse = this.cachedReadAccessor;
|
||||
if (accessorToUse != null) {
|
||||
try {
|
||||
@@ -108,20 +113,24 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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 {
|
||||
throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE, name,
|
||||
throw new SpelEvaluationException(getStartPosition(),SpelMessages.PROPERTY_OR_FIELD_NOT_READABLE, name,
|
||||
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();
|
||||
EvaluationContext eContext = state.getEvaluationContext();
|
||||
|
||||
if (contextObject.getValue() == null && nullSafe) {
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyAccessor accessorToUse = this.cachedWriteAccessor;
|
||||
if (accessorToUse != null) {
|
||||
@@ -149,19 +158,19 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
||||
}
|
||||
}
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWritableProperty(String name, ExpressionState state) throws SpelException {
|
||||
public boolean isWritableProperty(String name, ExpressionState state) throws SpelEvaluationException {
|
||||
Object contextObject = state.getActiveContextObject().getValue();
|
||||
EvaluationContext eContext = state.getEvaluationContext();
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
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.spel.ExpressionState;
|
||||
@@ -31,11 +30,11 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
public class QualifiedIdentifier extends SpelNodeImpl {
|
||||
|
||||
// TODO safe to cache? dont think so
|
||||
private TypedValue value;
|
||||
|
||||
public QualifiedIdentifier(Token payload) {
|
||||
super(payload);
|
||||
// value = payload.getText();
|
||||
public QualifiedIdentifier(int pos,SpelNodeImpl... operands) {
|
||||
super(pos,operands);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,7 +46,7 @@ public class QualifiedIdentifier extends SpelNodeImpl {
|
||||
if (i > 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
@@ -27,9 +26,9 @@ public class RealLiteral extends Literal {
|
||||
|
||||
private final TypedValue value;
|
||||
|
||||
public RealLiteral(Token payload) {
|
||||
super(payload);
|
||||
value = new TypedValue(Double.parseDouble(payload.getText()),DOUBLE_TYPE_DESCRIPTOR);
|
||||
public RealLiteral(String payload, int pos, double value) {
|
||||
super(payload, pos);
|
||||
this.value = new TypedValue(value,DOUBLE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,12 +22,11 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
/**
|
||||
@@ -46,18 +45,21 @@ public class Selection extends SpelNodeImpl {
|
||||
public final static int LAST = 2; // $[]
|
||||
|
||||
private final int variant;
|
||||
private final boolean nullSafe;
|
||||
|
||||
public Selection(Token payload, int variant) {
|
||||
super(payload);
|
||||
public Selection(boolean nullSafe, int variant,int pos,SpelNodeImpl expression) {
|
||||
super(pos,expression);
|
||||
this.nullSafe = nullSafe;
|
||||
this.variant = variant;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue op = state.getActiveContextObject();
|
||||
Object operand = op.getValue();
|
||||
|
||||
SpelNodeImpl selectionCriteria = getChild(0);
|
||||
SpelNodeImpl selectionCriteria = children[0];
|
||||
if (operand instanceof Map) {
|
||||
Map<?, ?> mapdata = (Map<?, ?>) operand;
|
||||
// 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());
|
||||
}
|
||||
} else {
|
||||
throw new SpelException(selectionCriteria.getCharPositionInLine(),
|
||||
throw new SpelEvaluationException(selectionCriteria.getStartPosition(),
|
||||
SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST());
|
||||
}
|
||||
} finally {
|
||||
@@ -113,7 +115,7 @@ public class Selection extends SpelNodeImpl {
|
||||
result.add(element);
|
||||
}
|
||||
} else {
|
||||
throw new SpelException(selectionCriteria.getCharPositionInLine(),
|
||||
throw new SpelEvaluationException(selectionCriteria.getStartPosition(),
|
||||
SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST());
|
||||
}
|
||||
idx++;
|
||||
@@ -130,8 +132,12 @@ public class Selection extends SpelNodeImpl {
|
||||
}
|
||||
return new TypedValue(result,op.getTypeDescriptor());
|
||||
} else {
|
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.INVALID_TYPE_FOR_SELECTION,
|
||||
(operand == null ? "null" : operand.getClass().getName()));
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,18 +16,13 @@
|
||||
|
||||
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.TypedValue;
|
||||
import org.springframework.expression.common.ExpressionUtils;
|
||||
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.SpelNode;
|
||||
import org.springframework.expression.spel.generated.SpringExpressionsParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
@@ -36,14 +31,22 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Serializable, CommonTypeDescriptors {
|
||||
public abstract class SpelNodeImpl implements SpelNode, CommonTypeDescriptors {
|
||||
|
||||
/**
|
||||
* The Antlr parser uses this constructor to build SpelNodes.
|
||||
* @param payload the token for the node that has been parsed
|
||||
*/
|
||||
protected SpelNodeImpl(Token payload) {
|
||||
super(payload);
|
||||
private static SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0];
|
||||
|
||||
protected int pos; // start = top 16bits, end = bottom 16bits
|
||||
protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
|
||||
|
||||
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 {
|
||||
@@ -60,20 +63,15 @@ public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Seria
|
||||
}
|
||||
|
||||
public void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException {
|
||||
throw new SpelException(
|
||||
getCharPositionInLine(), SpelMessages.SETVALUE_NOT_SUPPORTED, getClass(), getTokenName());
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessages.SETVALUE_NOT_SUPPORTED, getClass());
|
||||
}
|
||||
|
||||
protected String getTokenName() {
|
||||
if (getToken() == null) {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
return SpringExpressionsParser.tokenNames[getToken().getType()];
|
||||
public SpelNode getChild(int index) {
|
||||
return children[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpelNodeImpl getChild(int index) {
|
||||
return (SpelNodeImpl) super.getChild(index);
|
||||
|
||||
public int getChildCount() {
|
||||
return children.length;
|
||||
}
|
||||
|
||||
public Class<?> getObjectClass(Object obj) {
|
||||
@@ -97,13 +95,16 @@ public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Seria
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
public int getStartPosition() {
|
||||
return getCharPositionInLine();
|
||||
}
|
||||
|
||||
|
||||
public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException;
|
||||
|
||||
public abstract String toStringAST();
|
||||
|
||||
public int getStartPosition() {
|
||||
return (pos>>16);
|
||||
}
|
||||
|
||||
public int getEndPosition() {
|
||||
return (pos&0xffff);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
@@ -28,12 +27,11 @@ public class StringLiteral extends Literal {
|
||||
|
||||
private final TypedValue value;
|
||||
|
||||
public StringLiteral(Token payload) {
|
||||
super(payload);
|
||||
String val = payload.getText();
|
||||
public StringLiteral(String payload, int pos, String value) {
|
||||
super(payload,pos);
|
||||
// TODO should these have been skipped being created by the parser rules? or not?
|
||||
val = val.substring(1, val.length() - 1);
|
||||
this.value = new TypedValue(val.replaceAll("''", "'"),STRING_TYPE_DESCRIPTOR);
|
||||
value = value.substring(1, value.length() - 1);
|
||||
this.value = new TypedValue(value.replaceAll("''", "'"),STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
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.spel.ExpressionState;
|
||||
@@ -30,8 +29,9 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
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
|
||||
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()) {
|
||||
return getChild(1).getValueInternal(state);
|
||||
return children[1].getValueInternal(state);
|
||||
} else {
|
||||
return getChild(2).getValueInternal(state);
|
||||
return children[2].getValueInternal(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
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.spel.ExpressionState;
|
||||
@@ -28,14 +27,14 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
public class TypeReference extends SpelNodeImpl {
|
||||
|
||||
public TypeReference(Token payload) {
|
||||
super(payload);
|
||||
public TypeReference(int pos,SpelNodeImpl qualifiedId) {
|
||||
super(pos,qualifiedId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
// 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))) {
|
||||
TypeCode tc = TypeCode.valueOf(typename.toUpperCase());
|
||||
if (tc != TypeCode.OBJECT) {
|
||||
@@ -54,5 +53,5 @@ public class TypeReference extends SpelNodeImpl {
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
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
|
||||
@@ -36,14 +35,14 @@ public class VariableReference extends SpelNodeImpl {
|
||||
private final String name;
|
||||
|
||||
|
||||
public VariableReference(Token payload) {
|
||||
super(payload);
|
||||
this.name = payload.getText();
|
||||
public VariableReference(String variableName, int pos) {
|
||||
super(pos);
|
||||
name = variableName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelEvaluationException {
|
||||
if (this.name.equals(THIS)) {
|
||||
return state.getActiveContextObject();
|
||||
}
|
||||
@@ -56,7 +55,7 @@ public class VariableReference extends SpelNodeImpl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(ExpressionState state, Object value) throws SpelException {
|
||||
public void setValue(ExpressionState state, Object value) throws SpelEvaluationException {
|
||||
state.setVariable(this.name, value);
|
||||
}
|
||||
|
||||
@@ -66,7 +65,7 @@ public class VariableReference extends SpelNodeImpl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelEvaluationException {
|
||||
return !(this.name.equals(THIS) || this.name.equals(ROOT));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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';
|
||||
@@ -13,32 +13,25 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.expression.spel.standard;
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelParseException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @since 3.0
|
||||
*/
|
||||
public class EmptySpelNode extends SpelNodeImpl {
|
||||
public class InternalParseException extends RuntimeException {
|
||||
|
||||
public EmptySpelNode(Token payload) {
|
||||
super(payload);
|
||||
public InternalParseException(SpelParseException t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
throw new RuntimeException("?");
|
||||
|
||||
public SpelParseException getCause() {
|
||||
return (SpelParseException)super.getCause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
return "<no string form node '" + getTokenName() + "'>";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
package org.springframework.expression.spel.support;
|
||||
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ast.SpelNodeImpl;
|
||||
import org.springframework.expression.spel.ast.CommonTypeDescriptors;
|
||||
|
||||
/**
|
||||
* @author Andy Clement
|
||||
@@ -28,7 +28,7 @@ public class BooleanTypedValue extends TypedValue {
|
||||
public static final BooleanTypedValue False = new BooleanTypedValue(false);
|
||||
|
||||
private BooleanTypedValue(boolean b) {
|
||||
super(b,SpelNodeImpl.BOOLEAN_TYPE_DESCRIPTOR);
|
||||
super(b,CommonTypeDescriptors.BOOLEAN_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
public static BooleanTypedValue forValue(boolean b) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.expression.EvaluationException;
|
||||
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.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -112,7 +112,7 @@ public class ReflectionHelper {
|
||||
int argCountUpToVarargs = expectedArgTypes.length-1;
|
||||
for (int i = 0; i < argCountUpToVarargs && match != null; i++) {
|
||||
Class suppliedArg = suppliedArgTypes[i];
|
||||
Class expectedArg = expectedArgTypes[i];
|
||||
Class<?> expectedArg = expectedArgTypes[i];
|
||||
if (expectedArg != suppliedArg) {
|
||||
if (expectedArg.isAssignableFrom(suppliedArg) || ClassUtils.isAssignableValue(expectedArg, suppliedArg)) {
|
||||
if (match != ArgsMatchKind.REQUIRES_CONVERSION) {
|
||||
@@ -226,10 +226,10 @@ public class ReflectionHelper {
|
||||
* @param isVarargs whether parameterTypes relates to a varargs method
|
||||
* @param converter the converter to use for type conversions
|
||||
* @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,
|
||||
Object[] arguments) throws SpelException {
|
||||
Object[] arguments) throws SpelEvaluationException {
|
||||
|
||||
Assert.notNull(arguments,"should not be called if nothing to convert");
|
||||
|
||||
@@ -248,16 +248,16 @@ public class ReflectionHelper {
|
||||
try {
|
||||
if (arguments[i] != null && arguments[i].getClass() != targetType) {
|
||||
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);
|
||||
}
|
||||
} catch (EvaluationException ex) {
|
||||
// allows for another type converter throwing a different kind of EvaluationException
|
||||
if (ex instanceof SpelException) {
|
||||
throw (SpelException)ex;
|
||||
if (ex instanceof SpelEvaluationException) {
|
||||
throw (SpelEvaluationException)ex;
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.MethodExecutor;
|
||||
import org.springframework.expression.MethodResolver;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
/**
|
||||
@@ -88,7 +88,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||
}
|
||||
else if (matchRequiringConversion != null) {
|
||||
if (multipleOptions) {
|
||||
throw new SpelException(SpelMessages.MULTIPLE_POSSIBLE_METHODS, name);
|
||||
throw new SpelEvaluationException(SpelMessages.MULTIPLE_POSSIBLE_METHODS, name);
|
||||
}
|
||||
return new ReflectiveMethodExecutor(matchRequiringConversion, argsToConvert);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.springframework.expression.spel.support;
|
||||
|
||||
import org.springframework.expression.TypeComparator;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
/**
|
||||
@@ -30,7 +30,7 @@ import org.springframework.expression.spel.SpelMessages;
|
||||
public class StandardTypeComparator implements TypeComparator {
|
||||
|
||||
@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 (left == null) {
|
||||
return right == null ? 0 : 1;
|
||||
@@ -65,7 +65,7 @@ public class StandardTypeComparator implements TypeComparator {
|
||||
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) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultTypeConverter;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
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.util.Assert;
|
||||
|
||||
@@ -55,10 +55,10 @@ public class StandardTypeConverter implements TypeConverter {
|
||||
return this.typeConverter.convert(value, typeDescriptor);
|
||||
}
|
||||
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) {
|
||||
throw new SpelException(ce, SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString());
|
||||
throw new SpelEvaluationException(ce, SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.expression.EvaluationException;
|
||||
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.util.ClassUtils;
|
||||
|
||||
@@ -76,7 +76,7 @@ public class StandardTypeLocator implements TypeLocator {
|
||||
// might be a different prefix
|
||||
}
|
||||
}
|
||||
throw new SpelException(SpelMessages.TYPE_NOT_FOUND, typename);
|
||||
throw new SpelEvaluationException(SpelMessages.TYPE_NOT_FOUND, typename);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user