objects flowing around in expression evaluation are now TypedValue's - these carry generics info, used for conversions.
This commit is contained in:
parent
f6c1144e8d
commit
4c5854d017
|
|
@ -17,15 +17,18 @@
|
|||
package org.springframework.context.expression;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* EL property accessor that knows how to traverse the beans and contextual objects
|
||||
* of a Spring {@link org.springframework.beans.factory.config.BeanExpressionContext}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BeanExpressionContextAccessor implements PropertyAccessor {
|
||||
|
|
@ -34,8 +37,8 @@ public class BeanExpressionContextAccessor implements PropertyAccessor {
|
|||
return (((BeanExpressionContext) target).containsObject(name));
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return ((BeanExpressionContext) target).getObject(name);
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(((BeanExpressionContext) target).getObject(name));
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
|
|
|||
|
|
@ -17,15 +17,18 @@
|
|||
package org.springframework.context.expression;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* EL property accessor that knows how to traverse the beans of a
|
||||
* Spring {@link org.springframework.beans.factory.BeanFactory}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BeanFactoryAccessor implements PropertyAccessor {
|
||||
|
|
@ -34,8 +37,8 @@ public class BeanFactoryAccessor implements PropertyAccessor {
|
|||
return (((BeanFactory) target).containsBean(name));
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return ((BeanFactory) target).getBean(name);
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(((BeanFactory) target).getBean(name));
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
|
|
|||
|
|
@ -21,12 +21,15 @@ import java.util.Map;
|
|||
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.ast.CommonTypeDescriptors;
|
||||
|
||||
/**
|
||||
* EL property accessor that knows how to traverse the keys
|
||||
* of a standard {@link java.util.Map}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class MapAccessor implements PropertyAccessor {
|
||||
|
|
@ -35,8 +38,8 @@ public class MapAccessor implements PropertyAccessor {
|
|||
return (((Map) target).containsKey(name));
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return ((Map) target).get(name);
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(((Map) target).get(name),CommonTypeDescriptors.OBJECT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.expression;
|
||||
|
||||
|
||||
// TODO Is the resolver/executor model too pervasive in this package?
|
||||
/**
|
||||
* Executors are built by resolvers and can be cached by the infrastructure to repeat an operation quickly without going
|
||||
|
|
@ -39,6 +40,6 @@ public interface ConstructorExecutor {
|
|||
* @return the new object
|
||||
* @throws AccessException if there is a problem executing the command or the CommandExecutor is no longer valid
|
||||
*/
|
||||
Object execute(EvaluationContext context, Object... arguments) throws AccessException;
|
||||
TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public interface EvaluationContext {
|
|||
/**
|
||||
* @return the root context object against which unqualified properties/methods/etc should be resolved
|
||||
*/
|
||||
Object getRootObject();
|
||||
TypedValue getRootObject();
|
||||
|
||||
/**
|
||||
* Set a named variable within this execution context to a specified value.
|
||||
|
|
|
|||
|
|
@ -39,6 +39,6 @@ public interface MethodExecutor {
|
|||
* @return the value returned from execution
|
||||
* @throws AccessException if there is a problem executing the command or the MethodExecutor is no longer valid
|
||||
*/
|
||||
Object execute(EvaluationContext context, Object target, Object... arguments) throws AccessException;
|
||||
TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,10 +58,10 @@ public interface PropertyAccessor {
|
|||
* @param context the evaluation context in which the access is being attempted
|
||||
* @param target the target object upon which the property is being accessed
|
||||
* @param name the name of the property being accessed
|
||||
* @return Object the value of the property
|
||||
* @return a TypedValue object wrapping the property value read and a type descriptor for it
|
||||
* @throws AccessException if there is any problem accessing the property value
|
||||
*/
|
||||
Object read(EvaluationContext context, Object target, String name) throws AccessException;
|
||||
TypedValue read(EvaluationContext context, Object target, String name) throws AccessException;
|
||||
|
||||
/**
|
||||
* Called to determine if a resolver instance is able to write to a specified property on a specified target object.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
/**
|
||||
* Encapsulates an object and a type descriptor that describes it.
|
||||
* The type descriptor can hold generic information that would
|
||||
* not be accessible through a simple getClass() call on the object.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class TypedValue {
|
||||
|
||||
private Object value;
|
||||
private TypeDescriptor typeDescriptor;
|
||||
|
||||
/**
|
||||
* Create a TypedValue for a simple object. The type descriptor is inferred
|
||||
* from the object, so no generic information is preserved.
|
||||
* @param value the object value
|
||||
*/
|
||||
public TypedValue(Object value) {
|
||||
this.value = value;
|
||||
this.typeDescriptor = TypeDescriptor.forObject(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TypedValue for a particular value with a particular type descriptor.
|
||||
* @param value the object value
|
||||
* @param typeDescriptor a type descriptor describing the type of the value
|
||||
*/
|
||||
public TypedValue(Object value, TypeDescriptor typeDescriptor) {
|
||||
this.value = value;
|
||||
this.typeDescriptor = typeDescriptor;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public TypeDescriptor getTypeDescriptor() {
|
||||
return this.typeDescriptor;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ import org.springframework.expression.Operation;
|
|||
import org.springframework.expression.OperatorOverloader;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypeComparator;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* An ExpressionState is for maintaining per-expression-evaluation state, any changes to it are not seen by other
|
||||
|
|
@ -45,7 +46,7 @@ public class ExpressionState {
|
|||
|
||||
private final Stack<VariableScope> variableScopes = new Stack<VariableScope>();
|
||||
|
||||
private final Stack<Object> contextObjects = new Stack<Object>();
|
||||
private final Stack<TypedValue> contextObjects = new Stack<TypedValue>();
|
||||
|
||||
|
||||
public ExpressionState() {
|
||||
|
|
@ -65,14 +66,18 @@ public class ExpressionState {
|
|||
/**
|
||||
* The active context object is what unqualified references to properties/etc are resolved against.
|
||||
*/
|
||||
public Object getActiveContextObject() {
|
||||
public TypedValue getActiveContextObject() {
|
||||
if (this.contextObjects.isEmpty()) {
|
||||
return this.relatedContext.getRootObject();
|
||||
TypedValue rootObject = this.relatedContext.getRootObject();
|
||||
if (rootObject == null) {
|
||||
return new TypedValue(rootObject,TypeDescriptor.NULL_TYPE_DESCRIPTOR);
|
||||
}
|
||||
return rootObject;
|
||||
}
|
||||
return this.contextObjects.peek();
|
||||
}
|
||||
|
||||
public void pushActiveContextObject(Object obj) {
|
||||
public void pushActiveContextObject(TypedValue obj) {
|
||||
this.contextObjects.push(obj);
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +85,7 @@ public class ExpressionState {
|
|||
this.contextObjects.pop();
|
||||
}
|
||||
|
||||
public Object getRootContextObject() {
|
||||
public TypedValue getRootContextObject() {
|
||||
return this.relatedContext.getRootObject();
|
||||
}
|
||||
|
||||
|
|
@ -88,8 +93,9 @@ public class ExpressionState {
|
|||
this.relatedContext.setVariable(name, value);
|
||||
}
|
||||
|
||||
public Object lookupVariable(String name) {
|
||||
return this.relatedContext.lookupVariable(name);
|
||||
public TypedValue lookupVariable(String name) {
|
||||
Object value = this.relatedContext.lookupVariable(name);
|
||||
return new TypedValue(value,TypeDescriptor.valueOf((value==null?null:value.getClass())));
|
||||
}
|
||||
|
||||
public TypeComparator getTypeComparator() {
|
||||
|
|
@ -103,11 +109,15 @@ public class ExpressionState {
|
|||
public <T> T convertValue(Object value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
|
||||
return this.relatedContext.getTypeConverter().convertValue(value, targetTypeDescriptor);
|
||||
}
|
||||
|
||||
public <T> T convertValue(Object value, Class<T> targetType) throws EvaluationException {
|
||||
return this.relatedContext.getTypeConverter().convertValue(value, targetType);
|
||||
|
||||
public <T> T convertValue(TypedValue value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
|
||||
return this.relatedContext.getTypeConverter().convertValue(value.getValue(), targetTypeDescriptor);
|
||||
}
|
||||
|
||||
// public <T> T convertValue(TypedValue value, Class<T> targetType) throws EvaluationException {
|
||||
// return this.relatedContext.getTypeConverter().convertValue(value, targetType);
|
||||
// }
|
||||
|
||||
/**
|
||||
* A new scope is entered when a function is invoked
|
||||
*/
|
||||
|
|
@ -137,10 +147,11 @@ public class ExpressionState {
|
|||
return null;
|
||||
}
|
||||
|
||||
public Object operate(Operation op, Object left, Object right) throws EvaluationException {
|
||||
public TypedValue operate(Operation op, Object left, Object right) throws EvaluationException {
|
||||
OperatorOverloader overloader = this.relatedContext.getOperatorOverloader();
|
||||
if (overloader.overridesOperation(op, left, right)) {
|
||||
return overloader.operate(op, left, right);
|
||||
Object returnValue = overloader.operate(op, left, right);
|
||||
return new TypedValue(returnValue,TypeDescriptor.forObject(returnValue));
|
||||
}
|
||||
else {
|
||||
throw new SpelException(SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES, op, left, right);
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@ package org.springframework.expression.spel.ast;
|
|||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
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.
|
||||
|
|
@ -36,9 +37,9 @@ public class Assign extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object newValue = getChild(1).getValueInternal(state);
|
||||
getChild(0).setValue(state, newValue);
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue newValue = getChild(1).getValueInternal(state);
|
||||
getChild(0).setValue(state, newValue.getValue());
|
||||
return newValue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* Represents the literal values TRUE and FALSE.
|
||||
|
|
@ -26,15 +27,15 @@ import org.antlr.runtime.Token;
|
|||
*/
|
||||
public class BooleanLiteral extends Literal {
|
||||
|
||||
private final Boolean value;
|
||||
private final BooleanTypedValue value;
|
||||
|
||||
public BooleanLiteral(Token payload, boolean value) {
|
||||
super(payload);
|
||||
this.value = value;
|
||||
this.value = BooleanTypedValue.forValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getLiteralValue() {
|
||||
public BooleanTypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
/**
|
||||
* @author Andy Clement
|
||||
* @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);
|
||||
|
||||
}
|
||||
|
|
@ -18,8 +18,9 @@ package org.springframework.expression.spel.ast;
|
|||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
|
||||
/**
|
||||
* Represents a DOT separated expression sequence, such as 'property1.property2.methodOne()'
|
||||
|
|
@ -40,8 +41,8 @@ public class CompoundExpression extends SpelNodeImpl {
|
|||
* @return the final value from the last piece of the compound expression
|
||||
*/
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object result = null;
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue result = null;
|
||||
SpelNodeImpl nextNode = null;
|
||||
try {
|
||||
nextNode = getChild(0);
|
||||
|
|
@ -69,7 +70,7 @@ public class CompoundExpression extends SpelNodeImpl {
|
|||
getChild(0).setValue(state, value);
|
||||
return;
|
||||
}
|
||||
Object ctx = getChild(0).getValueInternal(state);
|
||||
TypedValue ctx = getChild(0).getValueInternal(state);
|
||||
for (int i = 1; i < getChildCount() - 1; i++) {
|
||||
try {
|
||||
state.pushActiveContextObject(ctx);
|
||||
|
|
@ -91,7 +92,7 @@ public class CompoundExpression extends SpelNodeImpl {
|
|||
if (getChildCount() == 1) {
|
||||
return getChild(0).isWritable(state);
|
||||
}
|
||||
Object ctx = getChild(0).getValueInternal(state);
|
||||
TypedValue ctx = getChild(0).getValueInternal(state);
|
||||
for (int i = 1; i < getChildCount() - 1; i++) {
|
||||
try {
|
||||
state.pushActiveContextObject(ctx);
|
||||
|
|
|
|||
|
|
@ -20,12 +20,13 @@ 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;
|
||||
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.SpelMessages;
|
||||
|
|
@ -67,7 +68,7 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
* Implements getValue() - delegating to the code for building an array or a simple type.
|
||||
*/
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
if (this.isArrayConstructor) {
|
||||
return createArray(state);
|
||||
}
|
||||
|
|
@ -123,14 +124,14 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
* @return the new array
|
||||
* @throws EvaluationException if there is a problem creating the array
|
||||
*/
|
||||
private Object createArray(ExpressionState state) throws EvaluationException {
|
||||
Object intendedArrayType = getChild(0).getValueInternal(state);
|
||||
if (!(intendedArrayType instanceof String)) {
|
||||
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;
|
||||
String type = (String) intendedArrayType.getValue();
|
||||
Class<?> componentType = null;
|
||||
TypeCode arrayTypeCode = TypeCode.forName(type);
|
||||
if (arrayTypeCode == TypeCode.OBJECT) {
|
||||
|
|
@ -140,6 +141,7 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
Object newArray = null;
|
||||
TypeDescriptor newArrayTypeDescriptor = null;
|
||||
|
||||
if (getChild(1).getChildCount() == 0) { // are the array ranks defined?
|
||||
if (getChildCount() < 3) {
|
||||
|
|
@ -149,13 +151,14 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
// 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.class);
|
||||
int arraySize = state.convertValue(o, INTEGER_TYPE_DESCRIPTOR);
|
||||
if (getChildCount() == 3) {
|
||||
// Check initializer length matches array size length
|
||||
int initializerLength = getChild(2).getChildCount();
|
||||
|
|
@ -165,14 +168,16 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
}
|
||||
}
|
||||
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.class);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -195,47 +200,47 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
} 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.class);
|
||||
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.class);
|
||||
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.class);
|
||||
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.class);
|
||||
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.class);
|
||||
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.class);
|
||||
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.class);
|
||||
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.class);
|
||||
newByteArray[i] = state.convertValue(initializer.getChild(i).getValueInternal(state), BYTE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newArray;
|
||||
return new TypedValue(newArray, newArrayTypeDescriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -244,13 +249,13 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
* @return the new object
|
||||
* @throws EvaluationException if there is a problem creating the object
|
||||
*/
|
||||
private Object createNewInstance(ExpressionState state) throws EvaluationException {
|
||||
private TypedValue createNewInstance(ExpressionState state) throws EvaluationException {
|
||||
Object[] arguments = new Object[getChildCount() - 1];
|
||||
Class<?>[] argumentTypes = new Class[getChildCount() - 1];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
Object childValue = getChild(i + 1).getValueInternal(state);
|
||||
arguments[i] = childValue;
|
||||
argumentTypes[i] = childValue.getClass();
|
||||
TypedValue childValue = getChild(i + 1).getValueInternal(state);
|
||||
arguments[i] = childValue.getValue();
|
||||
argumentTypes[i] = childValue.getValue().getClass();
|
||||
}
|
||||
|
||||
ConstructorExecutor executorToUse = this.cachedExecutor;
|
||||
|
|
@ -266,7 +271,7 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
// either there was no accessor or it no longer exists
|
||||
String typename = (String) getChild(0).getValueInternal(state);
|
||||
String typename = (String) getChild(0).getValueInternal(state).getValue();
|
||||
executorToUse = findExecutorForConstructor(typename, argumentTypes, state);
|
||||
try {
|
||||
return executorToUse.execute(state.getEvaluationContext(), arguments);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
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.
|
||||
|
|
@ -39,7 +40,7 @@ public class Dot extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws SpelException {
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
|
||||
/**
|
||||
* @author Andy Clement
|
||||
|
|
@ -31,7 +32,7 @@ public class EmptySpelNode extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws SpelException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
throw new RuntimeException("?");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@ 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.SpelMessages;
|
||||
|
|
@ -53,18 +55,18 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object o = state.lookupVariable(name);
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue o = state.lookupVariable(name);
|
||||
if (o == null) {
|
||||
throw new SpelException(SpelMessages.FUNCTION_NOT_DEFINED, name);
|
||||
}
|
||||
|
||||
// Two possibilities: a lambda function or a Java static method registered as a function
|
||||
if (!(o instanceof Method)) {
|
||||
if (!(o.getValue() instanceof Method)) {
|
||||
throw new SpelException(SpelMessages.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, name, o.getClass());
|
||||
}
|
||||
|
||||
return executeFunctionJLRMethod(state, (Method) o);
|
||||
return executeFunctionJLRMethod(state, (Method) o.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -75,7 +77,7 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
* @return the return value of the invoked Java method
|
||||
* @throws EvaluationException if there is any problem invoking the method
|
||||
*/
|
||||
private Object executeFunctionJLRMethod(ExpressionState state, Method m) throws EvaluationException {
|
||||
private TypedValue executeFunctionJLRMethod(ExpressionState state, Method m) throws EvaluationException {
|
||||
Object[] functionArgs = getArguments(state);
|
||||
|
||||
if (!m.isVarArgs() && m.getParameterTypes().length != functionArgs.length) {
|
||||
|
|
@ -99,7 +101,7 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
try {
|
||||
return m.invoke(m.getClass(), functionArgs);
|
||||
return new TypedValue(m.invoke(m.getClass(), functionArgs),new TypeDescriptor(new MethodParameter(m,-1)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new SpelException(getCharPositionInLine(), e, SpelMessages.EXCEPTION_DURING_FUNCTION_CALL, name, e
|
||||
.getMessage());
|
||||
|
|
@ -139,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);
|
||||
arguments[i] = getChild(i).getValueInternal(state).getValue();
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,8 @@
|
|||
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;
|
||||
|
||||
/**
|
||||
* @author Andy Clement
|
||||
|
|
@ -27,20 +26,20 @@ import org.springframework.expression.spel.SpelException;
|
|||
*/
|
||||
public class Identifier extends SpelNodeImpl {
|
||||
|
||||
private final String id;
|
||||
private final TypedValue id;
|
||||
|
||||
public Identifier(Token payload) {
|
||||
super(payload);
|
||||
this.id = payload.getText();
|
||||
this.id = new TypedValue(payload.getText(), STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
return this.id;
|
||||
return (String)this.id.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueInternal(ExpressionState state) {
|
||||
public TypedValue getValueInternal(ExpressionState state) {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ 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.SpelMessages;
|
||||
|
|
@ -43,53 +44,44 @@ public class Indexer extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object ctx = state.getActiveContextObject();
|
||||
Object index = getChild(0).getValueInternal(state);
|
||||
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);
|
||||
Object index = indexValue.getValue();
|
||||
|
||||
// Indexing into a Map
|
||||
if (ctx instanceof Map) {
|
||||
return ((Map<?, ?>) ctx).get(index);
|
||||
if (targetObject instanceof Map) {
|
||||
Object possiblyConvertedKey = state.convertValue(indexValue,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getMapKeyType()));
|
||||
Object o = ((Map<?, ?>) targetObject).get(possiblyConvertedKey);
|
||||
return new TypedValue(o,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getMapValueType()));
|
||||
}
|
||||
|
||||
int idx = state.convertValue(index, INTEGER_TYPE_DESCRIPTOR);
|
||||
|
||||
if (ctx.getClass().isArray()) {
|
||||
return accessArrayElement(ctx, idx);
|
||||
} else if (ctx instanceof Collection) {
|
||||
Collection<?> c = (Collection<?>) ctx;
|
||||
if (targetObjectTypeDescriptor.isArray()) {
|
||||
return new TypedValue(accessArrayElement(targetObject, idx),TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
|
||||
} else if (targetObjectTypeDescriptor.isCollection()) {
|
||||
Collection<?> c = (Collection<?>) targetObject;
|
||||
if (idx >= c.size()) {
|
||||
throw new SpelException(SpelMessages.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
|
||||
}
|
||||
int pos = 0;
|
||||
for (Object o : c) {
|
||||
if (pos == idx) {
|
||||
return o;
|
||||
return new TypedValue(o,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getElementType()));
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
// } else if (ctx instanceof Map) {
|
||||
// Map<?,?> c = (Map<?,?>) ctx;
|
||||
// // This code would allow a key/value pair to be pulled out by index from a map
|
||||
// if (idx >= c.size()) {
|
||||
// throw new ELException(ELMessages.COLLECTION_INDEX_OUT_OF_BOUNDS,c.size(),idx);
|
||||
// }
|
||||
// Set<?> keys = c.keySet();
|
||||
// int pos = 0;
|
||||
// for (Object k : keys) {
|
||||
// if (pos==idx) {
|
||||
// return new KeyValuePair(k,c.get(k));
|
||||
// }
|
||||
// pos++;
|
||||
// }
|
||||
} else if (ctx instanceof String) {
|
||||
String ctxString = (String) ctx;
|
||||
} 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);
|
||||
}
|
||||
return String.valueOf(ctxString.charAt(idx));
|
||||
return new TypedValue(String.valueOf(ctxString.charAt(idx)),STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, ctx.getClass().getName());
|
||||
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -101,27 +93,38 @@ public class Indexer extends SpelNodeImpl {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void setValue(ExpressionState state, Object newValue) throws EvaluationException {
|
||||
Object ctx = state.getActiveContextObject();
|
||||
Object index = getChild(0).getValueInternal(state);
|
||||
TypedValue contextObject = state.getActiveContextObject();
|
||||
Object targetObject = contextObject.getValue();
|
||||
TypeDescriptor targetObjectTypeDescriptor = contextObject.getTypeDescriptor();
|
||||
TypedValue index = getChild(0).getValueInternal(state);
|
||||
|
||||
// Indexing into a Map
|
||||
if (ctx instanceof Map) {
|
||||
((Map) ctx).put(index,newValue); // TODO missing conversion for both index and newValue
|
||||
if (targetObjectTypeDescriptor.isMap()) {
|
||||
Map map = (Map)targetObject;
|
||||
Object possiblyConvertedKey = state.convertValue(index.getValue(),TypeDescriptor.valueOf(targetObjectTypeDescriptor.getMapKeyType()));
|
||||
Object possiblyConvertedValue = state.convertValue(newValue,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getMapValueType()));
|
||||
map.put(possiblyConvertedKey,possiblyConvertedValue);
|
||||
return;
|
||||
}
|
||||
|
||||
int idx = state.convertValue(index, INTEGER_TYPE_DESCRIPTOR);
|
||||
|
||||
if (ctx.getClass().isArray()) {
|
||||
setArrayElement(state, ctx, idx, newValue);
|
||||
} else if (ctx instanceof List) {
|
||||
List<Object> c = (List<Object>) ctx;
|
||||
if (targetObjectTypeDescriptor.isArray()) {
|
||||
int idx = state.convertValue(index, INTEGER_TYPE_DESCRIPTOR);
|
||||
setArrayElement(state, contextObject.getValue(), idx, newValue, targetObjectTypeDescriptor.getElementType());
|
||||
} else if (targetObjectTypeDescriptor.isCollection()) {
|
||||
int idx = 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);
|
||||
}
|
||||
c.set(idx,newValue); // TODO missing conversion
|
||||
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());
|
||||
}
|
||||
} else {
|
||||
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, ctx.getClass().getName());
|
||||
throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, contextObject.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,44 +141,44 @@ public class Indexer extends SpelNodeImpl {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
private void setArrayElement(ExpressionState state, Object ctx, int idx, Object newValue) throws EvaluationException {
|
||||
Class<?> arrayComponentType = ctx.getClass().getComponentType();
|
||||
private void setArrayElement(ExpressionState state, Object ctx, int idx, Object newValue, Class clazz) throws EvaluationException {
|
||||
Class<?> arrayComponentType = clazz;
|
||||
if (arrayComponentType == Integer.TYPE) {
|
||||
int[] array = (int[]) ctx;
|
||||
checkAccess(array.length, idx);
|
||||
array[idx] = state.convertValue(newValue, Integer.class);
|
||||
array[idx] = state.convertValue(newValue, INTEGER_TYPE_DESCRIPTOR);
|
||||
} else if (arrayComponentType == Boolean.TYPE) {
|
||||
boolean[] array = (boolean[]) ctx;
|
||||
checkAccess(array.length, idx);
|
||||
array[idx] = state.convertValue(newValue, Boolean.class);
|
||||
array[idx] = state.convertValue(newValue, BOOLEAN_TYPE_DESCRIPTOR);
|
||||
} else if (arrayComponentType == Character.TYPE) {
|
||||
char[] array = (char[]) ctx;
|
||||
checkAccess(array.length, idx);
|
||||
array[idx] = state.convertValue(newValue, Character.class);
|
||||
array[idx] = state.convertValue(newValue, CHARACTER_TYPE_DESCRIPTOR);
|
||||
} else if (arrayComponentType == Long.TYPE) {
|
||||
long[] array = (long[]) ctx;
|
||||
checkAccess(array.length, idx);
|
||||
array[idx] = state.convertValue(newValue, Long.class);
|
||||
array[idx] = state.convertValue(newValue, LONG_TYPE_DESCRIPTOR);
|
||||
} else if (arrayComponentType == Short.TYPE) {
|
||||
short[] array = (short[]) ctx;
|
||||
checkAccess(array.length, idx);
|
||||
array[idx] = state.convertValue(newValue, Short.class);
|
||||
array[idx] = state.convertValue(newValue, SHORT_TYPE_DESCRIPTOR);
|
||||
} else if (arrayComponentType == Double.TYPE) {
|
||||
double[] array = (double[]) ctx;
|
||||
checkAccess(array.length, idx);
|
||||
array[idx] = state.convertValue(newValue, Double.class);
|
||||
array[idx] = state.convertValue(newValue, DOUBLE_TYPE_DESCRIPTOR);
|
||||
} else if (arrayComponentType == Float.TYPE) {
|
||||
float[] array = (float[]) ctx;
|
||||
checkAccess(array.length, idx);
|
||||
array[idx] = state.convertValue(newValue, Float.class);
|
||||
array[idx] = state.convertValue(newValue, FLOAT_TYPE_DESCRIPTOR);
|
||||
} else if (arrayComponentType == Byte.TYPE) {
|
||||
byte[] array = (byte[]) ctx;
|
||||
checkAccess(array.length, idx);
|
||||
array[idx] = state.convertValue(newValue, Byte.class);
|
||||
array[idx] = state.convertValue(newValue, BYTE_TYPE_DESCRIPTOR);
|
||||
} else {
|
||||
Object[] array = (Object[]) ctx;
|
||||
checkAccess(array.length, idx);
|
||||
array[idx] = state.convertValue(newValue, arrayComponentType);
|
||||
array[idx] = state.convertValue(newValue, TypeDescriptor.valueOf(clazz));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
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.
|
||||
|
|
@ -26,15 +27,15 @@ import org.antlr.runtime.Token;
|
|||
*/
|
||||
public class IntLiteral extends Literal {
|
||||
|
||||
private final Integer value;
|
||||
private final TypedValue value;
|
||||
|
||||
IntLiteral(Token payload, int value) {
|
||||
super(payload);
|
||||
this.value = value;
|
||||
this.value = new TypedValue(value, INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getLiteralValue() {
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
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;
|
||||
|
|
@ -34,16 +35,16 @@ public abstract class Literal extends SpelNodeImpl {
|
|||
super(payload);
|
||||
}
|
||||
|
||||
public abstract Object getLiteralValue();
|
||||
public abstract TypedValue getLiteralValue();
|
||||
|
||||
@Override
|
||||
public final Object getValueInternal(ExpressionState state) throws SpelException {
|
||||
public final TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
return getLiteralValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getLiteralValue().toString();
|
||||
return getLiteralValue().getValue().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* Expression language AST node that represents a long integer literal.
|
||||
|
|
@ -26,15 +27,15 @@ import org.antlr.runtime.Token;
|
|||
*/
|
||||
public class LongLiteral extends Literal {
|
||||
|
||||
private final Long value;
|
||||
private final TypedValue value;
|
||||
|
||||
LongLiteral(Token payload, long value) {
|
||||
super(payload);
|
||||
this.value = value;
|
||||
this.value = new TypedValue(value, LONG_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLiteralValue() {
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ 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;
|
||||
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.SpelMessages;
|
||||
|
|
@ -48,11 +48,11 @@ public class MethodReference extends SpelNodeImpl {
|
|||
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object currentContext = state.getActiveContextObject();
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue currentContext = state.getActiveContextObject();
|
||||
Object[] arguments = new Object[getChildCount()];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
arguments[i] = getChild(i).getValueInternal(state);
|
||||
arguments[i] = getChild(i).getValueInternal(state).getValue();
|
||||
}
|
||||
if (currentContext == null) {
|
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.ATTEMPTED_METHOD_CALL_ON_NULL_CONTEXT_OBJECT,
|
||||
|
|
@ -63,7 +63,7 @@ public class MethodReference extends SpelNodeImpl {
|
|||
if (executorToUse != null) {
|
||||
try {
|
||||
return executorToUse.execute(
|
||||
state.getEvaluationContext(), state.getActiveContextObject(), arguments);
|
||||
state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments);
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
// this is OK - it may have gone stale due to a class change,
|
||||
|
|
@ -77,7 +77,7 @@ public class MethodReference extends SpelNodeImpl {
|
|||
this.cachedExecutor = executorToUse;
|
||||
try {
|
||||
return executorToUse.execute(
|
||||
state.getEvaluationContext(), state.getActiveContextObject(), arguments);
|
||||
state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments);
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
throw new SpelException(getCharPositionInLine(), ae, SpelMessages.EXCEPTION_DURING_METHOD_INVOCATION,
|
||||
|
|
@ -139,7 +139,8 @@ public class MethodReference extends SpelNodeImpl {
|
|||
protected MethodExecutor findAccessorForMethod(String name, Class<?>[] argumentTypes, ExpressionState state)
|
||||
throws SpelException {
|
||||
|
||||
Object contextObject = state.getActiveContextObject();
|
||||
TypedValue context = state.getActiveContextObject();
|
||||
Object contextObject = context.getValue();
|
||||
EvaluationContext eContext = state.getEvaluationContext();
|
||||
if (contextObject == null) {
|
||||
throw new SpelException(SpelMessages.ATTEMPTED_METHOD_CALL_ON_NULL_CONTEXT_OBJECT,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* @author Andy Clement
|
||||
|
|
@ -24,13 +26,15 @@ import org.antlr.runtime.Token;
|
|||
*/
|
||||
public class NullLiteral extends Literal {
|
||||
|
||||
private static final TypedValue NULL_TYPED_VALUE = new TypedValue(null,TypeDescriptor.NULL_TYPE_DESCRIPTOR);
|
||||
|
||||
public NullLiteral(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLiteralValue() {
|
||||
return null;
|
||||
public TypedValue getLiteralValue() {
|
||||
return NULL_TYPED_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -18,8 +18,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.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* Represents the boolean AND operation.
|
||||
|
|
@ -39,7 +41,7 @@ public class OperatorAnd extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
boolean leftValue;
|
||||
boolean rightValue;
|
||||
|
||||
|
|
@ -52,7 +54,7 @@ public class OperatorAnd extends Operator {
|
|||
}
|
||||
|
||||
if (leftValue == false) {
|
||||
return false; // no need to evaluate right operand
|
||||
return BooleanTypedValue.forValue(false); // no need to evaluate right operand
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -63,7 +65,7 @@ public class OperatorAnd extends Operator {
|
|||
throw ee;
|
||||
}
|
||||
|
||||
return /* leftValue && */rightValue;
|
||||
return /* leftValue && */BooleanTypedValue.forValue(rightValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import org.springframework.expression.TypeComparator;
|
|||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* Represents the between operator. The left operand to between must be a single value and the right operand must be a
|
||||
|
|
@ -52,9 +53,9 @@ public class OperatorBetween extends Operator {
|
|||
* @throws EvaluationException if there is a problem evaluating the expression
|
||||
*/
|
||||
@Override
|
||||
public Boolean getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state);
|
||||
Object right = getRightOperand().getValueInternal(state);
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
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(),
|
||||
SpelMessages.BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST);
|
||||
|
|
@ -64,7 +65,7 @@ public class OperatorBetween extends Operator {
|
|||
Object high = l.get(1);
|
||||
TypeComparator comparator = state.getTypeComparator();
|
||||
try {
|
||||
return (comparator.compare(left, low) >= 0 && comparator.compare(left, high) <= 0);
|
||||
return BooleanTypedValue.forValue((comparator.compare(left, low) >= 0 && comparator.compare(left, high) <= 0));
|
||||
} catch (SpelException ex) {
|
||||
ex.setPosition(getCharPositionInLine());
|
||||
throw ex;
|
||||
|
|
|
|||
|
|
@ -17,8 +17,10 @@
|
|||
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;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
|
|
@ -39,26 +41,22 @@ public class OperatorDivide extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operandOne = getLeftOperand().getValueInternal(state);
|
||||
Object operandTwo = getRightOperand().getValueInternal(state);
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operandOne = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object operandTwo = getRightOperand().getValueInternal(state).getValue();
|
||||
if (operandOne instanceof Number && operandTwo instanceof Number) {
|
||||
Number op1 = (Number) operandOne;
|
||||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() / op2.doubleValue();
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() / op2.floatValue();
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() / op2.longValue();
|
||||
}
|
||||
else { // TODO what about non-int result of the division?
|
||||
return op1.intValue() / op2.intValue();
|
||||
return new TypedValue(op1.doubleValue() / op2.doubleValue(), DOUBLE_TYPE_DESCRIPTOR);
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return new TypedValue(op1.longValue() / op2.longValue(), LONG_TYPE_DESCRIPTOR);
|
||||
} else { // TODO what about non-int result of the division?
|
||||
return new TypedValue(op1.intValue() / op2.intValue(), INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
return state.operate(Operation.DIVIDE, operandOne, operandTwo);
|
||||
Object result = state.operate(Operation.DIVIDE, operandOne, operandTwo);
|
||||
return new TypedValue(result,TypeDescriptor.forObject(result));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ 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;
|
||||
|
||||
/**
|
||||
* Implements equality operator.
|
||||
|
|
@ -38,26 +39,21 @@ public class OperatorEquality extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state);
|
||||
Object right = getRightOperand().getValueInternal(state);
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() == op2.doubleValue();
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() == op2.floatValue();
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() == op2.longValue();
|
||||
}
|
||||
else {
|
||||
return op1.intValue() == op2.intValue();
|
||||
return BooleanTypedValue.forValue(op1.doubleValue() == op2.doubleValue());
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return BooleanTypedValue.forValue(op1.longValue() == op2.longValue());
|
||||
} else {
|
||||
return BooleanTypedValue.forValue(op1.intValue() == op2.intValue());
|
||||
}
|
||||
}
|
||||
return state.getTypeComparator().compare(left, right) == 0;
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) == 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ 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;
|
||||
|
||||
/**
|
||||
* Implements greater-than operator.
|
||||
|
|
@ -38,26 +39,26 @@ public class OperatorGreaterThan extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state);
|
||||
Object right = getRightOperand().getValueInternal(state);
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() > op2.doubleValue();
|
||||
return BooleanTypedValue.forValue(op1.doubleValue() > op2.doubleValue());
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() > op2.floatValue();
|
||||
return BooleanTypedValue.forValue(op1.floatValue() > op2.floatValue());
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() > op2.longValue();
|
||||
return BooleanTypedValue.forValue(op1.longValue() > op2.longValue());
|
||||
}
|
||||
else {
|
||||
return op1.intValue() > op2.intValue();
|
||||
return BooleanTypedValue.forValue(op1.intValue() > op2.intValue());
|
||||
}
|
||||
}
|
||||
return state.getTypeComparator().compare(left, right) > 0;
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) > 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@
|
|||
* 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.EvaluationException;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* Implements greater-than-or-equal operator.
|
||||
|
|
@ -38,26 +38,26 @@ public class OperatorGreaterThanOrEqual extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state);
|
||||
Object right = getRightOperand().getValueInternal(state);
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() >= op2.doubleValue();
|
||||
return BooleanTypedValue.forValue(op1.doubleValue() >= op2.doubleValue());
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() >= op2.floatValue();
|
||||
return BooleanTypedValue.forValue(op1.floatValue() >= op2.floatValue());
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() >= op2.longValue();
|
||||
return BooleanTypedValue.forValue( op1.longValue() >= op2.longValue());
|
||||
}
|
||||
else {
|
||||
return op1.intValue() >= op2.intValue();
|
||||
return BooleanTypedValue.forValue(op1.intValue() >= op2.intValue());
|
||||
}
|
||||
}
|
||||
return state.getTypeComparator().compare(left, right) >= 0;
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) >= 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ 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;
|
||||
|
||||
/**
|
||||
* Implements the not-equal operator.
|
||||
|
|
@ -38,26 +39,21 @@ public class OperatorInequality extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state);
|
||||
Object right = getRightOperand().getValueInternal(state);
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() != op2.doubleValue();
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() != op2.floatValue();
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() != op2.longValue();
|
||||
}
|
||||
else {
|
||||
return op1.intValue() != op2.intValue();
|
||||
return BooleanTypedValue.forValue(op1.doubleValue() != op2.doubleValue());
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return BooleanTypedValue.forValue(op1.longValue() != op2.longValue());
|
||||
} else {
|
||||
return BooleanTypedValue.forValue(op1.intValue() != op2.intValue());
|
||||
}
|
||||
}
|
||||
return state.getTypeComparator().compare(left, right) != 0;
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) != 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@
|
|||
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.SpelMessages;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* The operator 'instanceof' checks if an object is of the class specified in the right hand operand,
|
||||
|
|
@ -49,19 +50,21 @@ public class OperatorInstanceof extends Operator {
|
|||
* @throws EvaluationException if there is a problem evaluating the expression
|
||||
*/
|
||||
@Override
|
||||
public Boolean getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state);
|
||||
Object right = getRightOperand().getValueInternal(state);
|
||||
if (left == null) {
|
||||
return false; // null is not an instanceof anything
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue left = getLeftOperand().getValueInternal(state);
|
||||
TypedValue right = getRightOperand().getValueInternal(state);
|
||||
Object leftValue = left.getValue();
|
||||
Object rightValue = right.getValue();
|
||||
if (leftValue == null) {
|
||||
return BooleanTypedValue.False; // null is not an instanceof anything
|
||||
}
|
||||
if (right == null || !(right instanceof Class<?>)) {
|
||||
if (rightValue == null || !(rightValue instanceof Class<?>)) {
|
||||
throw new SpelException(getRightOperand().getCharPositionInLine(),
|
||||
SpelMessages.INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND,
|
||||
(right == null ? "null" : right.getClass().getName()));
|
||||
(rightValue == null ? "null" : rightValue.getClass().getName()));
|
||||
}
|
||||
Class<?> rightClass = (Class<?>) right;
|
||||
return rightClass.isAssignableFrom(left.getClass());
|
||||
Class<?> rightClass = (Class<?>) rightValue;
|
||||
return BooleanTypedValue.forValue(rightClass.isAssignableFrom(leftValue.getClass()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ 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;
|
||||
|
||||
/**
|
||||
* Implements the less-than operator.
|
||||
|
|
@ -38,26 +39,26 @@ public class OperatorLessThan extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state);
|
||||
Object right = getRightOperand().getValueInternal(state);
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() < op2.doubleValue();
|
||||
return BooleanTypedValue.forValue(op1.doubleValue() < op2.doubleValue());
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() < op2.floatValue();
|
||||
return BooleanTypedValue.forValue(op1.floatValue() < op2.floatValue());
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() < op2.longValue();
|
||||
return BooleanTypedValue.forValue(op1.longValue() < op2.longValue());
|
||||
}
|
||||
else {
|
||||
return op1.intValue() < op2.intValue();
|
||||
return BooleanTypedValue.forValue(op1.intValue() < op2.intValue());
|
||||
}
|
||||
}
|
||||
return state.getTypeComparator().compare(left, right) < 0;
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) < 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ 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;
|
||||
|
||||
/**
|
||||
* Implements the less-than-or-equal operator.
|
||||
|
|
@ -33,26 +34,26 @@ public class OperatorLessThanOrEqual extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state);
|
||||
Object right = getRightOperand().getValueInternal(state);
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() <= op2.doubleValue();
|
||||
return BooleanTypedValue.forValue(op1.doubleValue() <= op2.doubleValue());
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() <= op2.floatValue();
|
||||
return BooleanTypedValue.forValue(op1.floatValue() <= op2.floatValue());
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() <= op2.longValue();
|
||||
return BooleanTypedValue.forValue(op1.longValue() <= op2.longValue());
|
||||
}
|
||||
else {
|
||||
return op1.intValue() <= op2.intValue();
|
||||
return BooleanTypedValue.forValue(op1.intValue() <= op2.intValue());
|
||||
}
|
||||
}
|
||||
return state.getTypeComparator().compare(left, right) <= 0;
|
||||
return BooleanTypedValue.forValue( state.getTypeComparator().compare(left, right) <= 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.springframework.expression.EvaluationException;
|
|||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* Implements the matches operator. Matches takes two operands. The first is a string and the second is a java regex. It
|
||||
|
|
@ -51,11 +52,11 @@ public class OperatorMatches extends Operator {
|
|||
* @throws EvaluationException if there is a problem evaluating the expression (e.g. the regex is invalid)
|
||||
*/
|
||||
@Override
|
||||
public Boolean getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
SpelNodeImpl leftOp = getLeftOperand();
|
||||
SpelNodeImpl rightOp = getRightOperand();
|
||||
Object left = leftOp.getValue(state, String.class);
|
||||
Object right = getRightOperand().getValueInternal(state);
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
try {
|
||||
if (!(left instanceof String)) {
|
||||
throw new SpelException(leftOp.getCharPositionInLine(),
|
||||
|
|
@ -67,7 +68,7 @@ public class OperatorMatches extends Operator {
|
|||
}
|
||||
Pattern pattern = Pattern.compile((String) right);
|
||||
Matcher matcher = pattern.matcher((String) left);
|
||||
return matcher.matches();
|
||||
return BooleanTypedValue.forValue(matcher.matches());
|
||||
}
|
||||
catch (PatternSyntaxException pse) {
|
||||
throw new SpelException(rightOp.getCharPositionInLine(), pse, SpelMessages.INVALID_PATTERN, right);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ 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;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
|
@ -49,45 +50,45 @@ public class OperatorMinus extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
SpelNodeImpl leftOp = getLeftOperand();
|
||||
SpelNodeImpl rightOp = getRightOperand();
|
||||
if (rightOp == null) {// If only one operand, then this is unary minus
|
||||
Object left = leftOp.getValueInternal(state);
|
||||
Object left = leftOp.getValueInternal(state).getValue();
|
||||
if (left instanceof Number) {
|
||||
Number n = (Number) left;
|
||||
if (left instanceof Double) {
|
||||
return 0 - n.doubleValue();
|
||||
return new TypedValue(0 - n.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (left instanceof Float) {
|
||||
return 0 - n.floatValue();
|
||||
return new TypedValue(0 - n.floatValue(),FLOAT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (left instanceof Long) {
|
||||
return 0 - n.longValue();
|
||||
return new TypedValue(0 - n.longValue(),LONG_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else {
|
||||
return 0 - n.intValue();
|
||||
return new TypedValue(0 - n.intValue(),INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
throw new SpelException(SpelMessages.CANNOT_NEGATE_TYPE, left.getClass().getName());
|
||||
}
|
||||
else {
|
||||
Object left = leftOp.getValueInternal(state);
|
||||
Object right = rightOp.getValueInternal(state);
|
||||
Object left = leftOp.getValueInternal(state).getValue();
|
||||
Object right = rightOp.getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() - op2.doubleValue();
|
||||
return new TypedValue(op1.doubleValue() - op2.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() - op2.floatValue();
|
||||
return new TypedValue(op1.floatValue() - op2.floatValue(),FLOAT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() - op2.longValue();
|
||||
return new TypedValue(op1.longValue() - op2.longValue(),LONG_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else {
|
||||
return op1.intValue() - op2.intValue();
|
||||
return new TypedValue(op1.intValue() - op2.intValue(),INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
return state.operate(Operation.SUBTRACT, left, right);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ 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;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
|
|
@ -39,23 +40,23 @@ public class OperatorModulus extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operandOne = getLeftOperand().getValueInternal(state);
|
||||
Object operandTwo = getRightOperand().getValueInternal(state);
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operandOne = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object operandTwo = getRightOperand().getValueInternal(state).getValue();
|
||||
if (operandOne instanceof Number && operandTwo instanceof Number) {
|
||||
Number op1 = (Number) operandOne;
|
||||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() % op2.doubleValue();
|
||||
return new TypedValue(op1.doubleValue() % op2.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() % op2.floatValue();
|
||||
return new TypedValue(op1.floatValue() % op2.floatValue(),FLOAT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() % op2.longValue();
|
||||
return new TypedValue(op1.longValue() % op2.longValue(),LONG_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else {
|
||||
return op1.intValue() % op2.intValue();
|
||||
return new TypedValue(op1.intValue() % op2.intValue(),INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
return state.operate(Operation.MODULUS, operandOne, operandTwo);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ 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;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
|
|
@ -50,23 +51,23 @@ public class OperatorMultiply extends Operator {
|
|||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operandOne = getLeftOperand().getValueInternal(state);
|
||||
Object operandTwo = getRightOperand().getValueInternal(state);
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operandOne = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object operandTwo = getRightOperand().getValueInternal(state).getValue();
|
||||
if (operandOne instanceof Number && operandTwo instanceof Number) {
|
||||
Number op1 = (Number) operandOne;
|
||||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() * op2.doubleValue();
|
||||
return new TypedValue(op1.doubleValue() * op2.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() * op2.floatValue();
|
||||
return new TypedValue(op1.floatValue() * op2.floatValue(),FLOAT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() * op2.longValue();
|
||||
return new TypedValue(op1.longValue() * op2.longValue(),LONG_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else {
|
||||
return op1.intValue() * op2.intValue();
|
||||
return new TypedValue(op1.intValue() * op2.intValue(),INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
else if (operandOne instanceof String && operandTwo instanceof Integer) {
|
||||
|
|
@ -75,7 +76,7 @@ public class OperatorMultiply extends Operator {
|
|||
for (int i = 0; i < repeats; i++) {
|
||||
result.append(operandOne);
|
||||
}
|
||||
return result.toString();
|
||||
return new TypedValue(result.toString(),STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
return state.operate(Operation.MULTIPLY, operandOne, operandTwo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ 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.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* Represents a NOT operation.
|
||||
|
|
@ -34,10 +35,10 @@ public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so do
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
try {
|
||||
boolean value = state.convertValue(getChild(0).getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
||||
return !value;
|
||||
return BooleanTypedValue.forValue(!value);
|
||||
}
|
||||
catch (SpelException see) {
|
||||
see.setPosition(getChild(0).getCharPositionInLine());
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ 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.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* Represents the boolean OR operation.
|
||||
|
|
@ -39,7 +40,7 @@ public class OperatorOr extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
boolean leftValue;
|
||||
boolean rightValue;
|
||||
try {
|
||||
|
|
@ -51,7 +52,7 @@ public class OperatorOr extends Operator {
|
|||
}
|
||||
|
||||
if (leftValue == true) {
|
||||
return true; // no need to evaluate right operand
|
||||
return BooleanTypedValue.True; // no need to evaluate right operand
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -62,7 +63,7 @@ public class OperatorOr extends Operator {
|
|||
throw see;
|
||||
}
|
||||
|
||||
return leftValue || rightValue;
|
||||
return BooleanTypedValue.forValue(leftValue || rightValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
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;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
|
|
@ -33,46 +33,46 @@ public class OperatorPlus extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
SpelNodeImpl leftOp = getLeftOperand();
|
||||
SpelNodeImpl rightOp = getRightOperand();
|
||||
if (rightOp == null) { // If only one operand, then this is unary plus
|
||||
Object operandOne = leftOp.getValueInternal(state);
|
||||
Object operandOne = leftOp.getValueInternal(state).getValue();
|
||||
if (operandOne instanceof Number) {
|
||||
return ((Number) operandOne).intValue();
|
||||
return new TypedValue(((Number) operandOne).intValue(),INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
return state.operate(Operation.ADD, operandOne, null);
|
||||
}
|
||||
else {
|
||||
Object operandOne = leftOp.getValueInternal(state);
|
||||
Object operandTwo = rightOp.getValueInternal(state);
|
||||
Object operandOne = leftOp.getValueInternal(state).getValue();
|
||||
Object operandTwo = rightOp.getValueInternal(state).getValue();
|
||||
if (operandOne instanceof Number && operandTwo instanceof Number) {
|
||||
Number op1 = (Number) operandOne;
|
||||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return op1.doubleValue() + op2.doubleValue();
|
||||
return new TypedValue(op1.doubleValue() + op2.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return op1.floatValue() + op2.floatValue();
|
||||
return new TypedValue(op1.floatValue() + op2.floatValue(),FLOAT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return op1.longValue() + op2.longValue();
|
||||
return new TypedValue(op1.longValue() + op2.longValue(),LONG_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else { // TODO what about overflow?
|
||||
return op1.intValue() + op2.intValue();
|
||||
return new TypedValue(op1.intValue() + op2.intValue(),INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
else if (operandOne instanceof String && operandTwo instanceof String) {
|
||||
return new StringBuilder((String) operandOne).append((String) operandTwo).toString();
|
||||
return new TypedValue(new StringBuilder((String) operandOne).append((String) operandTwo).toString(),STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
else if (operandOne instanceof String && operandTwo instanceof Integer) {
|
||||
String l = (String) operandOne;
|
||||
Integer i = (Integer) operandTwo;
|
||||
// implements character + int (ie. a + 1 = b)
|
||||
if (l.length() == 1) {
|
||||
return Character.toString((char) (l.charAt(0) + i));
|
||||
return new TypedValue(Character.toString((char) (l.charAt(0) + i)),STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
return new StringBuilder(l).append(i).toString();
|
||||
return new TypedValue(new StringBuilder(l).append(i).toString(),STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
return state.operate(Operation.ADD, operandOne, operandTwo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@
|
|||
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;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
* PlaceHolder nodes are created for tokens that come through from the grammar purely to give us additional positional
|
||||
|
|
@ -35,7 +36,7 @@ public class Placeholder extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getValueInternal(ExpressionState state) throws SpelException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.PLACEHOLDER_SHOULD_NEVER_BE_EVALUATED);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,9 @@ 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.SpelMessages;
|
||||
|
|
@ -43,9 +44,12 @@ public class Projection extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operand = state.getActiveContextObject();
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue op = state.getActiveContextObject();
|
||||
|
||||
Object operand = op.getValue();
|
||||
TypeDescriptor operandTypeDescriptor = op.getTypeDescriptor();
|
||||
|
||||
// When the input is a map, we push a special context object on the stack
|
||||
// before calling the specified operation. This special context object
|
||||
// has two fields 'key' and 'value' that refer to the map entries key
|
||||
|
|
@ -56,21 +60,21 @@ public class Projection extends SpelNodeImpl {
|
|||
List<Object> result = new ArrayList<Object>();
|
||||
for (Object k : mapdata.keySet()) {
|
||||
try {
|
||||
state.pushActiveContextObject(new KeyValuePair(k, mapdata.get(k)));
|
||||
state.pushActiveContextObject(new TypedValue(new KeyValuePair(k, mapdata.get(k)),TypeDescriptor.valueOf(KeyValuePair.class)));
|
||||
result.add(getChild(0).getValueInternal(state));
|
||||
} finally {
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else if (operand instanceof Collection) {
|
||||
return new TypedValue(result,TypeDescriptor.valueOf(Map.class)); // TODO unable to build correct type descriptor
|
||||
} else if (operand instanceof List) {
|
||||
List<Object> data = new ArrayList<Object>();
|
||||
data.addAll((Collection<?>) operand);
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
int idx = 0;
|
||||
for (Object element : data) {
|
||||
try {
|
||||
state.pushActiveContextObject(element);
|
||||
state.pushActiveContextObject(new TypedValue(element,TypeDescriptor.valueOf(op.getTypeDescriptor().getType())));
|
||||
state.enterScope("index", idx);
|
||||
result.add(getChild(0).getValueInternal(state));
|
||||
} finally {
|
||||
|
|
@ -79,7 +83,7 @@ public class Projection extends SpelNodeImpl {
|
|||
}
|
||||
idx++;
|
||||
}
|
||||
return result;
|
||||
return new TypedValue(result,op.getTypeDescriptor());
|
||||
} else {
|
||||
throw new SpelException(SpelMessages.PROJECTION_NOT_SUPPORTED_ON_TYPE, operand.getClass().getName());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ 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.SpelMessages;
|
||||
|
|
@ -49,7 +50,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws SpelException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
return readProperty(state, this.name);
|
||||
}
|
||||
|
||||
|
|
@ -75,14 +76,14 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
* @return the value of the property
|
||||
* @throws SpelException if any problem accessing the property or it cannot be found
|
||||
*/
|
||||
private Object readProperty(ExpressionState state, String name) throws SpelException {
|
||||
Object contextObject = state.getActiveContextObject();
|
||||
private TypedValue readProperty(ExpressionState state, String name) throws SpelException {
|
||||
TypedValue contextObject = state.getActiveContextObject();
|
||||
EvaluationContext eContext = state.getEvaluationContext();
|
||||
|
||||
PropertyAccessor accessorToUse = this.cachedReadAccessor;
|
||||
if (accessorToUse != null) {
|
||||
try {
|
||||
return accessorToUse.read(state.getEvaluationContext(), contextObject, name);
|
||||
return accessorToUse.read(state.getEvaluationContext(), contextObject.getValue(), name);
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
// this is OK - it may have gone stale due to a class change,
|
||||
|
|
@ -91,7 +92,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
}
|
||||
}
|
||||
|
||||
Class<?> contextObjectClass = getObjectClass(contextObject);
|
||||
Class<?> contextObjectClass = getObjectClass(contextObject.getValue());
|
||||
List<PropertyAccessor> accessorsToTry = getPropertyAccessorsToTry(contextObjectClass, state);
|
||||
|
||||
// Go through the accessors that may be able to resolve it. If they are a cacheable accessor then
|
||||
|
|
@ -100,9 +101,9 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
if (accessorsToTry != null) {
|
||||
try {
|
||||
for (PropertyAccessor accessor : accessorsToTry) {
|
||||
if (accessor.canRead(eContext, contextObject, name)) {
|
||||
if (accessor.canRead(eContext, contextObject.getValue(), name)) {
|
||||
this.cachedReadAccessor = accessor;
|
||||
return accessor.read(eContext, contextObject, name);
|
||||
return accessor.read(eContext, contextObject.getValue(), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -115,13 +116,13 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
private void writeProperty(ExpressionState state, String name, Object newValue) throws SpelException {
|
||||
Object contextObject = state.getActiveContextObject();
|
||||
TypedValue contextObject = state.getActiveContextObject();
|
||||
EvaluationContext eContext = state.getEvaluationContext();
|
||||
|
||||
PropertyAccessor accessorToUse = this.cachedWriteAccessor;
|
||||
if (accessorToUse != null) {
|
||||
try {
|
||||
accessorToUse.write(state.getEvaluationContext(), contextObject, name, newValue);
|
||||
accessorToUse.write(state.getEvaluationContext(), contextObject.getValue(), name, newValue);
|
||||
return;
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
|
|
@ -131,15 +132,15 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
}
|
||||
}
|
||||
|
||||
Class<?> contextObjectClass = getObjectClass(contextObject);
|
||||
Class<?> contextObjectClass = getObjectClass(contextObject.getValue());
|
||||
|
||||
List<PropertyAccessor> accessorsToTry = getPropertyAccessorsToTry(contextObjectClass, state);
|
||||
if (accessorsToTry != null) {
|
||||
try {
|
||||
for (PropertyAccessor accessor : accessorsToTry) {
|
||||
if (accessor.canWrite(eContext, contextObject, name)) {
|
||||
if (accessor.canWrite(eContext, contextObject.getValue(), name)) {
|
||||
this.cachedWriteAccessor = accessor;
|
||||
accessor.write(eContext, contextObject, name, newValue);
|
||||
accessor.write(eContext, contextObject.getValue(), name, newValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -153,7 +154,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
public boolean isWritableProperty(String name, ExpressionState state) throws SpelException {
|
||||
Object contextObject = state.getActiveContextObject();
|
||||
Object contextObject = state.getActiveContextObject().getValue();
|
||||
EvaluationContext eContext = state.getEvaluationContext();
|
||||
if (contextObject == null) {
|
||||
throw new SpelException(SpelMessages.ATTEMPTED_PROPERTY_FIELD_REF_ON_NULL_CONTEXT_OBJECT, name);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
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;
|
||||
|
||||
/**
|
||||
|
|
@ -39,7 +39,7 @@ public class QualifiedIdentifier extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
// Cache the concatenation of child identifiers
|
||||
if (this.value == null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
|
@ -47,11 +47,11 @@ public class QualifiedIdentifier extends SpelNodeImpl {
|
|||
if (i > 0) {
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(getChild(i).getValueInternal(state));
|
||||
sb.append(getChild(i).getValueInternal(state).getValue());
|
||||
}
|
||||
this.value = sb.toString();
|
||||
}
|
||||
return this.value;
|
||||
return new TypedValue(this.value,STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* @author Andy Clement
|
||||
|
|
@ -24,15 +25,15 @@ import org.antlr.runtime.Token;
|
|||
*/
|
||||
public class RealLiteral extends Literal {
|
||||
|
||||
private final Double value;
|
||||
private final TypedValue value;
|
||||
|
||||
public RealLiteral(Token payload) {
|
||||
super(payload);
|
||||
value = Double.parseDouble(payload.getText());
|
||||
value = new TypedValue(Double.parseDouble(payload.getText()),DOUBLE_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getLiteralValue() {
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,9 @@ 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.SpelMessages;
|
||||
|
|
@ -51,15 +52,17 @@ public class Selection extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operand = state.getActiveContextObject();
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue op = state.getActiveContextObject();
|
||||
Object operand = op.getValue();
|
||||
|
||||
SpelNodeImpl selectionCriteria = getChild(0);
|
||||
if (operand instanceof Map) {
|
||||
Map<?, ?> mapdata = (Map<?, ?>) operand;
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
for (Object k : mapdata.keySet()) {
|
||||
try {
|
||||
Object kvpair = new KeyValuePair(k, mapdata.get(k));
|
||||
TypedValue kvpair = new TypedValue(new KeyValuePair(k, mapdata.get(k)),TypeDescriptor.valueOf(KeyValuePair.class));
|
||||
state.pushActiveContextObject(kvpair);
|
||||
Object o = selectionCriteria.getValueInternal(state);
|
||||
if (o instanceof Boolean) {
|
||||
|
|
@ -79,10 +82,10 @@ public class Selection extends SpelNodeImpl {
|
|||
return null;
|
||||
}
|
||||
if (variant == LAST) {
|
||||
return result.get(result.size() - 1);
|
||||
return new TypedValue(result.get(result.size() - 1),TypeDescriptor.valueOf(op.getTypeDescriptor().getElementType()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return new TypedValue(result,op.getTypeDescriptor());
|
||||
} else if (operand instanceof Collection) {
|
||||
List<Object> data = new ArrayList<Object>();
|
||||
data.addAll((Collection<?>) operand);
|
||||
|
|
@ -90,13 +93,13 @@ public class Selection extends SpelNodeImpl {
|
|||
int idx = 0;
|
||||
for (Object element : data) {
|
||||
try {
|
||||
state.pushActiveContextObject(element);
|
||||
state.pushActiveContextObject(new TypedValue(element,TypeDescriptor.valueOf(op.getTypeDescriptor().getElementType())));
|
||||
state.enterScope("index", idx);
|
||||
Object o = selectionCriteria.getValueInternal(state);
|
||||
Object o = selectionCriteria.getValueInternal(state).getValue();
|
||||
if (o instanceof Boolean) {
|
||||
if (((Boolean) o).booleanValue() == true) {
|
||||
if (variant == FIRST)
|
||||
return element;
|
||||
return new TypedValue(element,TypeDescriptor.valueOf(op.getTypeDescriptor().getElementType()));
|
||||
result.add(element);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -113,9 +116,9 @@ public class Selection extends SpelNodeImpl {
|
|||
return null;
|
||||
}
|
||||
if (variant == LAST) {
|
||||
return result.get(result.size() - 1);
|
||||
return new TypedValue(result.get(result.size() - 1),TypeDescriptor.valueOf(op.getTypeDescriptor().getElementType()));
|
||||
}
|
||||
return result;
|
||||
return new TypedValue(result,op.getTypeDescriptor());
|
||||
} else {
|
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.INVALID_TYPE_FOR_SELECTION,
|
||||
(operand == null ? "null" : operand.getClass().getName()));
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import java.io.Serializable;
|
|||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.antlr.runtime.tree.CommonTree;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
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;
|
||||
|
|
@ -36,10 +36,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
|||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Serializable {
|
||||
|
||||
protected static TypeDescriptor BOOLEAN_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Boolean.class);
|
||||
protected static TypeDescriptor INTEGER_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Integer.class);
|
||||
public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Serializable, CommonTypeDescriptors {
|
||||
|
||||
/**
|
||||
* The Antlr parser uses this constructor to build SpelNodes.
|
||||
|
|
@ -51,7 +48,7 @@ public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Seria
|
|||
|
||||
public final Object getValue(ExpressionState expressionState) throws EvaluationException {
|
||||
if (expressionState != null) {
|
||||
return getValueInternal(expressionState);
|
||||
return getValueInternal(expressionState).getValue();
|
||||
}
|
||||
else {
|
||||
return getValue(new ExpressionState(new StandardEvaluationContext()));
|
||||
|
|
@ -88,7 +85,7 @@ public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Seria
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final <T> T getValue(ExpressionState state, Class<T> desiredReturnType) throws EvaluationException {
|
||||
Object result = getValueInternal(state);
|
||||
Object result = getValueInternal(state).getValue();
|
||||
if (result != null && desiredReturnType != null) {
|
||||
Class<?> resultType = result.getClass();
|
||||
if (desiredReturnType.isAssignableFrom(resultType)) {
|
||||
|
|
@ -105,7 +102,7 @@ public abstract class SpelNodeImpl extends CommonTree implements SpelNode, Seria
|
|||
}
|
||||
|
||||
|
||||
public abstract Object getValueInternal(ExpressionState expressionState) throws EvaluationException;
|
||||
public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException;
|
||||
|
||||
public abstract String toStringAST();
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* @author Andy Clement
|
||||
|
|
@ -25,24 +26,24 @@ import org.antlr.runtime.Token;
|
|||
*/
|
||||
public class StringLiteral extends Literal {
|
||||
|
||||
private final String value;
|
||||
private final TypedValue value;
|
||||
|
||||
public StringLiteral(Token payload) {
|
||||
super(payload);
|
||||
String val = payload.getText();
|
||||
// TODO should these have been skipped being created by the parser rules? or not?
|
||||
val = val.substring(1, val.length() - 1);
|
||||
this.value = val.replaceAll("''", "'");
|
||||
this.value = new TypedValue(val.replaceAll("''", "'"),STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLiteralValue() {
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "'" + getLiteralValue() + "'";
|
||||
return "'" + getLiteralValue().getValue() + "'";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
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;
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ public class Ternary extends SpelNodeImpl {
|
|||
* executing the chosen alternative
|
||||
*/
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Boolean value = getChild(0).getValue(state, Boolean.class);
|
||||
try {
|
||||
if (Boolean.TRUE.equals(value)) {
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
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;
|
||||
|
||||
|
|
@ -34,17 +34,17 @@ public class TypeReference extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
// TODO possible optimization here if we cache the discovered type reference, but can we do that?
|
||||
String typename = (String) getChild(0).getValueInternal(state);
|
||||
String typename = (String) getChild(0).getValueInternal(state).getValue();
|
||||
if (typename.indexOf(".") == -1 && Character.isLowerCase(typename.charAt(0))) {
|
||||
TypeCode tc = TypeCode.forName(typename);
|
||||
if (tc != TypeCode.OBJECT) {
|
||||
// it is a primitive type
|
||||
return tc.getType();
|
||||
return new TypedValue(tc.getType(),CLASS_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
return state.findType(typename);
|
||||
return new TypedValue(state.findType(typename),CLASS_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
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;
|
||||
|
|
@ -44,14 +44,14 @@ public class VariableReference extends SpelNodeImpl {
|
|||
|
||||
|
||||
@Override
|
||||
public Object getValueInternal(ExpressionState state) throws SpelException {
|
||||
public TypedValue getValueInternal(ExpressionState state) throws SpelException {
|
||||
if (this.name.equals(THIS)) {
|
||||
return state.getActiveContextObject();
|
||||
}
|
||||
if (this.name.equals(ROOT)) {
|
||||
return state.getRootContextObject();
|
||||
}
|
||||
Object result = state.lookupVariable(this.name);
|
||||
TypedValue result = state.lookupVariable(this.name);
|
||||
if (result == null) {
|
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.VARIABLE_NOT_FOUND, this.name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ast.SpelNodeImpl;
|
||||
|
||||
/**
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BooleanTypedValue extends TypedValue {
|
||||
|
||||
public static final BooleanTypedValue True = new BooleanTypedValue(true);
|
||||
public static final BooleanTypedValue False = new BooleanTypedValue(false);
|
||||
|
||||
private BooleanTypedValue(boolean b) {
|
||||
super(b,SpelNodeImpl.BOOLEAN_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
public static BooleanTypedValue forValue(boolean b) {
|
||||
if (b) {
|
||||
return True;
|
||||
} else {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,9 +18,11 @@ package org.springframework.expression.spel.support;
|
|||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.ConstructorExecutor;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* A simple ConstructorExecutor implementation that runs a constructor using reflective invocation.
|
||||
|
|
@ -42,7 +44,7 @@ class ReflectiveConstructorExecutor implements ConstructorExecutor {
|
|||
this.argsRequiringConversion = argsRequiringConversion;
|
||||
}
|
||||
|
||||
public Object execute(EvaluationContext context, Object... arguments) throws AccessException {
|
||||
public TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException {
|
||||
try {
|
||||
if (argsRequiringConversion != null && arguments != null) {
|
||||
ReflectionHelper.convertArguments(c.getParameterTypes(), c.isVarArgs(),
|
||||
|
|
@ -54,7 +56,7 @@ class ReflectiveConstructorExecutor implements ConstructorExecutor {
|
|||
if (!c.isAccessible()) {
|
||||
c.setAccessible(true);
|
||||
}
|
||||
return c.newInstance(arguments);
|
||||
return new TypedValue(c.newInstance(arguments),TypeDescriptor.valueOf(c.getClass()));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new AccessException("Problem invoking constructor: " + c, ex);
|
||||
|
|
|
|||
|
|
@ -18,9 +18,12 @@ package org.springframework.expression.spel.support;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.MethodExecutor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -42,7 +45,7 @@ class ReflectiveMethodExecutor implements MethodExecutor {
|
|||
}
|
||||
|
||||
|
||||
public Object execute(EvaluationContext context, Object target, Object... arguments) throws AccessException {
|
||||
public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException {
|
||||
try {
|
||||
if (this.argsRequiringConversion != null && arguments != null) {
|
||||
ReflectionHelper.convertArguments(this.method.getParameterTypes(), this.method.isVarArgs(),
|
||||
|
|
@ -52,7 +55,7 @@ class ReflectiveMethodExecutor implements MethodExecutor {
|
|||
arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.method.getParameterTypes(), arguments);
|
||||
}
|
||||
ReflectionUtils.makeAccessible(this.method);
|
||||
return this.method.invoke(target, arguments);
|
||||
return new TypedValue(this.method.invoke(target, arguments), new TypeDescriptor(new MethodParameter(method,-1)));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new AccessException("Problem invoking method: " + this.method, ex);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.springframework.expression.AccessException;
|
|||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
|
@ -85,7 +86,7 @@ public class ReflectivePropertyResolver implements PropertyAccessor {
|
|||
return false;
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -95,7 +96,7 @@ public class ReflectivePropertyResolver implements PropertyAccessor {
|
|||
if (target instanceof Class) {
|
||||
throw new AccessException("Cannot access length on array class itself");
|
||||
}
|
||||
return Array.getLength(target);
|
||||
return new TypedValue(Array.getLength(target),TypeDescriptor.valueOf(Integer.TYPE));
|
||||
}
|
||||
|
||||
CacheKey cacheKey = new CacheKey(type, name);
|
||||
|
|
@ -113,7 +114,8 @@ public class ReflectivePropertyResolver implements PropertyAccessor {
|
|||
if (method != null) {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
return method.invoke(target);
|
||||
TypeDescriptor resultTypeDescriptor = new TypeDescriptor(new MethodParameter(method,-1));
|
||||
return new TypedValue(method.invoke(target),resultTypeDescriptor);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new AccessException("Unable to access property '" + name + "' through getter", ex);
|
||||
|
|
@ -133,7 +135,7 @@ public class ReflectivePropertyResolver implements PropertyAccessor {
|
|||
if (field != null) {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return field.get(target);
|
||||
return new TypedValue(field.get(target),new TypeDescriptor(field));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new AccessException("Unable to access field: " + name, ex);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.ConstructorResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.MethodResolver;
|
||||
|
|
@ -30,6 +31,7 @@ import org.springframework.expression.PropertyAccessor;
|
|||
import org.springframework.expression.TypeComparator;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.TypeLocator;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
|
@ -43,7 +45,7 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
public class StandardEvaluationContext implements EvaluationContext {
|
||||
|
||||
private Object rootObject;
|
||||
private TypedValue rootObject;
|
||||
|
||||
private final Map<String, Object> variables = new HashMap<String, Object>();
|
||||
|
||||
|
|
@ -68,10 +70,14 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
}
|
||||
|
||||
public void setRootObject(Object rootObject) {
|
||||
this.rootObject = rootObject;
|
||||
this.rootObject = new TypedValue(rootObject,TypeDescriptor.forObject(rootObject));
|
||||
}
|
||||
|
||||
public Object getRootObject() {
|
||||
public void setRootObject(Object rootObject, TypeDescriptor typeDescriptor) {
|
||||
this.rootObject = new TypedValue(rootObject,typeDescriptor);
|
||||
}
|
||||
|
||||
public TypedValue getRootObject() {
|
||||
return this.rootObject;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,12 +23,14 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ParseException;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
|
|
@ -235,6 +237,7 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
|
|||
private static class FruitColourAccessor implements PropertyAccessor {
|
||||
|
||||
private static Map<String,Color> propertyMap = new HashMap<String,Color>();
|
||||
private static TypeDescriptor mapElementTypeDescriptor = TypeDescriptor.valueOf(Color.class);
|
||||
|
||||
static {
|
||||
propertyMap.put("banana",Color.yellow);
|
||||
|
|
@ -253,8 +256,8 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
|
|||
return propertyMap.containsKey(name);
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return propertyMap.get(name);
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(propertyMap.get(name),mapElementTypeDescriptor);
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
|
@ -292,8 +295,8 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
|
|||
return propertyMap.containsKey(name);
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return propertyMap.get(name);
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(propertyMap.get(name),TypeDescriptor.valueOf(Color.class));
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ import org.springframework.expression.AccessException;
|
|||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
|
||||
import org.springframework.expression.spel.ast.CommonTypeDescriptors;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
|
|
@ -67,8 +69,8 @@ public class MapAccessTests extends ExpressionTestCase {
|
|||
return (((Map) target).containsKey(name));
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return ((Map) target).get(name);
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(((Map) target).get(name),CommonTypeDescriptors.OBJECT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import org.springframework.expression.spel.ast.Operator;
|
||||
|
||||
/**
|
||||
* Tests the evaluation of expressions using relational operators.
|
||||
*
|
||||
|
|
@ -48,6 +50,12 @@ public class OperatorTests extends ExpressionTestCase {
|
|||
evaluate("6 == 6", true, Boolean.class);
|
||||
}
|
||||
|
||||
public void testNotEqual() {
|
||||
evaluate("3 != 5", true, Boolean.class);
|
||||
evaluate("5 != 3", true, Boolean.class);
|
||||
evaluate("6 != 6", false, Boolean.class);
|
||||
}
|
||||
|
||||
public void testGreaterThanOrEqual() {
|
||||
evaluate("3 >= 5", false, Boolean.class);
|
||||
evaluate("5 >= 3", true, Boolean.class);
|
||||
|
|
@ -79,6 +87,10 @@ public class OperatorTests extends ExpressionTestCase {
|
|||
evaluate("3 % 2", 1, Integer.class);
|
||||
}
|
||||
|
||||
public void testDivide() {
|
||||
evaluate("4L/2L",2L,Long.class);
|
||||
}
|
||||
|
||||
public void testMathOperatorDivide_ConvertToDouble() {
|
||||
evaluateAndAskForReturnType("8/4", new Double(2.0), Double.class);
|
||||
}
|
||||
|
|
@ -92,6 +104,10 @@ public class OperatorTests extends ExpressionTestCase {
|
|||
// }
|
||||
|
||||
public void testDoubles() {
|
||||
evaluate("3.0d == 5.0d", false, Boolean.class);
|
||||
evaluate("3.0d == 3.0d", true, Boolean.class);
|
||||
evaluate("3.0d != 5.0d", true, Boolean.class);
|
||||
evaluate("3.0d != 3.0d", false, Boolean.class);
|
||||
evaluate("3.0d + 5.0d", 8.0d, Double.class);
|
||||
evaluate("3.0d - 5.0d", -2.0d, Double.class);
|
||||
evaluate("3.0d * 5.0d", 15.0d, Double.class);
|
||||
|
|
@ -100,6 +116,10 @@ public class OperatorTests extends ExpressionTestCase {
|
|||
}
|
||||
|
||||
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);
|
||||
|
|
@ -107,6 +127,17 @@ public class OperatorTests extends ExpressionTestCase {
|
|||
evaluate("5.0f % 3.1f", 1.9d, Double.class);
|
||||
}
|
||||
|
||||
public void testOperatorStrings() throws Exception {
|
||||
Operator node = getOperatorNode((SpelExpression)parser.parseExpression("1==3"));
|
||||
assertEquals("==",node.getOperatorName());
|
||||
|
||||
node = getOperatorNode((SpelExpression)parser.parseExpression("1!=3"));
|
||||
assertEquals("!=",node.getOperatorName());
|
||||
|
||||
node = getOperatorNode((SpelExpression)parser.parseExpression("3/3"));
|
||||
assertEquals("/",node.getOperatorName());
|
||||
}
|
||||
|
||||
public void testMixedOperands_FloatsAndDoubles() {
|
||||
evaluate("3.0d + 5.0f", 8.0d, Double.class);
|
||||
evaluate("3.0D - 5.0f", -2.0d, Double.class);
|
||||
|
|
@ -125,4 +156,37 @@ public class OperatorTests extends ExpressionTestCase {
|
|||
evaluate("5.5D % 3", 2.5, Double.class);
|
||||
}
|
||||
|
||||
public void testStrings() {
|
||||
evaluate("'abc' == 'abc'",true,Boolean.class);
|
||||
evaluate("'abc' == 'def'",false,Boolean.class);
|
||||
evaluate("'abc' != 'abc'",false,Boolean.class);
|
||||
evaluate("'abc' != 'def'",true,Boolean.class);
|
||||
}
|
||||
|
||||
public void testLongs() {
|
||||
evaluate("3L == 4L", false, Boolean.class);
|
||||
evaluate("3L == 3L", true, Boolean.class);
|
||||
evaluate("3L != 4L", true, Boolean.class);
|
||||
evaluate("3L != 3L", false, Boolean.class);
|
||||
}
|
||||
|
||||
private Operator getOperatorNode(SpelExpression e) {
|
||||
SpelNode node = e.getAST();
|
||||
return (Operator)findNode(node,Operator.class);
|
||||
}
|
||||
|
||||
private SpelNode findNode(SpelNode node, Class<Operator> clazz) {
|
||||
if (clazz.isAssignableFrom(node.getClass())) {
|
||||
return node;
|
||||
}
|
||||
int childCount = node.getChildCount();
|
||||
for (int i=0;i<childCount;i++) {
|
||||
SpelNode possible = findNode(node.getChild(i),clazz);
|
||||
if (possible!=null) {
|
||||
return possible;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ import junit.framework.TestCase;
|
|||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
|
||||
import org.springframework.expression.spel.ast.ConstructorReference;
|
||||
import org.springframework.expression.spel.ast.PropertyOrFieldReference;
|
||||
|
||||
/**
|
||||
* Tests the evaluation of real expressions in a real context.
|
||||
|
|
@ -31,7 +29,7 @@ import org.springframework.expression.spel.ast.PropertyOrFieldReference;
|
|||
*/
|
||||
public class PerformanceTests extends TestCase {
|
||||
|
||||
public static final int ITERATIONS = 100000;
|
||||
public static final int ITERATIONS = 10000;
|
||||
public static final boolean report = true;
|
||||
|
||||
private static SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser();
|
||||
|
|
@ -41,6 +39,15 @@ public class PerformanceTests extends TestCase {
|
|||
long starttime = 0;
|
||||
long endtime = 0;
|
||||
|
||||
// warmup
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
Expression expr = parser.parseExpression("placeOfBirth.city");
|
||||
if (expr == null) {
|
||||
fail("Parser returned null for expression");
|
||||
}
|
||||
Object value = expr.getValue(eContext);
|
||||
}
|
||||
|
||||
starttime = System.currentTimeMillis();
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
Expression expr = parser.parseExpression("placeOfBirth.city");
|
||||
|
|
@ -74,6 +81,15 @@ public class PerformanceTests extends TestCase {
|
|||
public void testPerformanceOfMethodAccess() throws Exception {
|
||||
long starttime = 0;
|
||||
long endtime = 0;
|
||||
|
||||
// warmup
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()");
|
||||
if (expr == null) {
|
||||
fail("Parser returned null for expression");
|
||||
}
|
||||
Object value = expr.getValue(eContext);
|
||||
}
|
||||
|
||||
starttime = System.currentTimeMillis();
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ import org.springframework.expression.EvaluationContext;
|
|||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
|
||||
import org.springframework.expression.spel.ast.CommonTypeDescriptors;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
|
|
@ -57,7 +59,7 @@ public class PropertyAccessTests extends ExpressionTestCase {
|
|||
// any 'default' ones
|
||||
ctx.addPropertyAccessor(new StringyPropertyAccessor());
|
||||
Expression expr = parser.parseExpression("new String('hello').flibbles");
|
||||
Integer i = (Integer) expr.getValue(ctx, Integer.class);
|
||||
Integer i = expr.getValue(ctx, Integer.class);
|
||||
assertEquals((int) i, 7);
|
||||
|
||||
// The reflection one will be used for other properties...
|
||||
|
|
@ -67,7 +69,7 @@ public class PropertyAccessTests extends ExpressionTestCase {
|
|||
|
||||
expr = parser.parseExpression("new String('hello').flibbles");
|
||||
expr.setValue(ctx, 99);
|
||||
i = (Integer) expr.getValue(ctx, Integer.class);
|
||||
i = expr.getValue(ctx, Integer.class);
|
||||
assertEquals((int) i, 99);
|
||||
|
||||
// Cannot set it to a string value
|
||||
|
|
@ -103,10 +105,10 @@ public class PropertyAccessTests extends ExpressionTestCase {
|
|||
return (name.equals("flibbles"));
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
if (!name.equals("flibbles"))
|
||||
throw new RuntimeException("Assertion Failed! name should be flibbles");
|
||||
return flibbles;
|
||||
return new TypedValue(flibbles,CommonTypeDescriptors.STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
|
||||
public void write(EvaluationContext context, Object target, String name, Object newValue)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.springframework.expression.spel;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
|
|
@ -27,6 +28,7 @@ import org.springframework.expression.MethodExecutor;
|
|||
import org.springframework.expression.MethodResolver;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
|
||||
import org.springframework.expression.spel.support.ReflectionHelper;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
|
@ -84,11 +86,11 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
|
|||
ctx.setRootObject(null);
|
||||
|
||||
pAccessor.setPerson(new Person("Andy"));
|
||||
value = (Boolean)expr.getValue(ctx,Boolean.class);
|
||||
value = expr.getValue(ctx,Boolean.class);
|
||||
assertTrue(value);
|
||||
|
||||
pAccessor.setPerson(new Person("Christian"));
|
||||
value = (Boolean)expr.getValue(ctx,Boolean.class);
|
||||
value = expr.getValue(ctx,Boolean.class);
|
||||
assertFalse(value);
|
||||
}
|
||||
|
||||
|
|
@ -210,8 +212,8 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
|
|||
return name.equals("principal");
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new Principal();
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(new Principal(),TypeDescriptor.valueOf(Principal.class));
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
|
@ -240,8 +242,8 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
|
|||
return name.equals("p");
|
||||
}
|
||||
|
||||
public Object read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return activePerson;
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(activePerson,TypeDescriptor.valueOf(Person.class));
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
|
@ -269,7 +271,7 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
|
|||
this.tc = typeConverter;
|
||||
}
|
||||
|
||||
public Object execute(EvaluationContext context, Object target, Object... arguments)
|
||||
public TypedValue execute(EvaluationContext context, Object target, Object... arguments)
|
||||
throws AccessException {
|
||||
try {
|
||||
Method m = HasRoleExecutor.class.getMethod("hasRole", String[].class);
|
||||
|
|
@ -280,7 +282,7 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
|
|||
if (m.isVarArgs()) {
|
||||
args = ReflectionHelper.setupArgumentsForVarargsInvocation(m.getParameterTypes(), args);
|
||||
}
|
||||
return m.invoke(null, args);
|
||||
return new TypedValue(m.invoke(null, args), new TypeDescriptor(new MethodParameter(m,-1)));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new AccessException("Problem invoking hasRole", ex);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package org.springframework.expression.spel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
|
|
@ -77,10 +79,15 @@ public class SetValueTests extends ExpressionTestCase {
|
|||
setValue("placesLivedList[0]", new PlaceOfBirth("Wien"));
|
||||
}
|
||||
|
||||
public void testSetGenericListElementValueTypeCoersion() {
|
||||
setValue("placesLivedList[0]", "Wien");
|
||||
public void testSetGenericListElementValueTypeCoersionFail() {
|
||||
// no type converter registered for String > PlaceOfBirth
|
||||
setValueExpectError("placesLivedList[0]", "Wien");
|
||||
}
|
||||
|
||||
public void testSetGenericListElementValueTypeCoersionOK() {
|
||||
setValue("booleanList[0]", "true", Boolean.TRUE);
|
||||
}
|
||||
|
||||
public void testSetListElementNestedValue() {
|
||||
setValue("placesLived[0].city", "Wien");
|
||||
}
|
||||
|
|
@ -106,6 +113,46 @@ public class SetValueTests extends ExpressionTestCase {
|
|||
setValue("SomeProperty", "true", Boolean.TRUE);
|
||||
}
|
||||
|
||||
public void testAssign() throws Exception {
|
||||
StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
|
||||
Expression e = parse("publicName='Andy'");
|
||||
assertFalse(e.isWritable(eContext));
|
||||
assertEquals("Andy",e.getValue(eContext));
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing the coercion of both the keys and the values to the correct type
|
||||
*/
|
||||
public void testSetGenericMapElementRequiresCoercion() throws Exception {
|
||||
StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
|
||||
Expression e = parse("mapOfStringToBoolean[42]");
|
||||
assertNull(e.getValue(eContext));
|
||||
|
||||
// Key should be coerced to string representation of 42
|
||||
e.setValue(eContext, "true");
|
||||
|
||||
// All keys should be strings
|
||||
Set ks = parse("mapOfStringToBoolean.keySet()").getValue(eContext,Set.class);
|
||||
for (Object o: ks) {
|
||||
assertEquals(String.class,o.getClass());
|
||||
}
|
||||
|
||||
// All values should be booleans
|
||||
Collection vs = parse("mapOfStringToBoolean.values()").getValue(eContext,Collection.class);
|
||||
for (Object o: vs) {
|
||||
assertEquals(Boolean.class,o.getClass());
|
||||
}
|
||||
|
||||
// One final test check coercion on the key for a map lookup
|
||||
Object o = e.getValue(eContext);
|
||||
assertEquals(Boolean.TRUE,o);
|
||||
}
|
||||
|
||||
|
||||
private Expression parse(String expressionString) throws Exception {
|
||||
return parser.parseExpression(expressionString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call setValue() but expect it to fail.
|
||||
*/
|
||||
|
|
@ -167,7 +214,12 @@ public class SetValueTests extends ExpressionTestCase {
|
|||
StandardEvaluationContext lContext = TestScenarioCreator.getTestEvaluationContext();
|
||||
assertTrue("Expression is not writeable but should be", e.isWritable(lContext));
|
||||
e.setValue(lContext, value);
|
||||
assertEquals("Retrieved value was not equal to set value", expectedValue, e.getValue(lContext));
|
||||
Object a = expectedValue;
|
||||
Object b = e.getValue(lContext);
|
||||
if (!a.equals(b)) {
|
||||
fail("Not the same: ["+a+"] type="+a.getClass()+" ["+b+"] type="+b.getClass());
|
||||
// assertEquals("Retrieved value was not equal to set value", expectedValue, e.getValue(lContext));
|
||||
}
|
||||
} catch (EvaluationException ee) {
|
||||
ee.printStackTrace();
|
||||
fail("Unexpected Exception: " + ee.getMessage());
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import java.util.Map;
|
|||
@SuppressWarnings("unused")
|
||||
public class Inventor {
|
||||
private String name;
|
||||
public String publicName;
|
||||
private PlaceOfBirth placeOfBirth;
|
||||
Date birthdate;
|
||||
private int sinNumber;
|
||||
|
|
@ -23,6 +24,8 @@ public class Inventor {
|
|||
public boolean publicBoolean;
|
||||
private boolean accessedThroughGetSet;
|
||||
public List<Integer> listOfInteger = new ArrayList<Integer>();
|
||||
public List<Boolean> booleanList = new ArrayList<Boolean>();
|
||||
public Map<String,Boolean> mapOfStringToBoolean = new HashMap<String,Boolean>();
|
||||
|
||||
public Inventor(String name, Date birthdate, String nationality) {
|
||||
this.name = name;
|
||||
|
|
@ -37,6 +40,8 @@ public class Inventor {
|
|||
testMap.put("friday", "freitag");
|
||||
testMap.put("saturday", "samstag");
|
||||
testMap.put("sunday", "sonntag");
|
||||
booleanList.add(false);
|
||||
booleanList.add(false);
|
||||
}
|
||||
|
||||
public void setPlaceOfBirth(PlaceOfBirth placeOfBirth2) {
|
||||
|
|
|
|||
|
|
@ -21,4 +21,16 @@ public class PlaceOfBirth {
|
|||
return i*2;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof PlaceOfBirth)) {
|
||||
return false;
|
||||
}
|
||||
PlaceOfBirth oPOB = (PlaceOfBirth)o;
|
||||
return (city.equals(oPOB.city));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return city.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue