Removed unnecessary code. Increased test coverage from 70>75% - still some way to go
This commit is contained in:
@@ -57,5 +57,11 @@ public class TypedValue {
|
||||
public TypeDescriptor getTypeDescriptor() {
|
||||
return this.typeDescriptor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer str = new StringBuffer();
|
||||
str.append("TypedValue: ").append(value).append(" of type "+typeDescriptor.asString());
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ 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;
|
||||
|
||||
/**
|
||||
* Represents assignment. An alternative to calling setValue() for an expression is to use an assign.
|
||||
@@ -49,9 +48,4 @@ public class Assign extends SpelNodeImpl {
|
||||
.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,11 +16,9 @@
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.List;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.ConstructorExecutor;
|
||||
import org.springframework.expression.ConstructorResolver;
|
||||
@@ -31,6 +29,7 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
// TODO asc array constructor call logic has been removed for now
|
||||
/**
|
||||
* 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.
|
||||
@@ -46,201 +45,22 @@ import org.springframework.expression.spel.SpelMessages;
|
||||
*/
|
||||
public class ConstructorReference extends SpelNodeImpl {
|
||||
|
||||
/**
|
||||
* If true then this is an array constructor, for example, 'new String[]', rather than a simple constructor 'new
|
||||
* String()'
|
||||
*/
|
||||
private final boolean isArrayConstructor;
|
||||
|
||||
// TODO is this caching safe - passing the expression around will mean this executor is also being passed around
|
||||
/**
|
||||
* The cached executor that may be reused on subsequent evaluations.
|
||||
*/
|
||||
private ConstructorExecutor cachedExecutor;
|
||||
|
||||
|
||||
public ConstructorReference(Token payload, boolean isArrayConstructor) {
|
||||
public ConstructorReference(Token payload) {
|
||||
super(payload);
|
||||
this.isArrayConstructor = isArrayConstructor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements getValue() - delegating to the code for building an array or a simple type.
|
||||
*/
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
if (this.isArrayConstructor) {
|
||||
return createArray(state);
|
||||
}
|
||||
else {
|
||||
return createNewInstance(state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("new ");
|
||||
|
||||
int index = 0;
|
||||
sb.append(getChild(index++).toStringAST());
|
||||
|
||||
if (!this.isArrayConstructor) {
|
||||
sb.append("(");
|
||||
for (int i = index; i < getChildCount(); i++) {
|
||||
if (i > index)
|
||||
sb.append(",");
|
||||
sb.append(getChild(i).toStringAST());
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
else {
|
||||
// Next child is EXPRESSIONLIST token with children that are the
|
||||
// expressions giving array size
|
||||
sb.append("[");
|
||||
SpelNodeImpl arrayRank = getChild(index++);
|
||||
for (int i = 0; i < arrayRank.getChildCount(); i++) {
|
||||
if (i > 0)
|
||||
sb.append(",");
|
||||
sb.append(arrayRank.getChild(i).toStringAST());
|
||||
}
|
||||
sb.append("]");
|
||||
if (index < getChildCount())
|
||||
sb.append(" ").append(getChild(index).toStringAST());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create an array and return it. The children of this node indicate the type of array, the array ranks and any
|
||||
* optional initializer that might have been supplied.
|
||||
* @param state the expression state within which this expression is being evaluated
|
||||
* @return the new array
|
||||
* @throws EvaluationException if there is a problem creating the array
|
||||
*/
|
||||
private TypedValue createArray(ExpressionState state) throws EvaluationException {
|
||||
TypedValue intendedArrayType = getChild(0).getValueInternal(state);
|
||||
if (!(intendedArrayType.getValue() instanceof String)) {
|
||||
throw new SpelException(getChild(0).getCharPositionInLine(),
|
||||
SpelMessages.TYPE_NAME_EXPECTED_FOR_ARRAY_CONSTRUCTION,
|
||||
FormatHelper.formatClassNameForMessage(intendedArrayType.getClass()));
|
||||
}
|
||||
String type = (String) intendedArrayType.getValue();
|
||||
Class<?> componentType = null;
|
||||
TypeCode arrayTypeCode = TypeCode.forName(type);
|
||||
if (arrayTypeCode == TypeCode.OBJECT) {
|
||||
componentType = state.findType(type);
|
||||
} else {
|
||||
componentType = arrayTypeCode.getType();
|
||||
}
|
||||
|
||||
Object newArray = null;
|
||||
TypeDescriptor newArrayTypeDescriptor = null;
|
||||
|
||||
if (getChild(1).getChildCount() == 0) { // are the array ranks defined?
|
||||
if (getChildCount() < 3) {
|
||||
throw new SpelException(getCharPositionInLine(),
|
||||
SpelMessages.NO_SIZE_OR_INITIALIZER_FOR_ARRAY_CONSTRUCTION);
|
||||
}
|
||||
// no array ranks so use the size of the initializer to determine array size
|
||||
int arraySize = getChild(2).getChildCount();
|
||||
newArray = Array.newInstance(componentType, arraySize);
|
||||
newArrayTypeDescriptor = TypeDescriptor.valueOf(newArray.getClass());
|
||||
}
|
||||
else {
|
||||
// Array ranks are specified but is it a single or multiple dimension array?
|
||||
int dimensions = getChild(1).getChildCount();
|
||||
if (dimensions == 1) {
|
||||
Object o = getChild(1).getValueInternal(state);
|
||||
int arraySize = state.convertValue(o, INTEGER_TYPE_DESCRIPTOR);
|
||||
if (getChildCount() == 3) {
|
||||
// Check initializer length matches array size length
|
||||
int initializerLength = getChild(2).getChildCount();
|
||||
if (initializerLength != arraySize) {
|
||||
throw new SpelException(getChild(2).getCharPositionInLine(),
|
||||
SpelMessages.INITIALIZER_LENGTH_INCORRECT, initializerLength, arraySize);
|
||||
}
|
||||
}
|
||||
newArray = Array.newInstance(componentType, arraySize);
|
||||
newArrayTypeDescriptor = TypeDescriptor.valueOf(newArray.getClass());
|
||||
}
|
||||
else {
|
||||
// Multi-dimensional - hold onto your hat !
|
||||
int[] dims = new int[dimensions];
|
||||
for (int d = 0; d < dimensions; d++) {
|
||||
dims[d] = state.convertValue(getChild(1).getChild(d).getValueInternal(state), INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
newArray = Array.newInstance(componentType, dims);
|
||||
newArrayTypeDescriptor = TypeDescriptor.valueOf(newArray.getClass());
|
||||
// TODO check any specified initializer for the multidim array matches
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the array using the initializer if one is specified
|
||||
if (getChildCount() == 3) {
|
||||
SpelNodeImpl initializer = getChild(2);
|
||||
if (arrayTypeCode == TypeCode.OBJECT) {
|
||||
Object[] newObjectArray = (Object[]) newArray;
|
||||
for (int i = 0; i < newObjectArray.length; i++) {
|
||||
SpelNodeImpl elementNode = initializer.getChild(i);
|
||||
Object arrayEntry = elementNode.getValueInternal(state);
|
||||
if (!componentType.isAssignableFrom(arrayEntry.getClass())) {
|
||||
throw new SpelException(elementNode.getCharPositionInLine(),
|
||||
SpelMessages.INCORRECT_ELEMENT_TYPE_FOR_ARRAY, componentType.getName(), arrayEntry
|
||||
.getClass().getName());
|
||||
}
|
||||
newObjectArray[i] = arrayEntry;
|
||||
}
|
||||
} else if (arrayTypeCode == TypeCode.INT) {
|
||||
int[] newIntArray = (int[]) newArray;
|
||||
for (int i = 0; i < newIntArray.length; i++) {
|
||||
newIntArray[i] = state.convertValue(initializer.getChild(i).getValueInternal(state), INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
} else if (arrayTypeCode == TypeCode.BOOLEAN) {
|
||||
boolean[] newBooleanArray = (boolean[]) newArray;
|
||||
for (int i = 0; i < newBooleanArray.length; i++) {
|
||||
newBooleanArray[i] = state.convertValue(initializer.getChild(i).getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
||||
}
|
||||
} else if (arrayTypeCode == TypeCode.CHAR) {
|
||||
char[] newCharArray = (char[]) newArray;
|
||||
for (int i = 0; i < newCharArray.length; i++) {
|
||||
newCharArray[i] = state.convertValue(initializer.getChild(i).getValueInternal(state), CHARACTER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
} else if (arrayTypeCode == TypeCode.SHORT) {
|
||||
short[] newShortArray = (short[]) newArray;
|
||||
for (int i = 0; i < newShortArray.length; i++) {
|
||||
newShortArray[i] = state.convertValue(initializer.getChild(i).getValueInternal(state), SHORT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
} else if (arrayTypeCode == TypeCode.LONG) {
|
||||
long[] newLongArray = (long[]) newArray;
|
||||
for (int i = 0; i < newLongArray.length; i++) {
|
||||
newLongArray[i] = state.convertValue(initializer.getChild(i).getValueInternal(state), LONG_TYPE_DESCRIPTOR);
|
||||
}
|
||||
} else if (arrayTypeCode == TypeCode.FLOAT) {
|
||||
float[] newFloatArray = (float[]) newArray;
|
||||
for (int i = 0; i < newFloatArray.length; i++) {
|
||||
newFloatArray[i] = state.convertValue(initializer.getChild(i).getValueInternal(state), FLOAT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
} else if (arrayTypeCode == TypeCode.DOUBLE) {
|
||||
double[] newDoubleArray = (double[]) newArray;
|
||||
for (int i = 0; i < newDoubleArray.length; i++) {
|
||||
newDoubleArray[i] = state.convertValue(initializer.getChild(i).getValueInternal(state), DOUBLE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
} else if (arrayTypeCode == TypeCode.BYTE) {
|
||||
byte[] newByteArray = (byte[]) newArray;
|
||||
for (int i = 0; i < newByteArray.length; i++) {
|
||||
newByteArray[i] = state.convertValue(initializer.getChild(i).getValueInternal(state), BYTE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new TypedValue(newArray, newArrayTypeDescriptor);
|
||||
return createNewInstance(state);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,9 +94,10 @@ public class ConstructorReference extends SpelNodeImpl {
|
||||
String typename = (String) getChild(0).getValueInternal(state).getValue();
|
||||
executorToUse = findExecutorForConstructor(typename, argumentTypes, state);
|
||||
try {
|
||||
return executorToUse.execute(state.getEvaluationContext(), arguments);
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -314,4 +135,22 @@ public class ConstructorReference extends SpelNodeImpl {
|
||||
argumentTypes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("new ");
|
||||
|
||||
int index = 0;
|
||||
sb.append(getChild(index++).toStringAST());
|
||||
|
||||
sb.append("(");
|
||||
for (int i = index; i < getChildCount(); i++) {
|
||||
if (i > index)
|
||||
sb.append(",");
|
||||
sb.append(getChild(i).toStringAST());
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ package org.springframework.expression.spel.ast;
|
||||
*
|
||||
* @author Andy Clement
|
||||
*/
|
||||
class FormatHelper {
|
||||
public class FormatHelper {
|
||||
|
||||
/**
|
||||
* Produce a nice string for a given method name with specified arguments.
|
||||
@@ -33,13 +33,11 @@ class FormatHelper {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
sb.append("(");
|
||||
if (argumentTypes != null) {
|
||||
for (int i = 0; i < argumentTypes.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(argumentTypes[i].getName());
|
||||
for (int i = 0; i < argumentTypes.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(formatClassNameForMessage(argumentTypes[i]));
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
|
||||
@@ -128,10 +128,6 @@ public class FunctionReference extends SpelNodeImpl {
|
||||
}
|
||||
|
||||
// to 'assign' to a function don't use the () suffix and so it is just a variable reference
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws EvaluationException {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the arguments to the function, they are the children of this expression node.
|
||||
|
||||
@@ -52,11 +52,6 @@ public abstract class Literal extends SpelNodeImpl {
|
||||
return toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the string form of a number, using the specified base if supplied and return an appropriate literal to
|
||||
* hold it. Any suffix to indicate a long will be taken into account (either 'l' or 'L' is supported).
|
||||
@@ -71,9 +66,7 @@ public abstract class Literal extends SpelNodeImpl {
|
||||
boolean isLong = false;
|
||||
boolean isHex = (radix == 16);
|
||||
|
||||
if (numberString.length() > 0) {
|
||||
isLong = numberString.endsWith("L") || numberString.endsWith("l");
|
||||
}
|
||||
isLong = numberString.endsWith("L") || numberString.endsWith("l");
|
||||
|
||||
if (isLong || isHex) { // needs to be chopped up a little
|
||||
int len = numberString.length();
|
||||
|
||||
@@ -78,10 +78,9 @@ public class MethodReference extends SpelNodeImpl {
|
||||
try {
|
||||
return executorToUse.execute(
|
||||
state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments);
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
} catch (AccessException ae) {
|
||||
throw new SpelException(getCharPositionInLine(), ae, SpelMessages.EXCEPTION_DURING_METHOD_INVOCATION,
|
||||
this.name, state.getActiveContextObject().getClass().getName(), ae.getMessage());
|
||||
this.name, state.getActiveContextObject().getValue().getClass().getName(), ae.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,11 +129,6 @@ public class MethodReference extends SpelNodeImpl {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
protected MethodExecutor findAccessorForMethod(String name, Class<?>[] argumentTypes, ExpressionState state)
|
||||
throws SpelException {
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
* Common supertype for operators that operate on either one or two operands. In the case of multiply or divide there
|
||||
@@ -32,15 +30,7 @@ public abstract class Operator extends SpelNodeImpl {
|
||||
public Operator(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operator expressions can never be written to
|
||||
*/
|
||||
@Override
|
||||
public final boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public SpelNodeImpl getLeftOperand() {
|
||||
return getChild(0);
|
||||
}
|
||||
@@ -57,17 +47,13 @@ public abstract class Operator extends SpelNodeImpl {
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (getChildCount() > 0) {
|
||||
sb.append("(");
|
||||
}
|
||||
sb.append("(");
|
||||
sb.append(getChild(0).toStringAST());
|
||||
for (int i = 1; i < getChildCount(); i++) {
|
||||
sb.append(" ").append(getOperatorName()).append(" ");
|
||||
sb.append(getChild(i).toStringAST());
|
||||
}
|
||||
if (getChildCount() > 0) {
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,9 +53,4 @@ public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so do
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,11 +28,10 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
* <li>add doubles (floats are represented as doubles)
|
||||
* <li>add longs
|
||||
* <li>add integers
|
||||
* <li>add a string of one character and a number (effectively increasing that character), so 'a'+3='d'
|
||||
* <li>concatenate strings
|
||||
* </ul>
|
||||
* It can be used as a unary operator for numbers (double/long/int). The standard promotions are performed
|
||||
* when the operand types vary (double+int=double).
|
||||
* For other options it defers to the registered overloader.
|
||||
* when the operand types vary (double+int=double). For other options it defers to the registered overloader.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
@@ -75,16 +74,6 @@ public class OperatorPlus extends Operator {
|
||||
}
|
||||
} else if (operandOne instanceof String && operandTwo instanceof String) {
|
||||
return new TypedValue(new StringBuilder((String) operandOne).append((String) operandTwo).toString(),STRING_TYPE_DESCRIPTOR);
|
||||
} else if (operandOne instanceof String && operandTwo instanceof Integer && ((String)operandOne).length()==1) {
|
||||
String theString = (String) operandOne;
|
||||
Integer theInteger = (Integer) operandTwo;
|
||||
// implements character + int (ie. a + 1 = b)
|
||||
return new TypedValue(Character.toString((char) (theString.charAt(0) + theInteger)),STRING_TYPE_DESCRIPTOR);
|
||||
} else if (operandOne instanceof Integer && ((operandTwo instanceof String) && ((String)operandTwo).length()==1)) {
|
||||
String theString = (String) operandTwo;
|
||||
Integer theInteger = (Integer) operandOne;
|
||||
// implements character + int (ie. 1 + a = b)
|
||||
return new TypedValue(Character.toString((char) (theString.charAt(0) + theInteger)),STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
return state.operate(Operation.ADD, operandOne, operandTwo);
|
||||
}
|
||||
|
||||
@@ -1,48 +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.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
/**
|
||||
* PlaceHolder nodes are created for tokens that come through from the grammar purely to give us additional positional
|
||||
* information for messages/etc.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class Placeholder extends SpelNodeImpl {
|
||||
|
||||
public Placeholder(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.PLACEHOLDER_SHOULD_NEVER_BE_EVALUATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,7 +61,7 @@ public class Projection extends SpelNodeImpl {
|
||||
for (Object k : mapdata.keySet()) {
|
||||
try {
|
||||
state.pushActiveContextObject(new TypedValue(new KeyValuePair(k, mapdata.get(k)),TypeDescriptor.valueOf(KeyValuePair.class)));
|
||||
result.add(getChild(0).getValueInternal(state));
|
||||
result.add(getChild(0).getValueInternal(state).getValue());
|
||||
} finally {
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
@@ -76,7 +76,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));
|
||||
result.add(getChild(0).getValueInternal(state).getValue());
|
||||
} finally {
|
||||
state.exitScope();
|
||||
state.popActiveContextObject();
|
||||
@@ -95,9 +95,4 @@ public class Projection extends SpelNodeImpl {
|
||||
return sb.append("!{").append(getChild(0).toStringAST()).append("}").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -145,6 +145,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
||||
}
|
||||
}
|
||||
} catch (AccessException ae) {
|
||||
ae.printStackTrace();
|
||||
throw new SpelException(getCharPositionInLine(), ae, SpelMessages.EXCEPTION_DURING_PROPERTY_WRITE,
|
||||
name, ae.getMessage());
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.springframework.expression.spel.ExpressionState;
|
||||
*/
|
||||
public class QualifiedIdentifier extends SpelNodeImpl {
|
||||
|
||||
private String value;
|
||||
private TypedValue value;
|
||||
|
||||
public QualifiedIdentifier(Token payload) {
|
||||
super(payload);
|
||||
@@ -49,18 +49,17 @@ public class QualifiedIdentifier extends SpelNodeImpl {
|
||||
}
|
||||
sb.append(getChild(i).getValueInternal(state).getValue());
|
||||
}
|
||||
this.value = sb.toString();
|
||||
this.value = new TypedValue(sb.toString(),STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
return new TypedValue(this.value,STRING_TYPE_DESCRIPTOR);
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (this.value != null) {
|
||||
sb.append(this.value);
|
||||
}
|
||||
else {
|
||||
sb.append(this.value.getValue());
|
||||
} else {
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
if (i > 0) {
|
||||
sb.append(".");
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.expression.spel.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -59,17 +60,21 @@ public class Selection extends SpelNodeImpl {
|
||||
SpelNodeImpl selectionCriteria = getChild(0);
|
||||
if (operand instanceof Map) {
|
||||
Map<?, ?> mapdata = (Map<?, ?>) operand;
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
// TODO don't lose generic info for the new map
|
||||
Map<Object,Object> result = new HashMap<Object,Object>();
|
||||
for (Object k : mapdata.keySet()) {
|
||||
try {
|
||||
TypedValue kvpair = new TypedValue(new KeyValuePair(k, mapdata.get(k)),TypeDescriptor.valueOf(KeyValuePair.class));
|
||||
KeyValuePair kvp = new KeyValuePair(k,mapdata.get(k));
|
||||
TypedValue kvpair = new TypedValue(kvp,TypeDescriptor.valueOf(KeyValuePair.class));
|
||||
state.pushActiveContextObject(kvpair);
|
||||
Object o = selectionCriteria.getValueInternal(state);
|
||||
Object o = selectionCriteria.getValueInternal(state).getValue();
|
||||
if (o instanceof Boolean) {
|
||||
if (((Boolean) o).booleanValue() == true) {
|
||||
if (variant == FIRST)
|
||||
return kvpair;
|
||||
result.add(kvpair);
|
||||
if (variant == FIRST) {
|
||||
result.put(kvp.key,kvp.value);
|
||||
return new TypedValue(result);
|
||||
}
|
||||
result.put(kvp.key,kvp.value);
|
||||
}
|
||||
} else {
|
||||
throw new SpelException(selectionCriteria.getCharPositionInLine(),
|
||||
@@ -142,9 +147,4 @@ public class Selection extends SpelNodeImpl {
|
||||
return sb.append(getChild(0).toStringAST()).append("}").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Seria
|
||||
}
|
||||
}
|
||||
|
||||
// by default Ast nodes are not writable
|
||||
public boolean isWritable(ExpressionState expressionState) throws EvaluationException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.antlr.runtime.tree.CommonTreeAdaptor;
|
||||
|
||||
import org.springframework.expression.spel.generated.SpringExpressionsLexer;
|
||||
|
||||
/**
|
||||
@@ -95,7 +94,7 @@ public class SpelTreeAdaptor extends CommonTreeAdaptor {
|
||||
return new CompoundExpression(payload);
|
||||
|
||||
case SpringExpressionsLexer.CONSTRUCTOR:
|
||||
return new ConstructorReference(payload, false);
|
||||
return new ConstructorReference(payload);
|
||||
case SpringExpressionsLexer.VARIABLEREF:
|
||||
return new VariableReference(payload);
|
||||
case SpringExpressionsLexer.FUNCTIONREF:
|
||||
@@ -123,11 +122,6 @@ public class SpelTreeAdaptor extends CommonTreeAdaptor {
|
||||
case SpringExpressionsLexer.INSTANCEOF:
|
||||
return new OperatorInstanceof(payload);
|
||||
|
||||
case SpringExpressionsLexer.RPAREN:
|
||||
return new Placeholder(payload);
|
||||
case SpringExpressionsLexer.COLON:
|
||||
return new Placeholder(payload);
|
||||
|
||||
case SpringExpressionsLexer.DOT:
|
||||
return new Dot(payload);
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ 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;
|
||||
|
||||
/**
|
||||
* Represents a ternary expression, for example: "someCheck()?true:false".
|
||||
@@ -57,9 +56,4 @@ public class Ternary extends SpelNodeImpl {
|
||||
.append(" : ").append(getChild(2).toStringAST()).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ 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;
|
||||
|
||||
/**
|
||||
* Represents a reference to a type, for example "T(String)" or "T(com.somewhere.Foo)"
|
||||
@@ -56,9 +55,4 @@ public class TypeReference extends SpelNodeImpl {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(ExpressionState expressionState) throws SpelException {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,8 +56,7 @@ class ReflectiveMethodExecutor implements MethodExecutor {
|
||||
}
|
||||
ReflectionUtils.makeAccessible(this.method);
|
||||
return new TypedValue(this.method.invoke(target, arguments), new TypeDescriptor(new MethodParameter(method,-1)));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
throw new AccessException("Problem invoking method: " + this.method, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.expression.spel.support;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.service.DefaultConversionService;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
@@ -31,8 +32,16 @@ import org.springframework.util.NumberUtils;
|
||||
*/
|
||||
public class StandardTypeConverter implements TypeConverter {
|
||||
|
||||
DefaultConversionService conversionService;
|
||||
|
||||
StandardTypeConverter() {
|
||||
conversionService = new DefaultConversionService();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T convertValue(Object value, Class<T> targetType) throws EvaluationException {
|
||||
// For activation when conversion service available - this replaces the rest of the method (probably...)
|
||||
// return (T)convertValue(value,TypeDescriptor.valueOf(targetType));
|
||||
if (ClassUtils.isAssignableValue(targetType, value)) {
|
||||
return (T) value;
|
||||
}
|
||||
@@ -78,10 +87,20 @@ public class StandardTypeConverter implements TypeConverter {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T convertValue(Object value, TypeDescriptor typeDescriptor) throws EvaluationException {
|
||||
// For activation when conversion service available - this replaces the rest of the method (probably...)
|
||||
// try {
|
||||
// return (T)conversionService.executeConversion(value, typeDescriptor);
|
||||
// } catch (ConversionExecutorNotFoundException cenfe) {
|
||||
// throw new SpelException(cenfe, SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString());
|
||||
// } catch (ConversionException ce) {
|
||||
// throw new SpelException(ce, SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString());
|
||||
// }
|
||||
return (T)convertValue(value,typeDescriptor.getType());
|
||||
}
|
||||
|
||||
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
||||
// For activation when conversion service available - this replaces the rest of the method (probably...)
|
||||
// return canConvert(sourceType,TypeDescriptor.valueOf(targetType));
|
||||
if (ClassUtils.isAssignable(targetType, sourceType) || String.class.equals(targetType)) {
|
||||
return true;
|
||||
}
|
||||
@@ -92,6 +111,12 @@ public class StandardTypeConverter implements TypeConverter {
|
||||
}
|
||||
|
||||
public boolean canConvert(Class<?> sourceType, TypeDescriptor typeDescriptor) {
|
||||
// For activation when conversion service available - this replaces the rest of the method (probably...)
|
||||
// try {
|
||||
// return conversionService.getConversionExecutor(sourceType, typeDescriptor)!=null;
|
||||
// } catch (ConversionExecutorNotFoundException cenfe) {
|
||||
// return false;
|
||||
// }
|
||||
return canConvert(sourceType,typeDescriptor.getType());
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.expression.spel;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* Tests the evaluation of real expressions in a real context.
|
||||
@@ -208,6 +209,22 @@ public class EvaluationTests extends ExpressionTestCase {
|
||||
public void testConstructorInvocation05() {
|
||||
evaluate("new java.lang.String('foobar')", "foobar", String.class);
|
||||
}
|
||||
|
||||
public void testConstructorInvocation06() throws Exception {
|
||||
// repeated evaluation to drive use of cached executor
|
||||
SpelExpression expr = (SpelExpression)parser.parseExpression("new String('wibble')");
|
||||
String newString = expr.getValue(String.class);
|
||||
assertEquals("wibble",newString);
|
||||
newString = expr.getValue(String.class);
|
||||
assertEquals("wibble",newString);
|
||||
|
||||
// not writable
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
|
||||
// ast
|
||||
assertEquals("new String('wibble')",expr.toStringAST());
|
||||
}
|
||||
|
||||
|
||||
// array construction
|
||||
// public void testArrayConstruction01() {
|
||||
@@ -275,14 +292,18 @@ public class EvaluationTests extends ExpressionTestCase {
|
||||
// }
|
||||
|
||||
// projection and selection
|
||||
// public void testProjection01() {
|
||||
// evaluate("{1,2,3,4,5,6,7,8,9,10}.!{#isEven(#this)}", "[n, y, n, y, n, y, n, y, n, y]", ArrayList.class);
|
||||
// }
|
||||
//
|
||||
// public void testProjection02() {
|
||||
// evaluate("#{'a':'y','b':'n','c':'y'}.!{value=='y'?key:null}.nonnull().sort()", "[a, c]", ArrayList.class);
|
||||
// }
|
||||
//
|
||||
public void testProjection01() {
|
||||
evaluate("listOfNumbersUpToTen.!{#this<5?'y':'n'}","[y, y, y, y, n, n, n, n, n, n]",ArrayList.class);
|
||||
// inline list creation not supported at the moment
|
||||
// evaluate("{1,2,3,4,5,6,7,8,9,10}.!{#isEven(#this)}", "[n, y, n, y, n, y, n, y, n, y]", ArrayList.class);
|
||||
}
|
||||
|
||||
public void testProjection02() {
|
||||
// inline map creation not supported at the moment
|
||||
// evaluate("#{'a':'y','b':'n','c':'y'}.!{value=='y'?key:null}.nonnull().sort()", "[a, c]", ArrayList.class);
|
||||
evaluate("mapOfNumbersUpToTen.!{key>5?value:null}", "[null, null, null, null, null, six, seven, eight, nine, ten]", ArrayList.class);
|
||||
}
|
||||
|
||||
// public void testProjection03() {
|
||||
// evaluate("{1,2,3,4,5,6,7,8,9,10}.!{#this>5}",
|
||||
// "[false, false, false, false, false, true, true, true, true, true]", ArrayList.class);
|
||||
@@ -291,11 +312,21 @@ public class EvaluationTests extends ExpressionTestCase {
|
||||
// public void testProjection04() {
|
||||
// evaluate("{1,2,3,4,5,6,7,8,9,10}.!{$index>5?'y':'n'}", "[n, n, n, n, n, n, y, y, y, y]", ArrayList.class);
|
||||
// }
|
||||
|
||||
public void testSelection01() {
|
||||
// inline list creation not supported:
|
||||
// evaluate("{1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'}", "[2, 4, 6, 8, 10]", ArrayList.class);
|
||||
|
||||
public void testProjection05() {
|
||||
evaluateAndCheckError("'abc'.!{true}", SpelMessages.PROJECTION_NOT_SUPPORTED_ON_TYPE);
|
||||
}
|
||||
|
||||
public void testProjection06() throws Exception {
|
||||
SpelExpression expr = (SpelExpression)parser.parseExpression("'abc'.!{true}");
|
||||
assertEquals("'abc'.!{true}",expr.toStringAST());
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
}
|
||||
|
||||
//public void testSelection01() {
|
||||
// inline list creation not supported:
|
||||
// evaluate("{1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'}", "[2, 4, 6, 8, 10]", ArrayList.class);
|
||||
//}
|
||||
|
||||
public void testSelection02() {
|
||||
evaluate("testMap.keySet().?{#this matches '.*o.*'}", "[monday]", ArrayList.class);
|
||||
@@ -303,23 +334,40 @@ public class EvaluationTests extends ExpressionTestCase {
|
||||
evaluate("testMap.keySet().?{#this matches '.*r.*'}.size()", "3", Integer.class);
|
||||
}
|
||||
|
||||
// public void testSelectionError_NonBooleanSelectionCriteria() {
|
||||
// evaluateAndCheckError("{1,2,3,4,5,6,7,8,9,10}.?{'nonboolean'}",
|
||||
// SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);
|
||||
// }
|
||||
public void testSelectionError_NonBooleanSelectionCriteria() {
|
||||
evaluateAndCheckError("listOfNumbersUpToTen.?{'nonboolean'}",
|
||||
SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);
|
||||
}
|
||||
|
||||
// public void testSelectionUsingIndex() {
|
||||
// evaluate("{1,2,3,4,5,6,7,8,9,10}.?{$index > 5 }", "[7, 8, 9, 10]", ArrayList.class);
|
||||
// }
|
||||
|
||||
public void testSelection03() {
|
||||
evaluate("mapOfNumbersUpToTen.?{key>5}.size()", "5", Integer.class);
|
||||
}
|
||||
|
||||
// public void testSelectionFirst01() {
|
||||
// evaluate("{1,2,3,4,5,6,7,8,9,10}.^{#isEven(#this) == 'y'}", "2", Integer.class);
|
||||
// }
|
||||
//
|
||||
// public void testSelectionLast01() {
|
||||
// evaluate("{1,2,3,4,5,6,7,8,9,10}.${#isEven(#this) == 'y'}", "10", Integer.class);
|
||||
// }
|
||||
public void testSelectionFirst01() {
|
||||
evaluate("listOfNumbersUpToTen.^{#isEven(#this) == 'y'}", "2", Integer.class);
|
||||
}
|
||||
|
||||
public void testSelectionLast01() {
|
||||
evaluate("listOfNumbersUpToTen.${#isEven(#this) == 'y'}", "10", Integer.class);
|
||||
}
|
||||
|
||||
public void testSelectionAST() throws Exception {
|
||||
SpelExpression expr = (SpelExpression)parser.parseExpression("'abc'.^{true}");
|
||||
assertEquals("'abc'.^{true}",expr.toStringAST());
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
expr = (SpelExpression)parser.parseExpression("'abc'.?{true}");
|
||||
assertEquals("'abc'.?{true}",expr.toStringAST());
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
expr = (SpelExpression)parser.parseExpression("'abc'.${true}");
|
||||
assertEquals("'abc'.${true}",expr.toStringAST());
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
}
|
||||
|
||||
|
||||
// assignment
|
||||
public void testAssignmentToVariables01() {
|
||||
evaluate("#var1='value1'", "value1", String.class);
|
||||
@@ -451,6 +499,16 @@ public class EvaluationTests extends ExpressionTestCase {
|
||||
public void testTypeReferences01() {
|
||||
evaluate("T(java.lang.String)", "class java.lang.String", Class.class);
|
||||
}
|
||||
|
||||
public void testTypeReferencesAndQualifiedIdentifierCaching() throws Exception {
|
||||
SpelExpression expr = (SpelExpression)parser.parseExpression("T(java.lang.String)");
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
assertEquals("T(java.lang.String)",expr.toStringAST());
|
||||
assertEquals(String.class,expr.getValue(Class.class));
|
||||
// use cached QualifiedIdentifier:
|
||||
assertEquals("T(java.lang.String)",expr.toStringAST());
|
||||
assertEquals(String.class,expr.getValue(Class.class));
|
||||
}
|
||||
|
||||
public void testTypeReferencesPrimitive() {
|
||||
evaluate("T(int)", "int", Class.class);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.expression.spel.ast.FormatHelper;
|
||||
|
||||
/**
|
||||
* Tests for any helper code.
|
||||
*
|
||||
* @author Andy Clement
|
||||
*/
|
||||
public class HelperTests extends ExpressionTestCase {
|
||||
|
||||
public void testFormatHelperForClassName() {
|
||||
assertEquals("java.lang.String",FormatHelper.formatClassNameForMessage(String.class));
|
||||
assertEquals("java.lang.String[]",FormatHelper.formatClassNameForMessage(new String[1].getClass()));
|
||||
assertEquals("int[]",FormatHelper.formatClassNameForMessage(new int[1].getClass()));
|
||||
assertEquals("int[][]",FormatHelper.formatClassNameForMessage(new int[1][2].getClass()));
|
||||
assertEquals("null",FormatHelper.formatClassNameForMessage(null));
|
||||
}
|
||||
|
||||
public void testFormatHelperForMethod() {
|
||||
assertEquals("foo(java.lang.String)",FormatHelper.formatMethodForMessage("foo", String.class));
|
||||
assertEquals("goo(java.lang.String,int[])",FormatHelper.formatMethodForMessage("goo", String.class,new int[1].getClass()));
|
||||
assertEquals("boo()",FormatHelper.formatMethodForMessage("boo"));
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* Tests the evaluation of basic literals: boolean, integer, hex integer, long, real, null, date
|
||||
*
|
||||
@@ -134,4 +136,13 @@ public class LiteralTests extends ExpressionTestCase {
|
||||
evaluate("new Integer(37).byteValue()", (byte) 37, Byte.class); // calling byteValue() on Integer.class
|
||||
evaluateAndAskForReturnType("new Integer(37)", (byte) 37, Byte.class); // relying on registered type converters
|
||||
}
|
||||
|
||||
public void testNotWritable() throws Exception {
|
||||
SpelExpression expr = (SpelExpression)parser.parseExpression("37");
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
expr = (SpelExpression)parser.parseExpression("37L");
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
expr = (SpelExpression)parser.parseExpression("true");
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,8 @@ public class OperatorTests extends ExpressionTestCase {
|
||||
evaluate("3 == 5", false, Boolean.class);
|
||||
evaluate("5 == 3", false, Boolean.class);
|
||||
evaluate("6 == 6", true, Boolean.class);
|
||||
evaluate("3.0f == 5.0f", false, Boolean.class);
|
||||
evaluate("3.0f == 3.0f", true, Boolean.class);
|
||||
evaluate("'abc' == null", false, Boolean.class);
|
||||
}
|
||||
|
||||
@@ -70,6 +72,8 @@ public class OperatorTests extends ExpressionTestCase {
|
||||
evaluate("3 != 5", true, Boolean.class);
|
||||
evaluate("5 != 3", true, Boolean.class);
|
||||
evaluate("6 != 6", false, Boolean.class);
|
||||
evaluate("3.0f != 5.0f", true, Boolean.class);
|
||||
evaluate("3.0f != 3.0f", false, Boolean.class);
|
||||
}
|
||||
|
||||
public void testGreaterThanOrEqual() {
|
||||
@@ -122,23 +126,36 @@ public class OperatorTests extends ExpressionTestCase {
|
||||
}
|
||||
|
||||
public void testPlus() throws Exception {
|
||||
evaluate("'a' + 2", "c", String.class);
|
||||
evaluate("7 + 2", "9", Integer.class);
|
||||
evaluate("3.0f + 5.0f", 8.0d, Double.class);
|
||||
evaluate("3.0d + 5.0d", 8.0d, Double.class);
|
||||
|
||||
evaluateAndCheckError("'ab' + 2", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
evaluate("2+'a' ", "c", String.class);
|
||||
evaluateAndCheckError("2+'a' ", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
evaluateAndCheckError("2+'ab'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
|
||||
// AST:
|
||||
SpelExpression expr = (SpelExpression)parser.parseExpression("+3");
|
||||
assertEquals("+3",expr.toStringAST());
|
||||
expr = (SpelExpression)parser.parseExpression("2+3");
|
||||
assertEquals("(2 + 3)",expr.toStringAST());
|
||||
|
||||
// use as a unary operator
|
||||
evaluate("+5d",5d,Double.class);
|
||||
evaluate("+5L",5L,Long.class);
|
||||
evaluate("+5",5,Integer.class);
|
||||
evaluateAndCheckError("+'abc'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
|
||||
// string concatenation
|
||||
evaluate("'abc'+'def'","abcdef",String.class);
|
||||
|
||||
//
|
||||
evaluate("5 + new Integer('37')",42,Integer.class);
|
||||
}
|
||||
|
||||
public void testMinus() throws Exception {
|
||||
evaluate("'c' - 2", "a", String.class);
|
||||
evaluate("3.0f - 5.0f", -2.0d, Double.class);
|
||||
evaluateAndCheckError("'ab' - 2", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
evaluateAndCheckError("2-'ab'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
SpelExpression expr = (SpelExpression)parser.parseExpression("-3");
|
||||
@@ -156,11 +173,14 @@ public class OperatorTests extends ExpressionTestCase {
|
||||
evaluate("3%2",1,Integer.class);
|
||||
evaluate("3L%2L",1L,Long.class);
|
||||
evaluate("3.0d%2.0d",1d,Double.class);
|
||||
evaluate("5.0f % 3.1f", 1.9d, Double.class);
|
||||
evaluateAndCheckError("'abc'%'def'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
}
|
||||
|
||||
public void testDivide() {
|
||||
evaluate("3.0f / 5.0f", 0.6d, Double.class);
|
||||
evaluate("4L/2L",2L,Long.class);
|
||||
evaluateAndCheckError("'abc'/'def'",SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
}
|
||||
|
||||
public void testMathOperatorDivide_ConvertToDouble() {
|
||||
@@ -182,20 +202,8 @@ public class OperatorTests extends ExpressionTestCase {
|
||||
evaluate("3.0d / 5.0d", 0.6d, Double.class);
|
||||
evaluate("6.0d % 3.5d", 2.5d, Double.class);
|
||||
}
|
||||
|
||||
public void testFloats() {
|
||||
evaluate("3.0f == 5.0f", false, Boolean.class);
|
||||
evaluate("3.0f == 3.0f", true, Boolean.class);
|
||||
evaluate("3.0f != 5.0f", true, Boolean.class);
|
||||
evaluate("3.0f != 3.0f", false, Boolean.class);
|
||||
evaluate("3.0f + 5.0f", 8.0d, Double.class);
|
||||
evaluate("3.0f - 5.0f", -2.0d, Double.class);
|
||||
evaluate("3.0f * 5.0f", 15.0d, Double.class);
|
||||
evaluate("3.0f / 5.0f", 0.6d, Double.class);
|
||||
evaluate("5.0f % 3.1f", 1.9d, Double.class);
|
||||
}
|
||||
|
||||
public void testOperatorStrings() throws Exception {
|
||||
public void testOperatorNames() throws Exception {
|
||||
Operator node = getOperatorNode((SpelExpression)parser.parseExpression("1==3"));
|
||||
assertEquals("==",node.getOperatorName());
|
||||
|
||||
@@ -266,6 +274,8 @@ public class OperatorTests extends ExpressionTestCase {
|
||||
evaluate("3L - 50L", -47L, Long.class);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
private Operator getOperatorNode(SpelExpression e) {
|
||||
SpelNode node = e.getAST();
|
||||
return (Operator)findNode(node,Operator.class);
|
||||
|
||||
@@ -29,6 +29,7 @@ public class ParserErrorMessagesTests extends ExpressionTestCase {
|
||||
// will not fit into an int, needs L suffix
|
||||
parseAndCheckError("0xCAFEBABE", SpelMessages.NOT_AN_INTEGER);
|
||||
evaluate("0xCAFEBABEL", 0xCAFEBABEL, Long.class);
|
||||
parseAndCheckError("0xCAFEBABECAFEBABEL", SpelMessages.NOT_A_LONG);
|
||||
}
|
||||
|
||||
public void testBrokenExpression02() {
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.expression.spel;
|
||||
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
|
||||
/**
|
||||
* Tests the evaluation of expressions that access variables and functions (lambda/java).
|
||||
*
|
||||
@@ -26,10 +27,15 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
*/
|
||||
public class VariableAndFunctionTests extends ExpressionTestCase {
|
||||
|
||||
public void testVariableAccess() {
|
||||
public void testVariableAccess01() {
|
||||
evaluate("#answer", "42", Integer.class, SHOULD_BE_WRITABLE);
|
||||
evaluate("#answer / 2", 21, Integer.class, SHOULD_NOT_BE_WRITABLE);
|
||||
}
|
||||
|
||||
public void testVariableAccess_WellKnownVariables() {
|
||||
evaluate("#this.getName()","Nikola Tesla",String.class);
|
||||
evaluate("#root.getName()","Nikola Tesla",String.class);
|
||||
}
|
||||
|
||||
public void testFunctionAccess01() {
|
||||
evaluate("#reverseInt(1,2,3)", "int[3]{3,2,1}", int[].class);
|
||||
@@ -71,7 +77,7 @@ public class VariableAndFunctionTests extends ExpressionTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this method is used by the test above
|
||||
public void nonStatic() {
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
package org.springframework.expression.spel.testresources;
|
||||
|
||||
///CLOVER:OFF
|
||||
public class Company {
|
||||
String address;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ package org.springframework.expression.spel.testresources;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
///CLOVER:OFF
|
||||
public class Fruit {
|
||||
public String name; // accessible as property field
|
||||
public Color color; // accessible as property through getter/setter
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
///CLOVER:OFF
|
||||
@SuppressWarnings("unused")
|
||||
public class Inventor {
|
||||
private String name;
|
||||
@@ -26,6 +27,8 @@ public class Inventor {
|
||||
public List<Integer> listOfInteger = new ArrayList<Integer>();
|
||||
public List<Boolean> booleanList = new ArrayList<Boolean>();
|
||||
public Map<String,Boolean> mapOfStringToBoolean = new HashMap<String,Boolean>();
|
||||
public Map<Integer,String> mapOfNumbersUpToTen = new HashMap<Integer,String>();
|
||||
public List<Integer> listOfNumbersUpToTen = new ArrayList<Integer>();
|
||||
|
||||
public Inventor(String name, Date birthdate, String nationality) {
|
||||
this.name = name;
|
||||
@@ -42,6 +45,26 @@ public class Inventor {
|
||||
testMap.put("sunday", "sonntag");
|
||||
booleanList.add(false);
|
||||
booleanList.add(false);
|
||||
listOfNumbersUpToTen.add(1);
|
||||
listOfNumbersUpToTen.add(2);
|
||||
listOfNumbersUpToTen.add(3);
|
||||
listOfNumbersUpToTen.add(4);
|
||||
listOfNumbersUpToTen.add(5);
|
||||
listOfNumbersUpToTen.add(6);
|
||||
listOfNumbersUpToTen.add(7);
|
||||
listOfNumbersUpToTen.add(8);
|
||||
listOfNumbersUpToTen.add(9);
|
||||
listOfNumbersUpToTen.add(10);
|
||||
mapOfNumbersUpToTen.put(1,"one");
|
||||
mapOfNumbersUpToTen.put(2,"two");
|
||||
mapOfNumbersUpToTen.put(3,"three");
|
||||
mapOfNumbersUpToTen.put(4,"four");
|
||||
mapOfNumbersUpToTen.put(5,"five");
|
||||
mapOfNumbersUpToTen.put(6,"six");
|
||||
mapOfNumbersUpToTen.put(7,"seven");
|
||||
mapOfNumbersUpToTen.put(8,"eight");
|
||||
mapOfNumbersUpToTen.put(9,"nine");
|
||||
mapOfNumbersUpToTen.put(10,"ten");
|
||||
}
|
||||
|
||||
public void setPlaceOfBirth(PlaceOfBirth placeOfBirth2) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package org.springframework.expression.spel.testresources;
|
||||
|
||||
|
||||
///CLOVER:OFF
|
||||
public class Person {
|
||||
private String privateName;
|
||||
Company company;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.springframework.expression.spel.testresources;
|
||||
|
||||
///CLOVER:OFF
|
||||
public class PlaceOfBirth {
|
||||
private String city;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user