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