Polish SpEL code
This commit is contained in:
parent
4830ea6065
commit
e83bdda7d5
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,13 +19,15 @@ package org.springframework.expression;
|
|||
|
||||
// TODO Is the resolver/executor model too pervasive in this package?
|
||||
/**
|
||||
* Executors are built by resolvers and can be cached by the infrastructure to repeat an operation quickly without going
|
||||
* back to the resolvers. For example, the particular constructor to run on a class may be discovered by the reflection
|
||||
* constructor resolver - it will then build a ConstructorExecutor that executes that constructor and the
|
||||
* ConstructorExecutor can be reused without needing to go back to the resolver to discover the constructor again.
|
||||
* Executors are built by resolvers and can be cached by the infrastructure to repeat an
|
||||
* operation quickly without going back to the resolvers. For example, the particular
|
||||
* constructor to run on a class may be discovered by the reflection constructor resolver
|
||||
* - it will then build a ConstructorExecutor that executes that constructor and the
|
||||
* ConstructorExecutor can be reused without needing to go back to the resolver to
|
||||
* discover the constructor again.
|
||||
*
|
||||
* They can become stale, and in that case should throw an AccessException - this will cause the infrastructure to go
|
||||
* back to the resolvers to ask for a new one.
|
||||
* <p>They can become stale, and in that case should throw an AccessException - this will
|
||||
* cause the infrastructure to go back to the resolvers to ask for a new one.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -34,11 +36,13 @@ public interface ConstructorExecutor {
|
|||
|
||||
/**
|
||||
* Execute a constructor in the specified context using the specified arguments.
|
||||
*
|
||||
* @param context the evaluation context in which the command is being executed
|
||||
* @param arguments the arguments to the constructor call, should match (in terms of number and type) whatever the
|
||||
* command will need to run
|
||||
* @param arguments the arguments to the constructor call, should match (in terms of
|
||||
* number and type) whatever the command will need to run
|
||||
* @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
|
||||
*/
|
||||
TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -21,18 +21,19 @@ import java.util.List;
|
|||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
/**
|
||||
* A constructor resolver attempts locate a constructor and returns a ConstructorExecutor that can be used to invoke
|
||||
* that constructor. The ConstructorExecutor will be cached but if it 'goes stale' the resolvers will be called again.
|
||||
*
|
||||
* A constructor resolver attempts locate a constructor and returns a ConstructorExecutor
|
||||
* that can be used to invoke that constructor. The ConstructorExecutor will be cached but
|
||||
* if it 'goes stale' the resolvers will be called again.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface ConstructorResolver {
|
||||
|
||||
/**
|
||||
* Within the supplied context determine a suitable constructor on the supplied type that can handle the
|
||||
* specified arguments. Return a ConstructorExecutor that can be used to invoke that constructor
|
||||
* (or {@code null} if no constructor could be found).
|
||||
* Within the supplied context determine a suitable constructor on the supplied type
|
||||
* that can handle the specified arguments. Return a ConstructorExecutor that can be
|
||||
* used to invoke that constructor (or {@code null} if no constructor could be found).
|
||||
* @param context the current evaluation context
|
||||
* @param typeName the type upon which to look for the constructor
|
||||
* @param argumentTypes the arguments that the constructor must be able to handle
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,12 +19,12 @@ package org.springframework.expression;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Expressions are executed in an evaluation context. It is in this context that references
|
||||
* are resolved when encountered during expression evaluation.
|
||||
* Expressions are executed in an evaluation context. It is in this context that
|
||||
* references are resolved when encountered during expression evaluation.
|
||||
*
|
||||
* <p>There is a default implementation of the EvaluationContext,
|
||||
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}
|
||||
* that can be extended, rather than having to implement everything.
|
||||
* {@link org.springframework.expression.spel.support.StandardEvaluationContext} that can
|
||||
* be extended, rather than having to implement everything.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -33,8 +33,9 @@ import java.util.List;
|
|||
public interface EvaluationContext {
|
||||
|
||||
/**
|
||||
* @return the default root context object against which unqualified properties/methods/etc
|
||||
* should be resolved. This can be overridden when evaluating an expression.
|
||||
* @return the default root context object against which unqualified
|
||||
* properties/methods/etc should be resolved. This can be overridden when
|
||||
* evaluating an expression.
|
||||
*/
|
||||
TypedValue getRootObject();
|
||||
|
||||
|
|
@ -54,7 +55,8 @@ public interface EvaluationContext {
|
|||
List<PropertyAccessor> getPropertyAccessors();
|
||||
|
||||
/**
|
||||
* @return a type locator that can be used to find types, either by short or fully qualified name.
|
||||
* @return a type locator that can be used to find types, either by short or fully
|
||||
* qualified name.
|
||||
*/
|
||||
TypeLocator getTypeLocator();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,10 +19,9 @@ package org.springframework.expression;
|
|||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
/**
|
||||
* An expression capable of evaluating itself against context objects.
|
||||
* Encapsulates the details of a previously parsed expression string.
|
||||
* Provides a common abstraction for expression evaluation independent
|
||||
* of any language like OGNL or the Unified EL.
|
||||
* An expression capable of evaluating itself against context objects. Encapsulates the
|
||||
* details of a previously parsed expression string. Provides a common abstraction for
|
||||
* expression evaluation independent of any language like OGNL or the Unified EL.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Andy Clement
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.expression;
|
||||
|
||||
|
||||
/**
|
||||
* Super class for exceptions that can occur whilst processing expressions
|
||||
*
|
||||
|
|
@ -27,8 +26,10 @@ package org.springframework.expression;
|
|||
public class ExpressionException extends RuntimeException {
|
||||
|
||||
protected String expressionString;
|
||||
|
||||
protected int position; // -1 if not known - but should be known in all reasonable cases
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new expression exception.
|
||||
* @param expressionString the expression string
|
||||
|
|
@ -85,15 +86,16 @@ public class ExpressionException extends RuntimeException {
|
|||
super(message,cause);
|
||||
}
|
||||
|
||||
|
||||
public String toDetailedString() {
|
||||
StringBuilder output = new StringBuilder();
|
||||
if (expressionString!=null) {
|
||||
if (this.expressionString!=null) {
|
||||
output.append("Expression '");
|
||||
output.append(expressionString);
|
||||
output.append(this.expressionString);
|
||||
output.append("'");
|
||||
if (position!=-1) {
|
||||
if (this.position!=-1) {
|
||||
output.append(" @ ");
|
||||
output.append(position);
|
||||
output.append(this.position);
|
||||
}
|
||||
output.append(": ");
|
||||
}
|
||||
|
|
@ -106,7 +108,7 @@ public class ExpressionException extends RuntimeException {
|
|||
}
|
||||
|
||||
public final int getPosition() {
|
||||
return position;
|
||||
return this.position;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -13,13 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.expression;
|
||||
|
||||
/**
|
||||
* This exception wraps (as cause) a checked exception thrown by some method that SpEL invokes.
|
||||
* It differs from a SpelEvaluationException because this indicates the occurrence of a checked exception
|
||||
* that the invoked method was defined to throw. SpelEvaluationExceptions are for handling (and wrapping)
|
||||
* unexpected exceptions.
|
||||
* This exception wraps (as cause) a checked exception thrown by some method that SpEL
|
||||
* invokes. It differs from a SpelEvaluationException because this indicates the
|
||||
* occurrence of a checked exception that the invoked method was defined to throw.
|
||||
* SpelEvaluationExceptions are for handling (and wrapping) unexpected exceptions.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0.3
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,13 +17,15 @@
|
|||
package org.springframework.expression;
|
||||
|
||||
/**
|
||||
* MethodExecutors are built by the resolvers and can be cached by the infrastructure to repeat an operation quickly
|
||||
* without going back to the resolvers. For example, the particular method to run on an object may be discovered by the
|
||||
* reflection method resolver - it will then build a MethodExecutor that executes that method and the MethodExecutor can
|
||||
* be reused without needing to go back to the resolver to discover the method again.
|
||||
* MethodExecutors are built by the resolvers and can be cached by the infrastructure to
|
||||
* repeat an operation quickly without going back to the resolvers. For example, the
|
||||
* particular method to run on an object may be discovered by the reflection method
|
||||
* resolver - it will then build a MethodExecutor that executes that method and the
|
||||
* MethodExecutor can be reused without needing to go back to the resolver to discover the
|
||||
* method again.
|
||||
*
|
||||
* <p>They can become stale, and in that case should throw an AccessException - this will cause the infrastructure to go
|
||||
* back to the resolvers to ask for a new one.
|
||||
* <p>They can become stale, and in that case should throw an AccessException - this will
|
||||
* cause the infrastructure to go back to the resolvers to ask for a new one.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -31,13 +33,15 @@ package org.springframework.expression;
|
|||
public interface MethodExecutor {
|
||||
|
||||
/**
|
||||
* Execute a command using the specified arguments, and using the specified expression state.
|
||||
* Execute a command using the specified arguments, and using the specified expression
|
||||
* state.
|
||||
* @param context the evaluation context in which the command is being executed
|
||||
* @param target the target object of the call - null for static methods
|
||||
* @param arguments the arguments to the executor, should match (in terms of number and type) whatever the
|
||||
* command will need to run
|
||||
* @param arguments the arguments to the executor, should match (in terms of number
|
||||
* and type) whatever the command will need to run
|
||||
* @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
|
||||
*/
|
||||
TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -13,18 +13,19 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.expression;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MethodFilter instances allow SpEL users to fine tune the behaviour of the method resolution
|
||||
* process. Method resolution (which translates from a method name in an expression to a real
|
||||
* method to invoke) will normally retrieve candidate methods for invocation via a simple call
|
||||
* to 'Class.getMethods()' and will choose the first one that is suitable for the
|
||||
* input parameters. By registering a MethodFilter the user can receive a callback
|
||||
* and change the methods that will be considered suitable.
|
||||
* MethodFilter instances allow SpEL users to fine tune the behaviour of the method
|
||||
* resolution process. Method resolution (which translates from a method name in an
|
||||
* expression to a real method to invoke) will normally retrieve candidate methods for
|
||||
* invocation via a simple call to 'Class.getMethods()' and will choose the first one that
|
||||
* is suitable for the input parameters. By registering a MethodFilter the user can
|
||||
* receive a callback and change the methods that will be considered suitable.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0.1
|
||||
|
|
@ -32,12 +33,11 @@ import java.util.List;
|
|||
public interface MethodFilter {
|
||||
|
||||
/**
|
||||
* Called by the method resolver to allow the SpEL user to organize the list of candidate
|
||||
* methods that may be invoked. The filter can remove methods that should not be
|
||||
* considered candidates and it may sort the results. The resolver will then search
|
||||
* through the methods as returned from the filter when looking for a suitable
|
||||
* Called by the method resolver to allow the SpEL user to organize the list of
|
||||
* candidate methods that may be invoked. The filter can remove methods that should
|
||||
* not be considered candidates and it may sort the results. The resolver will then
|
||||
* search through the methods as returned from the filter when looking for a suitable
|
||||
* candidate to invoke.
|
||||
*
|
||||
* @param methods the full list of methods the resolver was going to choose from
|
||||
* @return a possible subset of input methods that may be sorted by order of relevance
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -21,8 +21,9 @@ import java.util.List;
|
|||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
/**
|
||||
* A method resolver attempts locate a method and returns a command executor that can be used to invoke that method.
|
||||
* The command executor will be cached but if it 'goes stale' the resolvers will be called again.
|
||||
* A method resolver attempts locate a method and returns a command executor that can be
|
||||
* used to invoke that method. The command executor will be cached but if it 'goes stale'
|
||||
* the resolvers will be called again.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -30,13 +31,14 @@ import org.springframework.core.convert.TypeDescriptor;
|
|||
public interface MethodResolver {
|
||||
|
||||
/**
|
||||
* Within the supplied context determine a suitable method on the supplied object that can handle the
|
||||
* specified arguments. Return a MethodExecutor that can be used to invoke that method
|
||||
* (or {@code null} if no method could be found).
|
||||
* Within the supplied context determine a suitable method on the supplied object that
|
||||
* can handle the specified arguments. Return a MethodExecutor that can be used to
|
||||
* invoke that method (or {@code null} if no method could be found).
|
||||
* @param context the current evaluation context
|
||||
* @param targetObject the object upon which the method is being called
|
||||
* @param argumentTypes the arguments that the constructor must be able to handle
|
||||
* @return a MethodExecutor that can invoke the method, or null if the method cannot be found
|
||||
* @return a MethodExecutor that can invoke the method, or null if the method cannot
|
||||
* be found
|
||||
*/
|
||||
MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
|
||||
List<TypeDescriptor> argumentTypes) throws AccessException;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,13 +17,24 @@
|
|||
package org.springframework.expression;
|
||||
|
||||
/**
|
||||
* Supported operations that an {@link OperatorOverloader} can implement for any pair of operands.
|
||||
* Supported operations that an {@link OperatorOverloader} can implement for any pair of
|
||||
* operands.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public enum Operation {
|
||||
|
||||
ADD, SUBTRACT, DIVIDE, MULTIPLY, MODULUS, POWER
|
||||
ADD,
|
||||
|
||||
SUBTRACT,
|
||||
|
||||
DIVIDE,
|
||||
|
||||
MULTIPLY,
|
||||
|
||||
MODULUS,
|
||||
|
||||
POWER
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,8 +17,9 @@
|
|||
package org.springframework.expression;
|
||||
|
||||
/**
|
||||
* By default the mathematical operators {@link Operation} support simple types like numbers. By providing an
|
||||
* implementation of OperatorOverloader, a user of the expression language can support these operations on other types.
|
||||
* By default the mathematical operators {@link Operation} support simple types like
|
||||
* numbers. By providing an implementation of OperatorOverloader, a user of the expression
|
||||
* language can support these operations on other types.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -26,20 +27,21 @@ package org.springframework.expression;
|
|||
public interface OperatorOverloader {
|
||||
|
||||
/**
|
||||
* Return true if the operator overloader supports the specified operation
|
||||
* between the two operands and so should be invoked to handle it.
|
||||
* Return true if the operator overloader supports the specified operation between the
|
||||
* two operands and so should be invoked to handle it.
|
||||
* @param operation the operation to be performed
|
||||
* @param leftOperand the left operand
|
||||
* @param rightOperand the right operand
|
||||
* @return true if the OperatorOverloader supports the specified operation between the two operands
|
||||
* @return true if the OperatorOverloader supports the specified operation between the
|
||||
* two operands
|
||||
* @throws EvaluationException if there is a problem performing the operation
|
||||
*/
|
||||
boolean overridesOperation(Operation operation, Object leftOperand, Object rightOperand)
|
||||
throws EvaluationException;
|
||||
|
||||
/**
|
||||
* Execute the specified operation on two operands, returning a result.
|
||||
* See {@link Operation} for supported operations.
|
||||
* Execute the specified operation on two operands, returning a result. See
|
||||
* {@link Operation} for supported operations.
|
||||
* @param operation the operation to be performed
|
||||
* @param leftOperand the left operand
|
||||
* @param rightOperand the right operand
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,7 +17,8 @@
|
|||
package org.springframework.expression;
|
||||
|
||||
/**
|
||||
* Input provided to an expression parser that can influence an expression parsing/compilation routine.
|
||||
* Input provided to an expression parser that can influence an expression
|
||||
* parsing/compilation routine.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Andy Clement
|
||||
|
|
@ -26,38 +27,35 @@ package org.springframework.expression;
|
|||
public interface ParserContext {
|
||||
|
||||
/**
|
||||
* Whether or not the expression being parsed is a template. A template expression consists of literal text that can
|
||||
* be mixed with evaluatable blocks. Some examples:
|
||||
*
|
||||
* Whether or not the expression being parsed is a template. A template expression
|
||||
* consists of literal text that can be mixed with evaluatable blocks. Some examples:
|
||||
* <pre class="code">
|
||||
* Some literal text
|
||||
* Hello #{name.firstName}!
|
||||
* #{3 + 4}
|
||||
* </pre>
|
||||
*
|
||||
* @return true if the expression is a template, false otherwise
|
||||
*/
|
||||
boolean isTemplate();
|
||||
|
||||
/**
|
||||
* For template expressions, returns the prefix that identifies the start of an expression block within a string.
|
||||
* For example: "${"
|
||||
*
|
||||
* For template expressions, returns the prefix that identifies the start of an
|
||||
* expression block within a string. For example: "${"
|
||||
* @return the prefix that identifies the start of an expression
|
||||
*/
|
||||
String getExpressionPrefix();
|
||||
|
||||
/**
|
||||
* For template expressions, return the prefix that identifies the end of an expression block within a string.
|
||||
* For example: "}"
|
||||
*
|
||||
* For template expressions, return the prefix that identifies the end of an
|
||||
* expression block within a string. For example: "}"
|
||||
* @return the suffix that identifies the end of an expression
|
||||
*/
|
||||
String getExpressionSuffix();
|
||||
|
||||
|
||||
/**
|
||||
* The default ParserContext implementation that enables template expression parsing mode.
|
||||
* The expression prefix is #{ and the expression suffix is }.
|
||||
* The default ParserContext implementation that enables template expression parsing
|
||||
* mode. The expression prefix is #{ and the expression suffix is }.
|
||||
* @see #isTemplate()
|
||||
*/
|
||||
public static final ParserContext TEMPLATE_EXPRESSION = new ParserContext() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -18,13 +18,15 @@ package org.springframework.expression;
|
|||
|
||||
|
||||
/**
|
||||
* A property accessor is able to read (and possibly write) to object properties. The interface places no restrictions
|
||||
* and so implementors are free to access properties directly as fields or through getters or in any other way they see
|
||||
* as appropriate. A resolver can optionally specify an array of target classes for which it should be called - but if
|
||||
* it returns null from getSpecificTargetClasses() then it will be called for all property references and given a chance
|
||||
* to determine if it can read or write them. Property resolvers are considered to be ordered and each will be called in
|
||||
* turn. The only rule that affects the call order is that any naming the target class directly in
|
||||
* getSpecifiedTargetClasses() will be called first, before the general resolvers.
|
||||
* A property accessor is able to read (and possibly write) to object properties. The
|
||||
* interface places no restrictions and so implementors are free to access properties
|
||||
* directly as fields or through getters or in any other way they see as appropriate. A
|
||||
* resolver can optionally specify an array of target classes for which it should be
|
||||
* called - but if it returns null from getSpecificTargetClasses() then it will be called
|
||||
* for all property references and given a chance to determine if it can read or write
|
||||
* them. Property resolvers are considered to be ordered and each will be called in turn.
|
||||
* The only rule that affects the call order is that any naming the target class directly
|
||||
* in getSpecifiedTargetClasses() will be called first, before the general resolvers.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -32,19 +34,23 @@ package org.springframework.expression;
|
|||
public interface PropertyAccessor {
|
||||
|
||||
/**
|
||||
* Return an array of classes for which this resolver should be called. Returning null indicates this is a general
|
||||
* resolver that can be called in an attempt to resolve a property on any type.
|
||||
* @return an array of classes that this resolver is suitable for (or null if a general resolver)
|
||||
* Return an array of classes for which this resolver should be called. Returning null
|
||||
* indicates this is a general resolver that can be called in an attempt to resolve a
|
||||
* property on any type.
|
||||
* @return an array of classes that this resolver is suitable for (or null if a
|
||||
* general resolver)
|
||||
*/
|
||||
Class[] getSpecificTargetClasses();
|
||||
|
||||
/**
|
||||
* Called to determine if a resolver instance is able to access a specified property on a specified target object.
|
||||
* Called to determine if a resolver instance is able to access a specified property
|
||||
* on a specified target object.
|
||||
* @param context the evaluation context in which the access is being attempted
|
||||
* @param target the target object upon which the property is being accessed
|
||||
* @param name the name of the property being accessed
|
||||
* @return true if this resolver is able to read the property
|
||||
* @throws AccessException if there is any problem determining whether the property can be read
|
||||
* @throws AccessException if there is any problem determining whether the property
|
||||
* can be read
|
||||
*/
|
||||
boolean canRead(EvaluationContext context, Object target, String name) throws AccessException;
|
||||
|
||||
|
|
@ -59,17 +65,20 @@ public interface PropertyAccessor {
|
|||
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.
|
||||
* @param context the evaluation context in which the access is being attempted
|
||||
* @param target the target object upon which the property is being accessed
|
||||
* @param name the name of the property being accessed
|
||||
* @return true if this resolver is able to write to the property
|
||||
* @throws AccessException if there is any problem determining whether the property can be written to
|
||||
* @throws AccessException if there is any problem determining whether the property
|
||||
* can be written to
|
||||
*/
|
||||
boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException;
|
||||
|
||||
/**
|
||||
* Called to write to a property on a specified target object. Should only succeed if canWrite() also returns true.
|
||||
* Called to write to a property on a specified target object. Should only succeed if
|
||||
* canWrite() also returns true.
|
||||
* @param context the evaluation context in which the access is being attempted
|
||||
* @param target the target object upon which the property is being accessed
|
||||
* @param name the name of the property being accessed
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,8 +17,8 @@
|
|||
package org.springframework.expression;
|
||||
|
||||
/**
|
||||
* Instances of a type comparator should be able to compare pairs of objects for equality, the specification of the
|
||||
* return value is the same as for {@link Comparable}.
|
||||
* Instances of a type comparator should be able to compare pairs of objects for equality,
|
||||
* the specification of the return value is the same as for {@link Comparable}.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -29,9 +29,10 @@ public interface TypeComparator {
|
|||
* Compare two objects.
|
||||
* @param firstObject the first object
|
||||
* @param secondObject the second object
|
||||
* @return 0 if they are equal, <0 if the first is smaller than the second, or >0 if the first is larger than the
|
||||
* second
|
||||
* @throws EvaluationException if a problem occurs during comparison (or they are not comparable)
|
||||
* @return 0 if they are equal, <0 if the first is smaller than the second, or >0 if
|
||||
* the first is larger than the second
|
||||
* @throws EvaluationException if a problem occurs during comparison (or they are not
|
||||
* comparable)
|
||||
*/
|
||||
int compare(Object firstObject, Object secondObject) throws EvaluationException;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,10 +19,10 @@ package org.springframework.expression;
|
|||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
/**
|
||||
* A type converter can convert values between different types encountered
|
||||
* during expression evaluation. This is an SPI for the expression parser;
|
||||
* see {@link org.springframework.core.convert.ConversionService} for the
|
||||
* primary user API to Spring's conversion facilities.
|
||||
* A type converter can convert values between different types encountered during
|
||||
* expression evaluation. This is an SPI for the expression parser; see
|
||||
* {@link org.springframework.core.convert.ConversionService} for the primary user API to
|
||||
* Spring's conversion facilities.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -31,7 +31,8 @@ import org.springframework.core.convert.TypeDescriptor;
|
|||
public interface TypeConverter {
|
||||
|
||||
/**
|
||||
* Return true if the type converter can convert the specified type to the desired target type.
|
||||
* Return true if the type converter can convert the specified type to the desired
|
||||
* target type.
|
||||
* @param sourceType a type descriptor that describes the source type
|
||||
* @param targetType a type descriptor that describes the requested result type
|
||||
* @return true if that conversion can be performed
|
||||
|
|
@ -39,12 +40,15 @@ public interface TypeConverter {
|
|||
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||
|
||||
/**
|
||||
* Convert (may coerce) a value from one type to another, for example from a boolean to a string.
|
||||
* The typeDescriptor parameter enables support for typed collections - if the caller really wishes they
|
||||
* can have a List<Integer> for example, rather than simply a List.
|
||||
* Convert (may coerce) a value from one type to another, for example from a boolean
|
||||
* to a string. The typeDescriptor parameter enables support for typed collections -
|
||||
* if the caller really wishes they can have a List<Integer> for example, rather
|
||||
* than simply a List.
|
||||
* @param value the value to be converted
|
||||
* @param sourceType a type descriptor that supplies extra information about the source object
|
||||
* @param targetType a type descriptor that supplies extra information about the requested result type
|
||||
* @param sourceType a type descriptor that supplies extra information about the
|
||||
* source object
|
||||
* @param targetType a type descriptor that supplies extra information about the
|
||||
* requested result type
|
||||
* @return the converted value
|
||||
* @throws EvaluationException if conversion is not possible
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,9 +17,11 @@
|
|||
package org.springframework.expression;
|
||||
|
||||
/**
|
||||
* Implementors of this interface are expected to be able to locate types. They may use custom classloaders
|
||||
* or the and deal with common package prefixes (java.lang, etc) however they wish. See
|
||||
* {@link org.springframework.expression.spel.support.StandardTypeLocator} for an example implementation.
|
||||
* Implementors of this interface are expected to be able to locate types. They may use
|
||||
* custom classloaders or the and deal with common package prefixes (java.lang, etc)
|
||||
* however they wish. See
|
||||
* {@link org.springframework.expression.spel.support.StandardTypeLocator} for an example
|
||||
* implementation.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -27,7 +29,8 @@ package org.springframework.expression;
|
|||
public interface TypeLocator {
|
||||
|
||||
/**
|
||||
* Find a type by name. The name may or may not be fully qualified (eg. String or java.lang.String)
|
||||
* Find a type by name. The name may or may not be fully qualified (eg. String or
|
||||
* java.lang.String)
|
||||
* @param typename the type to be located
|
||||
* @return the class object representing that type
|
||||
* @throws EvaluationException if there is a problem finding it
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,9 +19,9 @@ 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 {@code getClass()} call on the object.
|
||||
* 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
|
||||
* {@code getClass()} call on the object.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -20,18 +20,21 @@ import org.springframework.core.convert.TypeDescriptor;
|
|||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* Represents a template expression broken into pieces. Each piece will be an Expression but pure text parts to the
|
||||
* template will be represented as LiteralExpression objects. An example of a template expression might be:
|
||||
*
|
||||
* Represents a template expression broken into pieces. Each piece will be an Expression
|
||||
* but pure text parts to the template will be represented as LiteralExpression objects.
|
||||
* An example of a template expression might be:
|
||||
*
|
||||
* <pre class="code">
|
||||
* "Hello ${getName()}"</pre>
|
||||
*
|
||||
* which will be represented as a CompositeStringExpression of two parts. The first part being a
|
||||
* LiteralExpression representing 'Hello ' and the second part being a real expression that will
|
||||
* call {@code getName()} when invoked.
|
||||
*
|
||||
* "Hello ${getName()}"
|
||||
* </pre>
|
||||
*
|
||||
* which will be represented as a CompositeStringExpression of two parts. The first part
|
||||
* being a LiteralExpression representing 'Hello ' and the second part being a real
|
||||
* expression that will call {@code getName()} when invoked.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
|
|
@ -131,13 +134,13 @@ public class CompositeStringExpression implements Expression {
|
|||
@Override
|
||||
public <T> T getValue(EvaluationContext context, Class<T> expectedResultType) throws EvaluationException {
|
||||
Object value = getValue(context);
|
||||
return ExpressionUtils.convert(context, value, expectedResultType);
|
||||
return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValue(Class<T> expectedResultType) throws EvaluationException {
|
||||
Object value = getValue();
|
||||
return ExpressionUtils.convert(null, value, expectedResultType);
|
||||
return ExpressionUtils.convertTypedValue(null, new TypedValue(value), expectedResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -146,21 +149,21 @@ public class CompositeStringExpression implements Expression {
|
|||
}
|
||||
|
||||
public Expression[] getExpressions() {
|
||||
return expressions;
|
||||
return this.expressions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T getValue(Object rootObject, Class<T> desiredResultType) throws EvaluationException {
|
||||
Object value = getValue(rootObject);
|
||||
return ExpressionUtils.convert(null, value, desiredResultType);
|
||||
return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValue(EvaluationContext context, Object rootObject, Class<T> desiredResultType)
|
||||
throws EvaluationException {
|
||||
Object value = getValue(context,rootObject);
|
||||
return ExpressionUtils.convert(context, value, desiredResultType);
|
||||
return ExpressionUtils.convertTypedValue(context, new TypedValue(value), desiredResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -33,29 +33,32 @@ import org.springframework.util.ClassUtils;
|
|||
public abstract class ExpressionUtils {
|
||||
|
||||
/**
|
||||
* Determines if there is a type converter available in the specified context and attempts to use it to convert the
|
||||
* supplied value to the specified type. Throws an exception if conversion is not possible.
|
||||
* Determines if there is a type converter available in the specified context and
|
||||
* attempts to use it to convert the supplied value to the specified type. Throws an
|
||||
* exception if conversion is not possible.
|
||||
* @param context the evaluation context that may define a type converter
|
||||
* @param value the value to convert (may be null)
|
||||
* @param targetType the type to attempt conversion to
|
||||
* @return the converted value
|
||||
* @throws EvaluationException if there is a problem during conversion or conversion of the value to the specified
|
||||
* type is not supported
|
||||
* @throws EvaluationException if there is a problem during conversion or conversion
|
||||
* of the value to the specified type is not supported
|
||||
* @deprecated use {@link #convertTypedValue(EvaluationContext, TypedValue, Class)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static <T> T convert(EvaluationContext context, Object value, Class<T> targetType) throws EvaluationException {
|
||||
// TODO remove this function over time and use the one it delegates to
|
||||
return convertTypedValue(context,new TypedValue(value),targetType);
|
||||
return convertTypedValue(context, new TypedValue(value), targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if there is a type converter available in the specified context and attempts to use it to convert the
|
||||
* supplied value to the specified type. Throws an exception if conversion is not possible.
|
||||
* Determines if there is a type converter available in the specified context and
|
||||
* attempts to use it to convert the supplied value to the specified type. Throws an
|
||||
* exception if conversion is not possible.
|
||||
* @param context the evaluation context that may define a type converter
|
||||
* @param typedValue the value to convert and a type descriptor describing it
|
||||
* @param targetType the type to attempt conversion to
|
||||
* @return the converted value
|
||||
* @throws EvaluationException if there is a problem during conversion or conversion of the value to the specified
|
||||
* type is not supported
|
||||
* @throws EvaluationException if there is a problem during conversion or conversion
|
||||
* of the value to the specified type is not supported
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T convertTypedValue(EvaluationContext context, TypedValue typedValue, Class<T> targetType) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -20,13 +20,14 @@ import org.springframework.core.convert.TypeDescriptor;
|
|||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* A very simple hardcoded implementation of the Expression interface that represents a string literal.
|
||||
* It is used with CompositeStringExpression when representing a template expression which is made up
|
||||
* of pieces - some being real expressions to be handled by an EL implementation like Spel, and some
|
||||
* being just textual elements.
|
||||
*
|
||||
* A very simple hardcoded implementation of the Expression interface that represents a
|
||||
* string literal. It is used with CompositeStringExpression when representing a template
|
||||
* expression which is made up of pieces - some being real expressions to be handled by an
|
||||
* EL implementation like Spel, and some being just textual elements.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
|
|
@ -78,19 +79,19 @@ public class LiteralExpression implements Expression {
|
|||
|
||||
@Override
|
||||
public void setValue(EvaluationContext context, Object value) throws EvaluationException {
|
||||
throw new EvaluationException(literalValue, "Cannot call setValue() on a LiteralExpression");
|
||||
throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValue(EvaluationContext context, Class<T> expectedResultType) throws EvaluationException {
|
||||
Object value = getValue(context);
|
||||
return ExpressionUtils.convert(context, value, expectedResultType);
|
||||
return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValue(Class<T> expectedResultType) throws EvaluationException {
|
||||
Object value = getValue();
|
||||
return ExpressionUtils.convert(null, value, expectedResultType);
|
||||
return ExpressionUtils.convertTypedValue(null, new TypedValue(value), expectedResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -106,7 +107,7 @@ public class LiteralExpression implements Expression {
|
|||
@Override
|
||||
public <T> T getValue(Object rootObject, Class<T> desiredResultType) throws EvaluationException {
|
||||
Object value = getValue(rootObject);
|
||||
return ExpressionUtils.convert(null, value, desiredResultType);
|
||||
return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -117,7 +118,7 @@ public class LiteralExpression implements Expression {
|
|||
@Override
|
||||
public <T> T getValue(EvaluationContext context, Object rootObject, Class<T> desiredResultType) throws EvaluationException {
|
||||
Object value = getValue(context, rootObject);
|
||||
return ExpressionUtils.convert(null, value, desiredResultType);
|
||||
return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -147,7 +148,7 @@ public class LiteralExpression implements Expression {
|
|||
|
||||
@Override
|
||||
public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException {
|
||||
throw new EvaluationException(literalValue, "Cannot call setValue() on a LiteralExpression");
|
||||
throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -157,7 +158,7 @@ public class LiteralExpression implements Expression {
|
|||
|
||||
@Override
|
||||
public void setValue(Object rootObject, Object value) throws EvaluationException {
|
||||
throw new EvaluationException(literalValue, "Cannot call setValue() on a LiteralExpression");
|
||||
throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -26,9 +26,9 @@ import org.springframework.expression.ParseException;
|
|||
import org.springframework.expression.ParserContext;
|
||||
|
||||
/**
|
||||
* An expression parser that understands templates. It can be subclassed
|
||||
* by expression parsers that do not offer first class support for templating.
|
||||
*
|
||||
* An expression parser that understands templates. It can be subclassed by expression
|
||||
* parsers that do not offer first class support for templating.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @author Andy Clement
|
||||
|
|
@ -40,102 +40,124 @@ public abstract class TemplateAwareExpressionParser implements ExpressionParser
|
|||
* Default ParserContext instance for non-template expressions.
|
||||
*/
|
||||
private static final ParserContext NON_TEMPLATE_PARSER_CONTEXT = new ParserContext() {
|
||||
|
||||
@Override
|
||||
public String getExpressionPrefix() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExpressionSuffix() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTemplate() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public Expression parseExpression(String expressionString) throws ParseException {
|
||||
return parseExpression(expressionString, NON_TEMPLATE_PARSER_CONTEXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression parseExpression(String expressionString, ParserContext context) throws ParseException {
|
||||
public Expression parseExpression(String expressionString, ParserContext context)
|
||||
throws ParseException {
|
||||
if (context == null) {
|
||||
context = NON_TEMPLATE_PARSER_CONTEXT;
|
||||
}
|
||||
|
||||
if (context.isTemplate()) {
|
||||
return parseTemplate(expressionString, context);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return doParseExpression(expressionString, context);
|
||||
}
|
||||
}
|
||||
|
||||
private Expression parseTemplate(String expressionString, ParserContext context) throws ParseException {
|
||||
private Expression parseTemplate(String expressionString, ParserContext context)
|
||||
throws ParseException {
|
||||
if (expressionString.length() == 0) {
|
||||
return new LiteralExpression("");
|
||||
}
|
||||
Expression[] expressions = parseExpressions(expressionString, context);
|
||||
if (expressions.length == 1) {
|
||||
return expressions[0];
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return new CompositeStringExpression(expressionString, expressions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper that parses given expression string using the configured parser. The expression string can contain any
|
||||
* number of expressions all contained in "${...}" markers. For instance: "foo${expr0}bar${expr1}". The static
|
||||
* pieces of text will also be returned as Expressions that just return that static piece of text. As a result,
|
||||
* evaluating all returned expressions and concatenating the results produces the complete evaluated string.
|
||||
* Unwrapping is only done of the outermost delimiters found, so the string 'hello ${foo${abc}}' would break into
|
||||
* the pieces 'hello ' and 'foo${abc}'. This means that expression languages that used ${..} as part of their
|
||||
* functionality are supported without any problem.
|
||||
* The parsing is aware of the structure of an embedded expression. It assumes that parentheses '(',
|
||||
* square brackets '[' and curly brackets '}' must be in pairs within the expression unless they are within a
|
||||
* string literal and a string literal starts and terminates with a single quote '.
|
||||
*
|
||||
* Helper that parses given expression string using the configured parser. The
|
||||
* expression string can contain any number of expressions all contained in "${...}"
|
||||
* markers. For instance: "foo${expr0}bar${expr1}". The static pieces of text will
|
||||
* also be returned as Expressions that just return that static piece of text. As a
|
||||
* result, evaluating all returned expressions and concatenating the results produces
|
||||
* the complete evaluated string. Unwrapping is only done of the outermost delimiters
|
||||
* found, so the string 'hello ${foo${abc}}' would break into the pieces 'hello ' and
|
||||
* 'foo${abc}'. This means that expression languages that used ${..} as part of their
|
||||
* functionality are supported without any problem. The parsing is aware of the
|
||||
* structure of an embedded expression. It assumes that parentheses '(', square
|
||||
* brackets '[' and curly brackets '}' must be in pairs within the expression unless
|
||||
* they are within a string literal and a string literal starts and terminates with a
|
||||
* single quote '.
|
||||
* @param expressionString the expression string
|
||||
* @return the parsed expressions
|
||||
* @throws ParseException when the expressions cannot be parsed
|
||||
*/
|
||||
private Expression[] parseExpressions(String expressionString, ParserContext context) throws ParseException {
|
||||
private Expression[] parseExpressions(String expressionString, ParserContext context)
|
||||
throws ParseException {
|
||||
List<Expression> expressions = new LinkedList<Expression>();
|
||||
String prefix = context.getExpressionPrefix();
|
||||
String suffix = context.getExpressionSuffix();
|
||||
int startIdx = 0;
|
||||
while (startIdx < expressionString.length()) {
|
||||
int prefixIndex = expressionString.indexOf(prefix,startIdx);
|
||||
int prefixIndex = expressionString.indexOf(prefix, startIdx);
|
||||
if (prefixIndex >= startIdx) {
|
||||
// an inner expression was found - this is a composite
|
||||
if (prefixIndex > startIdx) {
|
||||
expressions.add(createLiteralExpression(context,expressionString.substring(startIdx, prefixIndex)));
|
||||
expressions.add(createLiteralExpression(context,
|
||||
expressionString.substring(startIdx, prefixIndex)));
|
||||
}
|
||||
int afterPrefixIndex = prefixIndex + prefix.length();
|
||||
int suffixIndex = skipToCorrectEndSuffix(prefix,suffix,expressionString,afterPrefixIndex);
|
||||
int suffixIndex = skipToCorrectEndSuffix(prefix, suffix,
|
||||
expressionString, afterPrefixIndex);
|
||||
|
||||
if (suffixIndex == -1) {
|
||||
throw new ParseException(expressionString, prefixIndex, "No ending suffix '" + suffix +
|
||||
"' for expression starting at character " + prefixIndex + ": " +
|
||||
expressionString.substring(prefixIndex));
|
||||
throw new ParseException(expressionString, prefixIndex,
|
||||
"No ending suffix '" + suffix
|
||||
+ "' for expression starting at character "
|
||||
+ prefixIndex + ": "
|
||||
+ expressionString.substring(prefixIndex));
|
||||
}
|
||||
|
||||
if (suffixIndex == afterPrefixIndex) {
|
||||
throw new ParseException(expressionString, prefixIndex, "No expression defined within delimiter '" +
|
||||
prefix + suffix + "' at character " + prefixIndex);
|
||||
} else {
|
||||
String expr = expressionString.substring(prefixIndex + prefix.length(), suffixIndex);
|
||||
expr = expr.trim();
|
||||
if (expr.length()==0) {
|
||||
throw new ParseException(expressionString, prefixIndex, "No expression defined within delimiter '" +
|
||||
prefix + suffix + "' at character " + prefixIndex);
|
||||
}
|
||||
expressions.add(doParseExpression(expr, context));
|
||||
startIdx = suffixIndex + suffix.length();
|
||||
throw new ParseException(expressionString, prefixIndex,
|
||||
"No expression defined within delimiter '" + prefix + suffix
|
||||
+ "' at character " + prefixIndex);
|
||||
}
|
||||
} else {
|
||||
|
||||
String expr = expressionString.substring(prefixIndex + prefix.length(),
|
||||
suffixIndex);
|
||||
expr = expr.trim();
|
||||
|
||||
if (expr.length() == 0) {
|
||||
throw new ParseException(expressionString, prefixIndex,
|
||||
"No expression defined within delimiter '" + prefix + suffix
|
||||
+ "' at character " + prefixIndex);
|
||||
}
|
||||
|
||||
expressions.add(doParseExpression(expr, context));
|
||||
startIdx = suffixIndex + suffix.length();
|
||||
}
|
||||
else {
|
||||
// no more ${expressions} found in string, add rest as static text
|
||||
expressions.add(createLiteralExpression(context,expressionString.substring(startIdx)));
|
||||
expressions.add(createLiteralExpression(context,
|
||||
expressionString.substring(startIdx)));
|
||||
startIdx = expressionString.length();
|
||||
}
|
||||
}
|
||||
|
|
@ -147,19 +169,20 @@ public abstract class TemplateAwareExpressionParser implements ExpressionParser
|
|||
}
|
||||
|
||||
/**
|
||||
* Return true if the specified suffix can be found at the supplied position in the supplied expression string.
|
||||
* Return true if the specified suffix can be found at the supplied position in the
|
||||
* supplied expression string.
|
||||
* @param expressionString the expression string which may contain the suffix
|
||||
* @param pos the start position at which to check for the suffix
|
||||
* @param suffix the suffix string
|
||||
*/
|
||||
private boolean isSuffixHere(String expressionString,int pos,String suffix) {
|
||||
private boolean isSuffixHere(String expressionString, int pos, String suffix) {
|
||||
int suffixPosition = 0;
|
||||
for (int i=0;i<suffix.length() && pos<expressionString.length();i++) {
|
||||
if (expressionString.charAt(pos++)!=suffix.charAt(suffixPosition++)) {
|
||||
for (int i = 0; i < suffix.length() && pos < expressionString.length(); i++) {
|
||||
if (expressionString.charAt(pos++) != suffix.charAt(suffixPosition++)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (suffixPosition!=suffix.length()) {
|
||||
if (suffixPosition != suffix.length()) {
|
||||
// the expressionString ran out before the suffix could entirely be found
|
||||
return false;
|
||||
}
|
||||
|
|
@ -167,58 +190,73 @@ public abstract class TemplateAwareExpressionParser implements ExpressionParser
|
|||
}
|
||||
|
||||
/**
|
||||
* Copes with nesting, for example '${...${...}}' where the correct end for the first ${ is the final }.
|
||||
*
|
||||
* Copes with nesting, for example '${...${...}}' where the correct end for the first
|
||||
* ${ is the final }.
|
||||
* @param prefix the prefix
|
||||
* @param suffix the suffix
|
||||
* @param expressionString the expression string
|
||||
* @param afterPrefixIndex the most recently found prefix location for which the matching end suffix is being sought
|
||||
* @param afterPrefixIndex the most recently found prefix location for which the
|
||||
* matching end suffix is being sought
|
||||
* @return the position of the correct matching nextSuffix or -1 if none can be found
|
||||
*/
|
||||
private int skipToCorrectEndSuffix(String prefix, String suffix, String expressionString, int afterPrefixIndex) throws ParseException {
|
||||
private int skipToCorrectEndSuffix(String prefix, String suffix,
|
||||
String expressionString, int afterPrefixIndex) throws ParseException {
|
||||
// Chew on the expression text - relying on the rules:
|
||||
// brackets must be in pairs: () [] {}
|
||||
// string literals are "..." or '...' and these may contain unmatched brackets
|
||||
int pos = afterPrefixIndex;
|
||||
int maxlen = expressionString.length();
|
||||
int nextSuffix = expressionString.indexOf(suffix,afterPrefixIndex);
|
||||
if (nextSuffix ==-1 ) {
|
||||
int nextSuffix = expressionString.indexOf(suffix, afterPrefixIndex);
|
||||
if (nextSuffix == -1) {
|
||||
return -1; // the suffix is missing
|
||||
}
|
||||
Stack<Bracket> stack = new Stack<Bracket>();
|
||||
while (pos<maxlen) {
|
||||
if (isSuffixHere(expressionString,pos,suffix) && stack.isEmpty()) {
|
||||
while (pos < maxlen) {
|
||||
if (isSuffixHere(expressionString, pos, suffix) && stack.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
char ch = expressionString.charAt(pos);
|
||||
switch (ch) {
|
||||
case '{': case '[': case '(':
|
||||
stack.push(new Bracket(ch,pos));
|
||||
break;
|
||||
case '}':case ']':case ')':
|
||||
if (stack.isEmpty()) {
|
||||
throw new ParseException(expressionString, pos, "Found closing '"+ch+"' at position "+pos+" without an opening '"+Bracket.theOpenBracketFor(ch)+"'");
|
||||
}
|
||||
Bracket p = stack.pop();
|
||||
if (!p.compatibleWithCloseBracket(ch)) {
|
||||
throw new ParseException(expressionString, pos, "Found closing '"+ch+"' at position "+pos+" but most recent opening is '"+p.bracket+"' at position "+p.pos);
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
case '"':
|
||||
// jump to the end of the literal
|
||||
int endLiteral = expressionString.indexOf(ch,pos+1);
|
||||
if (endLiteral==-1) {
|
||||
throw new ParseException(expressionString, pos, "Found non terminating string literal starting at position "+pos);
|
||||
}
|
||||
pos=endLiteral;
|
||||
break;
|
||||
case '{':
|
||||
case '[':
|
||||
case '(':
|
||||
stack.push(new Bracket(ch, pos));
|
||||
break;
|
||||
case '}':
|
||||
case ']':
|
||||
case ')':
|
||||
if (stack.isEmpty()) {
|
||||
throw new ParseException(expressionString, pos, "Found closing '"
|
||||
+ ch + "' at position " + pos + " without an opening '"
|
||||
+ Bracket.theOpenBracketFor(ch) + "'");
|
||||
}
|
||||
Bracket p = stack.pop();
|
||||
if (!p.compatibleWithCloseBracket(ch)) {
|
||||
throw new ParseException(expressionString, pos, "Found closing '"
|
||||
+ ch + "' at position " + pos
|
||||
+ " but most recent opening is '" + p.bracket
|
||||
+ "' at position " + p.pos);
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
case '"':
|
||||
// jump to the end of the literal
|
||||
int endLiteral = expressionString.indexOf(ch, pos + 1);
|
||||
if (endLiteral == -1) {
|
||||
throw new ParseException(expressionString, pos,
|
||||
"Found non terminating string literal starting at position "
|
||||
+ pos);
|
||||
}
|
||||
pos = endLiteral;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (!stack.isEmpty()) {
|
||||
Bracket p = stack.pop();
|
||||
throw new ParseException(expressionString, p.pos, "Missing closing '"+Bracket.theCloseBracketFor(p.bracket)+"' for '"+p.bracket+"' at position "+p.pos);
|
||||
throw new ParseException(expressionString, p.pos, "Missing closing '"
|
||||
+ Bracket.theCloseBracketFor(p.bracket) + "' for '" + p.bracket
|
||||
+ "' at position " + p.pos);
|
||||
}
|
||||
if (!isSuffixHere(expressionString, pos, suffix)) {
|
||||
return -1;
|
||||
|
|
@ -226,43 +264,49 @@ public abstract class TemplateAwareExpressionParser implements ExpressionParser
|
|||
return pos;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This captures a type of bracket and the position in which it occurs in the expression. The positional
|
||||
* information is used if an error has to be reported because the related end bracket cannot be found.
|
||||
* Bracket is used to describe: square brackets [] round brackets () and curly brackets {}
|
||||
* This captures a type of bracket and the position in which it occurs in the
|
||||
* expression. The positional information is used if an error has to be reported
|
||||
* because the related end bracket cannot be found. Bracket is used to describe:
|
||||
* square brackets [] round brackets () and curly brackets {}
|
||||
*/
|
||||
private static class Bracket {
|
||||
|
||||
char bracket;
|
||||
|
||||
int pos;
|
||||
|
||||
Bracket(char bracket,int pos) {
|
||||
Bracket(char bracket, int pos) {
|
||||
this.bracket = bracket;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
boolean compatibleWithCloseBracket(char closeBracket) {
|
||||
if (bracket=='{') {
|
||||
return closeBracket=='}';
|
||||
} else if (bracket=='[') {
|
||||
return closeBracket==']';
|
||||
if (this.bracket == '{') {
|
||||
return closeBracket == '}';
|
||||
}
|
||||
return closeBracket==')';
|
||||
else if (this.bracket == '[') {
|
||||
return closeBracket == ']';
|
||||
}
|
||||
return closeBracket == ')';
|
||||
}
|
||||
|
||||
static char theOpenBracketFor(char closeBracket) {
|
||||
if (closeBracket=='}') {
|
||||
if (closeBracket == '}') {
|
||||
return '{';
|
||||
} else if (closeBracket==']') {
|
||||
}
|
||||
else if (closeBracket == ']') {
|
||||
return '[';
|
||||
}
|
||||
return '(';
|
||||
}
|
||||
|
||||
static char theCloseBracketFor(char openBracket) {
|
||||
if (openBracket=='{') {
|
||||
if (openBracket == '{') {
|
||||
return '}';
|
||||
} else if (openBracket=='[') {
|
||||
}
|
||||
else if (openBracket == '[') {
|
||||
return ']';
|
||||
}
|
||||
return ')';
|
||||
|
|
@ -276,8 +320,7 @@ public abstract class TemplateAwareExpressionParser implements ExpressionParser
|
|||
* @return an evaluator for the parsed expression
|
||||
* @throws ParseException an exception occurred during parsing
|
||||
*/
|
||||
protected abstract Expression doParseExpression(String expressionString, ParserContext context)
|
||||
throws ParseException;
|
||||
protected abstract Expression doParseExpression(String expressionString,
|
||||
ParserContext context) throws ParseException;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,8 +19,8 @@ package org.springframework.expression.common;
|
|||
import org.springframework.expression.ParserContext;
|
||||
|
||||
/**
|
||||
* Configurable {@link ParserContext} implementation for template parsing.
|
||||
* Expects the expression prefix and suffix as constructor arguments.
|
||||
* Configurable {@link ParserContext} implementation for template parsing. Expects the
|
||||
* expression prefix and suffix as constructor arguments.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -32,12 +32,15 @@ import org.springframework.expression.TypeConverter;
|
|||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* An ExpressionState is for maintaining per-expression-evaluation state, any changes to it are not seen by other
|
||||
* expressions but it gives a place to hold local variables and for component expressions in a compound expression to
|
||||
* communicate state. This is in contrast to the EvaluationContext, which is shared amongst expression evaluations, and
|
||||
* any changes to it will be seen by other expressions or any code that chooses to ask questions of the context.
|
||||
* An ExpressionState is for maintaining per-expression-evaluation state, any changes to
|
||||
* it are not seen by other expressions but it gives a place to hold local variables and
|
||||
* for component expressions in a compound expression to communicate state. This is in
|
||||
* contrast to the EvaluationContext, which is shared amongst expression evaluations, and
|
||||
* any changes to it will be seen by other expressions or any code that chooses to ask
|
||||
* questions of the context.
|
||||
*
|
||||
* <p>It also acts as a place for to define common utility routines that the various Ast nodes might need.
|
||||
* <p>It also acts as a place for to define common utility routines that the various AST
|
||||
* nodes might need.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -138,7 +141,8 @@ public class ExpressionState {
|
|||
}
|
||||
|
||||
public Object convertValue(Object value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
|
||||
return this.relatedContext.getTypeConverter().convertValue(value, TypeDescriptor.forObject(value), targetTypeDescriptor);
|
||||
return this.relatedContext.getTypeConverter().convertValue(value,
|
||||
TypeDescriptor.forObject(value), targetTypeDescriptor);
|
||||
}
|
||||
|
||||
public TypeConverter getTypeConverter() {
|
||||
|
|
@ -147,7 +151,8 @@ public class ExpressionState {
|
|||
|
||||
public Object convertValue(TypedValue value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
|
||||
Object val = value.getValue();
|
||||
return this.relatedContext.getTypeConverter().convertValue(val, TypeDescriptor.forObject(val), targetTypeDescriptor);
|
||||
return this.relatedContext.getTypeConverter().convertValue(val,
|
||||
TypeDescriptor.forObject(val), targetTypeDescriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -210,6 +215,7 @@ public class ExpressionState {
|
|||
return this.configuration;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A new scope is entered when a function is called and it is used to hold the parameters to the function call. If the names
|
||||
* of the parameters clash with those in a higher level scope, those in the higher level scope will not be accessible whilst
|
||||
|
|
@ -221,6 +227,7 @@ public class ExpressionState {
|
|||
|
||||
public VariableScope() { }
|
||||
|
||||
|
||||
public VariableScope(Map<String, Object> arguments) {
|
||||
if (arguments != null) {
|
||||
this.vars.putAll(arguments);
|
||||
|
|
@ -231,6 +238,7 @@ public class ExpressionState {
|
|||
this.vars.put(name,value);
|
||||
}
|
||||
|
||||
|
||||
public Object lookupVariable(String name) {
|
||||
return this.vars.get(name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -18,9 +18,9 @@ package org.springframework.expression.spel;
|
|||
import org.springframework.expression.EvaluationException;
|
||||
|
||||
/**
|
||||
* Root exception for Spring EL related exceptions. Rather than holding a hard coded string indicating the problem, it
|
||||
* records a message key and the inserts for the message. See {@link SpelMessage} for the list of all possible messages
|
||||
* that can occur.
|
||||
* Root exception for Spring EL related exceptions. Rather than holding a hard coded
|
||||
* string indicating the problem, it records a message key and the inserts for the
|
||||
* message. See {@link SpelMessage} for the list of all possible messages that can occur.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -28,8 +28,10 @@ import org.springframework.expression.EvaluationException;
|
|||
@SuppressWarnings("serial")
|
||||
public class SpelEvaluationException extends EvaluationException {
|
||||
|
||||
private SpelMessage message;
|
||||
private Object[] inserts;
|
||||
private final SpelMessage message;
|
||||
|
||||
private final Object[] inserts;
|
||||
|
||||
|
||||
public SpelEvaluationException(SpelMessage message, Object... inserts) {
|
||||
super(message.formatMessage(0, inserts)); // TODO poor position information, can the callers not really supply something?
|
||||
|
|
@ -56,15 +58,18 @@ public class SpelEvaluationException extends EvaluationException {
|
|||
this.inserts = inserts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return a formatted message with inserts applied
|
||||
*/
|
||||
@Override
|
||||
public String getMessage() {
|
||||
if (message != null)
|
||||
return message.formatMessage(position, inserts);
|
||||
else
|
||||
if (this.message != null) {
|
||||
return this.message.formatMessage(this.position, this.inserts);
|
||||
}
|
||||
else {
|
||||
return super.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -87,7 +92,7 @@ public class SpelEvaluationException extends EvaluationException {
|
|||
* @return the message inserts
|
||||
*/
|
||||
public Object[] getInserts() {
|
||||
return inserts;
|
||||
return this.inserts;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,98 +19,249 @@ package org.springframework.expression.spel;
|
|||
import java.text.MessageFormat;
|
||||
|
||||
/**
|
||||
* Contains all the messages that can be produced by the Spring Expression Language. Each message has a kind (info,
|
||||
* warn, error) and a code number. Tests can be written to expect particular code numbers rather than particular text,
|
||||
* enabling the message text to more easily be modified and the tests to run successfully in different locales.
|
||||
* <p>
|
||||
* When a message is formatted, it will have this kind of form
|
||||
* Contains all the messages that can be produced by the Spring Expression Language. Each
|
||||
* message has a kind (info, warn, error) and a code number. Tests can be written to
|
||||
* expect particular code numbers rather than particular text, enabling the message text
|
||||
* to more easily be modified and the tests to run successfully in different locales.
|
||||
*
|
||||
* <p>When a message is formatted, it will have this kind of form
|
||||
*
|
||||
* <pre class="code">
|
||||
* EL1004E: (pos 34): Type cannot be found 'String'
|
||||
* </pre>
|
||||
*
|
||||
* </code> The prefix captures the code and the error kind, whilst the position is included if it is known.
|
||||
* The prefix captures the code and the error kind, whilst the position is
|
||||
* included if it is known.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public enum SpelMessage {
|
||||
|
||||
TYPE_CONVERSION_ERROR(Kind.ERROR, 1001, "Type conversion problem, cannot convert from {0} to {1}"), //
|
||||
CONSTRUCTOR_NOT_FOUND(Kind.ERROR, 1002, "Constructor call: No suitable constructor found on type {0} for arguments {1}"), //
|
||||
CONSTRUCTOR_INVOCATION_PROBLEM(Kind.ERROR, 1003, "A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"), //
|
||||
METHOD_NOT_FOUND(Kind.ERROR, 1004, "Method call: Method {0} cannot be found on {1} type"), //
|
||||
TYPE_NOT_FOUND(Kind.ERROR, 1005, "Type cannot be found ''{0}''"), //
|
||||
FUNCTION_NOT_DEFINED(Kind.ERROR, 1006, "The function ''{0}'' could not be found"), //
|
||||
PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1007, "Field or property ''{0}'' cannot be found on null"), //
|
||||
PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1008, "Field or property ''{0}'' cannot be found on object of type ''{1}''"), //
|
||||
PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1009, "Field or property ''{0}'' cannot be set on null"), //
|
||||
PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010, "Field or property ''{0}'' cannot be set on object of type ''{1}''"), //
|
||||
METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1011, "Method call: Attempted to call method {0} on null context object"), //
|
||||
CANNOT_INDEX_INTO_NULL_VALUE(Kind.ERROR, 1012, "Cannot index into a null value"),
|
||||
NOT_COMPARABLE(Kind.ERROR, 1013, "Cannot compare instances of {0} and {1}"), //
|
||||
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1014, "Incorrect number of arguments for function, {0} supplied but function takes {1}"), //
|
||||
INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1015, "Cannot perform selection on input data of type ''{0}''"), //
|
||||
RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1016, "Result of selection criteria is not boolean"), //
|
||||
BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST(Kind.ERROR, 1017, "Right operand for the 'between' operator has to be a two-element list"), //
|
||||
INVALID_PATTERN(Kind.ERROR, 1018, "Pattern is not valid ''{0}''"), //
|
||||
PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1019, "Projection is not supported on the type ''{0}''"), //
|
||||
ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1020, "The argument list of a lambda expression should never have getValue() called upon it"), //
|
||||
EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1021, "A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"), //
|
||||
FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1022, "The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"), //
|
||||
EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1023, "A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"), //
|
||||
ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1024, "The array has ''{0}'' elements, index ''{1}'' is invalid"), //
|
||||
COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1025, "The collection has ''{0}'' elements, index ''{1}'' is invalid"), //
|
||||
STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1026, "The string has ''{0}'' characters, index ''{1}'' is invalid"), //
|
||||
INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1027, "Indexing into type ''{0}'' is not supported"), //
|
||||
INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1028, "The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"), //
|
||||
EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1029, "A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"), //
|
||||
OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1030, "The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"), //
|
||||
PROBLEM_LOCATING_METHOD(Kind.ERROR, 1031, "Problem locating method {0} cannot on type {1}"),
|
||||
SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1032, "setValue(ExpressionState, Object) not supported for ''{0}''"), //
|
||||
MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1033, "Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"), //
|
||||
EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1034, "A problem occurred whilst attempting to set the property ''{0}'': {1}"), //
|
||||
NOT_AN_INTEGER(Kind.ERROR, 1035, "The value ''{0}'' cannot be parsed as an int"), //
|
||||
NOT_A_LONG(Kind.ERROR, 1036, "The value ''{0}'' cannot be parsed as a long"), //
|
||||
INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1037, "First operand to matches operator must be a string. ''{0}'' is not"), //
|
||||
INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1038, "Second operand to matches operator must be a string. ''{0}'' is not"), //
|
||||
FUNCTION_MUST_BE_STATIC(Kind.ERROR, 1039, "Only static methods can be called via function references. The method ''{0}'' referred to by name ''{1}'' is not static."),//
|
||||
NOT_A_REAL(Kind.ERROR, 1040, "The value ''{0}'' cannot be parsed as a double"), //
|
||||
MORE_INPUT(Kind.ERROR,1041, "After parsing a valid expression, there is still more data in the expression: ''{0}''"),
|
||||
RIGHT_OPERAND_PROBLEM(Kind.ERROR,1042, "Problem parsing right operand"),
|
||||
NOT_EXPECTED_TOKEN(Kind.ERROR,1043,"Unexpected token. Expected ''{0}'' but was ''{1}''"),
|
||||
OOD(Kind.ERROR,1044,"Unexpectedly ran out of input"), //
|
||||
NON_TERMINATING_DOUBLE_QUOTED_STRING(Kind.ERROR,1045,"Cannot find terminating \" for string"),//
|
||||
NON_TERMINATING_QUOTED_STRING(Kind.ERROR,1046,"Cannot find terminating ' for string"), //
|
||||
MISSING_LEADING_ZERO_FOR_NUMBER(Kind.ERROR,1047,"A real number must be prefixed by zero, it cannot start with just ''.''"), //
|
||||
REAL_CANNOT_BE_LONG(Kind.ERROR,1048,"Real number cannot be suffixed with a long (L or l) suffix"),//
|
||||
UNEXPECTED_DATA_AFTER_DOT(Kind.ERROR,1049,"Unexpected data after ''.'': ''{0}''"),//
|
||||
MISSING_CONSTRUCTOR_ARGS(Kind.ERROR,1050,"The arguments '(...)' for the constructor call are missing"),//
|
||||
RUN_OUT_OF_ARGUMENTS(Kind.ERROR,1051,"Unexpected ran out of arguments"),//
|
||||
UNABLE_TO_GROW_COLLECTION(Kind.ERROR,1052,"Unable to grow collection"),//
|
||||
UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE(Kind.ERROR,1053,"Unable to grow collection: unable to determine list element type"),//
|
||||
UNABLE_TO_CREATE_LIST_FOR_INDEXING(Kind.ERROR,1054,"Unable to dynamically create a List to replace a null value"),//
|
||||
UNABLE_TO_CREATE_MAP_FOR_INDEXING(Kind.ERROR,1055,"Unable to dynamically create a Map to replace a null value"),//
|
||||
UNABLE_TO_DYNAMICALLY_CREATE_OBJECT(Kind.ERROR,1056,"Unable to dynamically create instance of ''{0}'' to replace a null value"),//
|
||||
NO_BEAN_RESOLVER_REGISTERED(Kind.ERROR,1057,"No bean resolver registered in the context to resolve access to bean ''{0}''"),//
|
||||
EXCEPTION_DURING_BEAN_RESOLUTION(Kind.ERROR, 1058, "A problem occurred when trying to resolve bean ''{0}'':''{1}''"), //
|
||||
INVALID_BEAN_REFERENCE(Kind.ERROR,1059,"@ can only be followed by an identifier or a quoted name"),//
|
||||
TYPE_CONVERSION_ERROR(Kind.ERROR, 1001,
|
||||
"Type conversion problem, cannot convert from {0} to {1}"),
|
||||
|
||||
CONSTRUCTOR_NOT_FOUND(Kind.ERROR, 1002,
|
||||
"Constructor call: No suitable constructor found on type {0} for " +
|
||||
"arguments {1}"),
|
||||
|
||||
CONSTRUCTOR_INVOCATION_PROBLEM(Kind.ERROR, 1003,
|
||||
"A problem occurred whilst attempting to construct an object of type " +
|
||||
"''{0}'' using arguments ''{1}''"),
|
||||
|
||||
METHOD_NOT_FOUND(Kind.ERROR, 1004,
|
||||
"Method call: Method {0} cannot be found on {1} type"),
|
||||
|
||||
TYPE_NOT_FOUND(Kind.ERROR, 1005,
|
||||
"Type cannot be found ''{0}''"),
|
||||
|
||||
FUNCTION_NOT_DEFINED(Kind.ERROR, 1006,
|
||||
"The function ''{0}'' could not be found"),
|
||||
|
||||
PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1007,
|
||||
"Field or property ''{0}'' cannot be found on null"),
|
||||
|
||||
PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1008,
|
||||
"Field or property ''{0}'' cannot be found on object of type ''{1}''"),
|
||||
|
||||
PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1009,
|
||||
"Field or property ''{0}'' cannot be set on null"),
|
||||
|
||||
PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010,
|
||||
"Field or property ''{0}'' cannot be set on object of type ''{1}''"),
|
||||
|
||||
METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1011,
|
||||
"Method call: Attempted to call method {0} on null context object"),
|
||||
|
||||
CANNOT_INDEX_INTO_NULL_VALUE(Kind.ERROR, 1012,
|
||||
"Cannot index into a null value"),
|
||||
|
||||
NOT_COMPARABLE(Kind.ERROR, 1013,
|
||||
"Cannot compare instances of {0} and {1}"),
|
||||
|
||||
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1014,
|
||||
"Incorrect number of arguments for function, {0} supplied but " +
|
||||
"function takes {1}"),
|
||||
|
||||
INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1015,
|
||||
"Cannot perform selection on input data of type ''{0}''"),
|
||||
|
||||
RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1016,
|
||||
"Result of selection criteria is not boolean"),
|
||||
|
||||
BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST(Kind.ERROR, 1017,
|
||||
"Right operand for the 'between' operator has to be a two-element list"),
|
||||
|
||||
INVALID_PATTERN(Kind.ERROR, 1018,
|
||||
"Pattern is not valid ''{0}''"),
|
||||
|
||||
PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1019,
|
||||
"Projection is not supported on the type ''{0}''"),
|
||||
|
||||
ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1020,
|
||||
"The argument list of a lambda expression should never have getValue() " +
|
||||
"called upon it"),
|
||||
|
||||
EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1021,
|
||||
"A problem occurred whilst attempting to access the property " +
|
||||
"''{0}'': ''{1}''"),
|
||||
|
||||
FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1022,
|
||||
"The function ''{0}'' mapped to an object of type ''{1}'' which " +
|
||||
"cannot be invoked"),
|
||||
|
||||
EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1023,
|
||||
"A problem occurred whilst attempting to invoke the " +
|
||||
"function ''{0}'': ''{1}''"),
|
||||
|
||||
ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1024,
|
||||
"The array has ''{0}'' elements, index ''{1}'' is invalid"),
|
||||
|
||||
COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1025,
|
||||
"The collection has ''{0}'' elements, index ''{1}'' is invalid"),
|
||||
|
||||
STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1026,
|
||||
"The string has ''{0}'' characters, index ''{1}'' is invalid"),
|
||||
|
||||
INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1027,
|
||||
"Indexing into type ''{0}'' is not supported"),
|
||||
|
||||
INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1028,
|
||||
"The operator 'instanceof' needs the right operand to be a class, " +
|
||||
"not a ''{0}''"),
|
||||
|
||||
EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1029,
|
||||
"A problem occurred when trying to execute method ''{0}'' on object " +
|
||||
"of type ''{1}'': ''{2}''"),
|
||||
|
||||
OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1030,
|
||||
"The operator ''{0}'' is not supported between objects of type " +
|
||||
"''{1}'' and ''{2}''"),
|
||||
|
||||
PROBLEM_LOCATING_METHOD(Kind.ERROR, 1031,
|
||||
"Problem locating method {0} cannot on type {1}"),
|
||||
|
||||
SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1032,
|
||||
"setValue(ExpressionState, Object) not supported for ''{0}''"),
|
||||
|
||||
MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1033,
|
||||
"Method call of ''{0}'' is ambiguous, supported type conversions " +
|
||||
"allow multiple variants to match"),
|
||||
|
||||
EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1034,
|
||||
"A problem occurred whilst attempting to set the property ''{0}'': {1}"),
|
||||
|
||||
NOT_AN_INTEGER(Kind.ERROR, 1035,
|
||||
"The value ''{0}'' cannot be parsed as an int"),
|
||||
|
||||
NOT_A_LONG(Kind.ERROR, 1036,
|
||||
"The value ''{0}'' cannot be parsed as a long"),
|
||||
|
||||
INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1037,
|
||||
"First operand to matches operator must be a string. ''{0}'' is not"),
|
||||
|
||||
INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1038,
|
||||
"Second operand to matches operator must be a string. ''{0}'' is not"),
|
||||
|
||||
FUNCTION_MUST_BE_STATIC(Kind.ERROR, 1039,
|
||||
"Only static methods can be called via function references. " +
|
||||
"The method ''{0}'' referred to by name ''{1}'' is not static."),
|
||||
|
||||
NOT_A_REAL(Kind.ERROR, 1040,
|
||||
"The value ''{0}'' cannot be parsed as a double"),
|
||||
|
||||
MORE_INPUT(Kind.ERROR,1041,
|
||||
"After parsing a valid expression, there is still more data in " +
|
||||
"the expression: ''{0}''"),
|
||||
|
||||
RIGHT_OPERAND_PROBLEM(Kind.ERROR, 1042,
|
||||
"Problem parsing right operand"),
|
||||
|
||||
NOT_EXPECTED_TOKEN(Kind.ERROR, 1043,
|
||||
"Unexpected token. Expected ''{0}'' but was ''{1}''"),
|
||||
|
||||
OOD(Kind.ERROR, 1044,
|
||||
"Unexpectedly ran out of input"),
|
||||
|
||||
NON_TERMINATING_DOUBLE_QUOTED_STRING(Kind.ERROR, 1045,
|
||||
"Cannot find terminating \" for string"),
|
||||
|
||||
NON_TERMINATING_QUOTED_STRING(Kind.ERROR, 1046,
|
||||
"Cannot find terminating ' for string"),
|
||||
|
||||
MISSING_LEADING_ZERO_FOR_NUMBER(Kind.ERROR, 1047,
|
||||
"A real number must be prefixed by zero, it cannot start with just ''.''"),
|
||||
|
||||
REAL_CANNOT_BE_LONG(Kind.ERROR, 1048,
|
||||
"Real number cannot be suffixed with a long (L or l) suffix"),
|
||||
|
||||
UNEXPECTED_DATA_AFTER_DOT(Kind.ERROR, 1049,
|
||||
"Unexpected data after ''.'': ''{0}''"),
|
||||
|
||||
MISSING_CONSTRUCTOR_ARGS(Kind.ERROR, 1050,
|
||||
"The arguments '(...)' for the constructor call are missing"),
|
||||
|
||||
RUN_OUT_OF_ARGUMENTS(Kind.ERROR, 1051,
|
||||
"Unexpected ran out of arguments"),
|
||||
|
||||
UNABLE_TO_GROW_COLLECTION(Kind.ERROR, 1052,
|
||||
"Unable to grow collection"),
|
||||
|
||||
UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE(Kind.ERROR, 1053,
|
||||
"Unable to grow collection: unable to determine list element type"),
|
||||
|
||||
UNABLE_TO_CREATE_LIST_FOR_INDEXING(Kind.ERROR, 1054,
|
||||
"Unable to dynamically create a List to replace a null value"),
|
||||
|
||||
UNABLE_TO_CREATE_MAP_FOR_INDEXING(Kind.ERROR, 1055,
|
||||
"Unable to dynamically create a Map to replace a null value"),
|
||||
|
||||
UNABLE_TO_DYNAMICALLY_CREATE_OBJECT(Kind.ERROR, 1056,
|
||||
"Unable to dynamically create instance of ''{0}'' to replace a null value"),
|
||||
|
||||
NO_BEAN_RESOLVER_REGISTERED(Kind.ERROR, 1057,
|
||||
"No bean resolver registered in the context to resolve access to bean ''{0}''"),
|
||||
|
||||
EXCEPTION_DURING_BEAN_RESOLUTION(Kind.ERROR, 1058,
|
||||
"A problem occurred when trying to resolve bean ''{0}'':''{1}''"),
|
||||
|
||||
INVALID_BEAN_REFERENCE(Kind.ERROR, 1059,
|
||||
"@ can only be followed by an identifier or a quoted name"),
|
||||
|
||||
TYPE_NAME_EXPECTED_FOR_ARRAY_CONSTRUCTION(Kind.ERROR, 1060,
|
||||
"Expected the type of the new array to be specified as a String but found ''{0}''"), //
|
||||
"Expected the type of the new array to be specified as a String but found ''{0}''"),
|
||||
|
||||
INCORRECT_ELEMENT_TYPE_FOR_ARRAY(Kind.ERROR, 1061,
|
||||
"The array of type ''{0}'' cannot have an element of type ''{1}'' inserted"), //
|
||||
"The array of type ''{0}'' cannot have an element of type ''{1}'' inserted"),
|
||||
|
||||
MULTIDIM_ARRAY_INITIALIZER_NOT_SUPPORTED(Kind.ERROR, 1062,
|
||||
"Using an initializer to build a multi-dimensional array is not currently supported"), //
|
||||
MISSING_ARRAY_DIMENSION(Kind.ERROR, 1063, "A required array dimension has not been specified"), //
|
||||
INITIALIZER_LENGTH_INCORRECT(
|
||||
Kind.ERROR, 1064, "array initializer size does not match array dimensions"), //
|
||||
UNEXPECTED_ESCAPE_CHAR(Kind.ERROR,1065,"unexpected escape character."), //
|
||||
OPERAND_NOT_INCREMENTABLE(Kind.ERROR,1066,"the expression component ''{0}'' does not support increment"), //
|
||||
OPERAND_NOT_DECREMENTABLE(Kind.ERROR,1067,"the expression component ''{0}'' does not support decrement"), //
|
||||
NOT_ASSIGNABLE(Kind.ERROR,1068,"the expression component ''{0}'' is not assignable"), //
|
||||
MISSING_CHARACTER(Kind.ERROR,1069,"missing expected character ''{0}''"),
|
||||
LEFT_OPERAND_PROBLEM(Kind.ERROR,1070, "Problem parsing left operand"),
|
||||
MISSING_SELECTION_EXPRESSION(Kind.ERROR, 1071, "A required selection expression has not been specified");
|
||||
"Using an initializer to build a multi-dimensional array is not currently supported"),
|
||||
|
||||
MISSING_ARRAY_DIMENSION(Kind.ERROR, 1063,
|
||||
"A required array dimension has not been specified"),
|
||||
|
||||
INITIALIZER_LENGTH_INCORRECT(Kind.ERROR, 1064,
|
||||
"array initializer size does not match array dimensions"),
|
||||
|
||||
UNEXPECTED_ESCAPE_CHAR(Kind.ERROR, 1065, "unexpected escape character."),
|
||||
|
||||
OPERAND_NOT_INCREMENTABLE(Kind.ERROR, 1066,
|
||||
"the expression component ''{0}'' does not support increment"),
|
||||
|
||||
OPERAND_NOT_DECREMENTABLE(Kind.ERROR, 1067,
|
||||
"the expression component ''{0}'' does not support decrement"),
|
||||
|
||||
NOT_ASSIGNABLE(Kind.ERROR, 1068,
|
||||
"the expression component ''{0}'' is not assignable"),
|
||||
|
||||
MISSING_CHARACTER(Kind.ERROR, 1069,
|
||||
"missing expected character ''{0}''"),
|
||||
|
||||
LEFT_OPERAND_PROBLEM(Kind.ERROR, 1070,
|
||||
"Problem parsing left operand"),
|
||||
|
||||
MISSING_SELECTION_EXPRESSION(Kind.ERROR, 1071,
|
||||
"A required selection expression has not been specified");
|
||||
|
||||
private Kind kind;
|
||||
private int code;
|
||||
|
|
@ -134,23 +285,17 @@ public enum SpelMessage {
|
|||
*/
|
||||
public String formatMessage(int pos, Object... inserts) {
|
||||
StringBuilder formattedMessage = new StringBuilder();
|
||||
formattedMessage.append("EL").append(code);
|
||||
switch (kind) {
|
||||
// case WARNING:
|
||||
// formattedMessage.append("W");
|
||||
// break;
|
||||
// case INFO:
|
||||
// formattedMessage.append("I");
|
||||
// break;
|
||||
case ERROR:
|
||||
formattedMessage.append("E");
|
||||
break;
|
||||
formattedMessage.append("EL").append(this.code);
|
||||
switch (this.kind) {
|
||||
case ERROR:
|
||||
formattedMessage.append("E");
|
||||
break;
|
||||
}
|
||||
formattedMessage.append(":");
|
||||
if (pos != -1) {
|
||||
formattedMessage.append("(pos ").append(pos).append("): ");
|
||||
}
|
||||
formattedMessage.append(MessageFormat.format(message, inserts));
|
||||
formattedMessage.append(MessageFormat.format(this.message, inserts));
|
||||
return formattedMessage.toString();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -28,14 +28,16 @@ import org.springframework.expression.TypedValue;
|
|||
public interface SpelNode {
|
||||
|
||||
/**
|
||||
* Evaluate the expression node in the context of the supplied expression state and return the value.
|
||||
* Evaluate the expression node in the context of the supplied expression state and
|
||||
* return the value.
|
||||
* @param expressionState the current expression state (includes the context)
|
||||
* @return the value of this node evaluated against the specified state
|
||||
*/
|
||||
Object getValue(ExpressionState expressionState) throws EvaluationException;
|
||||
|
||||
/**
|
||||
* Evaluate the expression node in the context of the supplied expression state and return the typed value.
|
||||
* Evaluate the expression node in the context of the supplied expression state and
|
||||
* return the typed value.
|
||||
* @param expressionState the current expression state (includes the context)
|
||||
* @return the type value of this node evaluated against the specified state
|
||||
*/
|
||||
|
|
@ -51,11 +53,13 @@ public interface SpelNode {
|
|||
boolean isWritable(ExpressionState expressionState) throws EvaluationException;
|
||||
|
||||
/**
|
||||
* Evaluate the expression to a node and then set the new value on that node. For example, if the expression
|
||||
* evaluates to a property reference then the property will be set to the new value.
|
||||
* Evaluate the expression to a node and then set the new value on that node. For
|
||||
* example, if the expression evaluates to a property reference then the property will
|
||||
* be set to the new value.
|
||||
* @param expressionState the current expression state (includes the context)
|
||||
* @param newValue the new value
|
||||
* @throws EvaluationException if any problem occurs evaluating the expression or setting the new value
|
||||
* @throws EvaluationException if any problem occurs evaluating the expression or
|
||||
* setting the new value
|
||||
*/
|
||||
void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException;
|
||||
|
||||
|
|
@ -78,7 +82,8 @@ public interface SpelNode {
|
|||
/**
|
||||
* Determine the class of the object passed in, unless it is already a class object.
|
||||
* @param obj the object that the caller wants the class of
|
||||
* @return the class of the object if it is not already a class object, or null if the object is null
|
||||
* @return the class of the object if it is not already a class object, or null if the
|
||||
* object is null
|
||||
*/
|
||||
Class<?> getObjectClass(Object obj);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,24 +19,20 @@ import org.springframework.expression.ParseException;
|
|||
|
||||
|
||||
/**
|
||||
* Root exception for Spring EL related exceptions. Rather than holding a hard coded string indicating the problem, it
|
||||
* records a message key and the inserts for the message. See {@link SpelMessage} for the list of all possible messages
|
||||
* that can occur.
|
||||
*
|
||||
* Root exception for Spring EL related exceptions. Rather than holding a hard coded
|
||||
* string indicating the problem, it records a message key and the inserts for the
|
||||
* message. See {@link SpelMessage} for the list of all possible messages that can occur.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SpelParseException extends ParseException {
|
||||
|
||||
private SpelMessage message;
|
||||
private Object[] inserts;
|
||||
private final SpelMessage message;
|
||||
|
||||
private final Object[] inserts;
|
||||
|
||||
// public SpelParseException(String expressionString, int position, Throwable cause, SpelMessages message, Object... inserts) {
|
||||
// super(expressionString, position, message.formatMessage(position,inserts), cause);
|
||||
// this.message = message;
|
||||
// this.inserts = inserts;
|
||||
// }
|
||||
|
||||
public SpelParseException(String expressionString, int position, SpelMessage message, Object... inserts) {
|
||||
super(expressionString, position, message.formatMessage(position,inserts));
|
||||
|
|
@ -59,36 +55,14 @@ public class SpelParseException extends ParseException {
|
|||
this.inserts = inserts;
|
||||
}
|
||||
|
||||
//
|
||||
// public SpelException(Throwable cause, SpelMessages message, Object... inserts) {
|
||||
// super(cause);
|
||||
// this.message = message;
|
||||
// this.inserts = inserts;
|
||||
// }
|
||||
//
|
||||
// public SpelException(int position, SpelMessages message, Object... inserts) {
|
||||
// super((Throwable)null);
|
||||
// this.position = position;
|
||||
// this.message = message;
|
||||
// this.inserts = inserts;
|
||||
// }
|
||||
//
|
||||
// public SpelException(SpelMessages message, Object... inserts) {
|
||||
// super((Throwable)null);
|
||||
// this.message = message;
|
||||
// this.inserts = inserts;
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* @return a formatted message with inserts applied
|
||||
*/
|
||||
@Override
|
||||
public String getMessage() {
|
||||
if (message != null)
|
||||
return message.formatMessage(position, inserts);
|
||||
else
|
||||
return super.getMessage();
|
||||
return (this.message != null ? this.message.formatMessage(this.position, this.inserts)
|
||||
: super.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -102,7 +76,7 @@ public class SpelParseException extends ParseException {
|
|||
* @return the message inserts
|
||||
*/
|
||||
public Object[] getInserts() {
|
||||
return inserts;
|
||||
return this.inserts;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class SpelParserConfiguration {
|
|||
|
||||
private final boolean autoGrowCollections;
|
||||
|
||||
private int maximumAutoGrowSize;
|
||||
private final int maximumAutoGrowSize;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -21,7 +21,8 @@ import org.springframework.expression.TypedValue;
|
|||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <p>Example: 'someNumberProperty=42'
|
||||
*
|
||||
|
|
@ -30,21 +31,23 @@ import org.springframework.expression.spel.ExpressionState;
|
|||
*/
|
||||
public class Assign extends SpelNodeImpl {
|
||||
|
||||
|
||||
public Assign(int pos,SpelNodeImpl... operands) {
|
||||
super(pos,operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue newValue = children[1].getValueInternal(state);
|
||||
TypedValue newValue = this.children[1].getValueInternal(state);
|
||||
getChild(0).setValue(state, newValue.getValue());
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
return new StringBuilder().append(getChild(0).toStringAST()).append("=").append(getChild(1).toStringAST())
|
||||
.toString();
|
||||
return new StringBuilder().append(getChild(0).toStringAST()).append("=").append(
|
||||
getChild(1).toStringAST()).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -30,13 +30,15 @@ import org.springframework.expression.PropertyAccessor;
|
|||
public class AstUtils {
|
||||
|
||||
/**
|
||||
* Determines the set of property resolvers that should be used to try and access a property on the specified target
|
||||
* type. The resolvers are considered to be in an ordered list, however in the returned list any that are exact
|
||||
* matches for the input target type (as opposed to 'general' resolvers that could work for any type) are placed at
|
||||
* the start of the list. In addition, there are specific resolvers that exactly name the class in question and
|
||||
* resolvers that name a specific class but it is a supertype of the class we have. These are put at the end of the
|
||||
* specific resolvers set and will be tried after exactly matching accessors but before generic accessors.
|
||||
*
|
||||
* Determines the set of property resolvers that should be used to try and access a
|
||||
* property on the specified target type. The resolvers are considered to be in an
|
||||
* ordered list, however in the returned list any that are exact matches for the input
|
||||
* target type (as opposed to 'general' resolvers that could work for any type) are
|
||||
* placed at the start of the list. In addition, there are specific resolvers that
|
||||
* exactly name the class in question and resolvers that name a specific class but it
|
||||
* is a supertype of the class we have. These are put at the end of the specific
|
||||
* resolvers set and will be tried after exactly matching accessors but before generic
|
||||
* accessors.
|
||||
* @param targetType the type upon which property access is being attempted
|
||||
* @return a list of resolvers that should be tried in order to access the property
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -31,25 +31,31 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
*/
|
||||
public class BeanReference extends SpelNodeImpl {
|
||||
|
||||
private String beanname;
|
||||
private final String beanname;
|
||||
|
||||
|
||||
public BeanReference(int pos,String beanname) {
|
||||
super(pos);
|
||||
this.beanname = beanname;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
BeanResolver beanResolver = state.getEvaluationContext().getBeanResolver();
|
||||
if (beanResolver==null) {
|
||||
throw new SpelEvaluationException(getStartPosition(),SpelMessage.NO_BEAN_RESOLVER_REGISTERED, beanname);
|
||||
throw new SpelEvaluationException(getStartPosition(),
|
||||
SpelMessage.NO_BEAN_RESOLVER_REGISTERED, this.beanname);
|
||||
}
|
||||
|
||||
try {
|
||||
TypedValue bean = new TypedValue(beanResolver.resolve(state.getEvaluationContext(),beanname));
|
||||
TypedValue bean = new TypedValue(beanResolver.resolve(
|
||||
state.getEvaluationContext(), this.beanname));
|
||||
return bean;
|
||||
} catch (AccessException ae) {
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
throw new SpelEvaluationException( getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_BEAN_RESOLUTION,
|
||||
beanname, ae.getMessage());
|
||||
this.beanname, ae.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,10 +63,11 @@ public class BeanReference extends SpelNodeImpl {
|
|||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("@");
|
||||
if (beanname.indexOf('.')==-1) {
|
||||
sb.append(beanname);
|
||||
} else {
|
||||
sb.append("'").append(beanname).append("'");
|
||||
if (this.beanname.indexOf('.') == -1) {
|
||||
sb.append(this.beanname);
|
||||
}
|
||||
else {
|
||||
sb.append("'").append(this.beanname).append("'");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -27,11 +27,13 @@ public class BooleanLiteral extends Literal {
|
|||
|
||||
private final BooleanTypedValue value;
|
||||
|
||||
|
||||
public BooleanLiteral(String payload, int pos, boolean value) {
|
||||
super(payload, pos);
|
||||
this.value = BooleanTypedValue.forValue(value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -39,32 +39,35 @@ public class CompoundExpression extends SpelNodeImpl {
|
|||
|
||||
@Override
|
||||
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
|
||||
if (getChildCount()==1) {
|
||||
return children[0].getValueRef(state);
|
||||
if (getChildCount() == 1) {
|
||||
return this.children[0].getValueRef(state);
|
||||
}
|
||||
TypedValue result = null;
|
||||
SpelNodeImpl nextNode = null;
|
||||
try {
|
||||
nextNode = children[0];
|
||||
nextNode = this.children[0];
|
||||
result = nextNode.getValueInternal(state);
|
||||
int cc = getChildCount();
|
||||
for (int i = 1; i < cc-1; i++) {
|
||||
for (int i = 1; i < cc - 1; i++) {
|
||||
try {
|
||||
state.pushActiveContextObject(result);
|
||||
nextNode = children[i];
|
||||
nextNode = this.children[i];
|
||||
result = nextNode.getValueInternal(state);
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
}
|
||||
try {
|
||||
state.pushActiveContextObject(result);
|
||||
nextNode = children[cc-1];
|
||||
nextNode = this.children[cc-1];
|
||||
return nextNode.getValueRef(state);
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
} catch (SpelEvaluationException ee) {
|
||||
}
|
||||
catch (SpelEvaluationException ee) {
|
||||
// Correct the position for the error before re-throwing
|
||||
ee.setPosition(nextNode.getStartPosition());
|
||||
throw ee;
|
||||
|
|
@ -96,7 +99,9 @@ public class CompoundExpression extends SpelNodeImpl {
|
|||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
if (i>0) { sb.append("."); }
|
||||
if (i > 0) {
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(getChild(i).toStringAST());
|
||||
}
|
||||
return sb.toString();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -132,7 +132,8 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
Throwable rootCause = ae.getCause().getCause();
|
||||
if (rootCause instanceof RuntimeException) {
|
||||
throw (RuntimeException) rootCause;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
String typename = (String) this.children[0].getValueInternal(state).getValue();
|
||||
throw new SpelEvaluationException(getStartPosition(), rootCause,
|
||||
SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM, typename, FormatHelper
|
||||
|
|
@ -153,9 +154,9 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
return executorToUse.execute(state.getEvaluationContext(), arguments);
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
throw new SpelEvaluationException(getStartPosition(), ae, SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM,
|
||||
typename, FormatHelper.formatMethodForMessage("", argumentTypes));
|
||||
|
||||
throw new SpelEvaluationException(getStartPosition(), ae,
|
||||
SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM, typename,
|
||||
FormatHelper.formatMethodForMessage("", argumentTypes));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,8 +169,9 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
* @return a reusable ConstructorExecutor that can be invoked to run the constructor or null
|
||||
* @throws SpelEvaluationException if there is a problem locating the constructor
|
||||
*/
|
||||
private ConstructorExecutor findExecutorForConstructor(String typename, List<TypeDescriptor> argumentTypes,
|
||||
ExpressionState state) throws SpelEvaluationException {
|
||||
private ConstructorExecutor findExecutorForConstructor(String typename,
|
||||
List<TypeDescriptor> argumentTypes, ExpressionState state)
|
||||
throws SpelEvaluationException {
|
||||
|
||||
EvaluationContext eContext = state.getEvaluationContext();
|
||||
List<ConstructorResolver> cResolvers = eContext.getConstructorResolvers();
|
||||
|
|
@ -202,8 +204,9 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
sb.append(getChild(index++).toStringAST());
|
||||
sb.append("(");
|
||||
for (int i = index; i < getChildCount(); i++) {
|
||||
if (i > index)
|
||||
if (i > index) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(getChild(i).toStringAST());
|
||||
}
|
||||
sb.append(")");
|
||||
|
|
@ -221,8 +224,8 @@ public class ConstructorReference extends SpelNodeImpl {
|
|||
Object intendedArrayType = getChild(0).getValue(state);
|
||||
if (!(intendedArrayType instanceof String)) {
|
||||
throw new SpelEvaluationException(getChild(0).getStartPosition(),
|
||||
SpelMessage.TYPE_NAME_EXPECTED_FOR_ARRAY_CONSTRUCTION, FormatHelper
|
||||
.formatClassNameForMessage(intendedArrayType.getClass()));
|
||||
SpelMessage.TYPE_NAME_EXPECTED_FOR_ARRAY_CONSTRUCTION,
|
||||
FormatHelper.formatClassNameForMessage(intendedArrayType.getClass()));
|
||||
}
|
||||
String type = (String) intendedArrayType;
|
||||
Class<?> componentType;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -21,8 +21,8 @@ import org.springframework.expression.TypedValue;
|
|||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
* Represents the elvis operator ?:. For an expression "a?:b" if a is not null, the value of the expression
|
||||
* is "a", if a is null then the value of the expression is "b".
|
||||
* Represents the elvis operator ?:. For an expression "a?:b" if a is not null, the value
|
||||
* of the expression is "a", if a is null then the value of the expression is "b".
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -33,25 +33,30 @@ public class Elvis extends SpelNodeImpl {
|
|||
super(pos,args);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate the condition and if not null, return it. If it is null return the other value.
|
||||
* Evaluate the condition and if not null, return it. If it is null return the other
|
||||
* value.
|
||||
* @param state the expression state
|
||||
* @throws EvaluationException if the condition does not evaluate correctly to a boolean or there is a problem
|
||||
* executing the chosen alternative
|
||||
* @throws EvaluationException if the condition does not evaluate correctly to a
|
||||
* boolean or there is a problem executing the chosen alternative
|
||||
*/
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue value = children[0].getValueInternal(state);
|
||||
if (value.getValue()!=null && !((value.getValue() instanceof String) && ((String)value.getValue()).length()==0)) {
|
||||
TypedValue value = this.children[0].getValueInternal(state);
|
||||
if ((value.getValue() != null) && !((value.getValue() instanceof String) &&
|
||||
((String) value.getValue()).length() == 0)) {
|
||||
return value;
|
||||
} else {
|
||||
return children[1].getValueInternal(state);
|
||||
}
|
||||
else {
|
||||
return this.children[1].getValueInternal(state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
return new StringBuilder().append(getChild(0).toStringAST()).append(" ?: ").append(getChild(1).toStringAST()).toString();
|
||||
return new StringBuilder().append(getChild(0).toStringAST()).append(" ?: ").append(
|
||||
getChild(1).toStringAST()).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
|
@ -24,6 +25,7 @@ import org.springframework.expression.TypedValue;
|
|||
* @since 3.2
|
||||
*/
|
||||
public class FloatLiteral extends Literal {
|
||||
|
||||
private final TypedValue value;
|
||||
|
||||
FloatLiteral(String payload, int pos, float value) {
|
||||
|
|
@ -31,6 +33,7 @@ public class FloatLiteral extends Literal {
|
|||
this.value = new TypedValue(value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -75,7 +75,8 @@ public class FormatHelper {
|
|||
for (int i = 0; i < dims; i++) {
|
||||
fmtd.append("[]");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
fmtd.append(clazz.getName());
|
||||
}
|
||||
return fmtd.toString();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -31,14 +31,15 @@ import org.springframework.expression.spel.support.ReflectionHelper;
|
|||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A function reference is of the form "#someFunction(a,b,c)". Functions may be defined in the context prior to the
|
||||
* expression being evaluated or within the expression itself using a lambda function definition. For example: Lambda
|
||||
* function definition in an expression: "(#max = {|x,y|$x>$y?$x:$y};max(2,3))" Calling context defined function:
|
||||
* "#isEven(37)". Functions may also be static java methods, registered in the context prior to invocation of the
|
||||
* expression.
|
||||
* A function reference is of the form "#someFunction(a,b,c)". Functions may be defined in
|
||||
* the context prior to the expression being evaluated or within the expression itself
|
||||
* using a lambda function definition. For example: Lambda function definition in an
|
||||
* expression: "(#max = {|x,y|$x>$y?$x:$y};max(2,3))" Calling context defined function:
|
||||
* "#isEven(37)". Functions may also be static java methods, registered in the context
|
||||
* prior to invocation of the expression.
|
||||
*
|
||||
* <p>Functions are very simplistic, the arguments are not part of the definition (right now),
|
||||
* so the names must be unique.
|
||||
* <p>Functions are very simplistic, the arguments are not part of the definition (right
|
||||
* now), so the names must be unique.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -47,21 +48,23 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
|
||||
private final String name;
|
||||
|
||||
|
||||
public FunctionReference(String functionName, int pos, SpelNodeImpl... arguments) {
|
||||
super(pos,arguments);
|
||||
name = functionName;
|
||||
this.name = functionName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue o = state.lookupVariable(name);
|
||||
TypedValue o = state.lookupVariable(this.name);
|
||||
if (o == null) {
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.FUNCTION_NOT_DEFINED, name);
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.FUNCTION_NOT_DEFINED, this.name);
|
||||
}
|
||||
|
||||
// Two possibilities: a lambda function or a Java static method registered as a function
|
||||
if (!(o.getValue() instanceof Method)) {
|
||||
throw new SpelEvaluationException(SpelMessage.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, name, o.getClass());
|
||||
throw new SpelEvaluationException(SpelMessage.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, this.name, o.getClass());
|
||||
}
|
||||
try {
|
||||
return executeFunctionJLRMethod(state, (Method) o.getValue());
|
||||
|
|
@ -89,9 +92,9 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
}
|
||||
// Only static methods can be called in this way
|
||||
if (!Modifier.isStatic(method.getModifiers())) {
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.FUNCTION_MUST_BE_STATIC, method
|
||||
.getDeclaringClass().getName()
|
||||
+ "." + method.getName(), name);
|
||||
throw new SpelEvaluationException(getStartPosition(),
|
||||
SpelMessage.FUNCTION_MUST_BE_STATIC,
|
||||
method.getDeclaringClass().getName() + "." + method.getName(), this.name);
|
||||
}
|
||||
|
||||
// Convert arguments if necessary and remap them for varargs if required
|
||||
|
|
@ -100,7 +103,8 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
ReflectionHelper.convertAllArguments(converter, functionArgs, method);
|
||||
}
|
||||
if (method.isVarArgs()) {
|
||||
functionArgs = ReflectionHelper.setupArgumentsForVarargsInvocation(method.getParameterTypes(), functionArgs);
|
||||
functionArgs = ReflectionHelper.setupArgumentsForVarargsInvocation(
|
||||
method.getParameterTypes(), functionArgs);
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -116,11 +120,12 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder("#").append(name);
|
||||
StringBuilder sb = new StringBuilder("#").append(this.name);
|
||||
sb.append("(");
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
if (i > 0)
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(getChild(i).toStringAST());
|
||||
}
|
||||
sb.append(")");
|
||||
|
|
@ -137,7 +142,7 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
// Compute arguments to the function
|
||||
Object[] arguments = new Object[getChildCount()];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
arguments[i] = children[i].getValueInternal(state).getValue();
|
||||
arguments[i] = this.children[i].getValueInternal(state).getValue();
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -27,14 +27,16 @@ public class Identifier extends SpelNodeImpl {
|
|||
|
||||
private final TypedValue id;
|
||||
|
||||
|
||||
public Identifier(String payload,int pos) {
|
||||
super(pos);
|
||||
this.id = new TypedValue(payload);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
return (String)this.id.getValue();
|
||||
return (String) this.id.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -33,9 +33,8 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
|
||||
|
||||
/**
|
||||
* An Indexer can index into some proceeding structure to access a particular
|
||||
* piece of it. Supported structures are: strings/collections
|
||||
* (lists/sets)/arrays
|
||||
* An Indexer can index into some proceeding structure to access a particular piece of it.
|
||||
* Supported structures are: strings/collections (lists/sets)/arrays
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Phillip Webb
|
||||
|
|
@ -95,26 +94,28 @@ public class Indexer extends SpelNodeImpl {
|
|||
|
||||
private final Object array;
|
||||
|
||||
private final int idx;
|
||||
private final int index;
|
||||
|
||||
private final TypeDescriptor typeDescriptor;
|
||||
|
||||
ArrayIndexingValueRef(TypeConverter typeConverter, Object array, int idx, TypeDescriptor typeDescriptor) {
|
||||
|
||||
ArrayIndexingValueRef(TypeConverter typeConverter, Object array, int index, TypeDescriptor typeDescriptor) {
|
||||
this.typeConverter = typeConverter;
|
||||
this.array = array;
|
||||
this.idx = idx;
|
||||
this.index = index;
|
||||
this.typeDescriptor = typeDescriptor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValue() {
|
||||
Object arrayElement = accessArrayElement(this.array, this.idx);
|
||||
Object arrayElement = accessArrayElement(this.array, this.index);
|
||||
return new TypedValue(arrayElement, this.typeDescriptor.elementTypeDescriptor(arrayElement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object newValue) {
|
||||
setArrayElement(this.typeConverter, this.array, this.idx, newValue,
|
||||
setArrayElement(this.typeConverter, this.array, this.index, newValue,
|
||||
this.typeDescriptor.getElementTypeDescriptor().getType());
|
||||
}
|
||||
|
||||
|
|
@ -136,17 +137,21 @@ public class Indexer extends SpelNodeImpl {
|
|||
|
||||
private final TypeDescriptor mapEntryTypeDescriptor;
|
||||
|
||||
MapIndexingValueRef(TypeConverter typeConverter, Map map, Object key, TypeDescriptor mapEntryTypeDescriptor) {
|
||||
|
||||
MapIndexingValueRef(TypeConverter typeConverter, Map map, Object key,
|
||||
TypeDescriptor mapEntryTypeDescriptor) {
|
||||
this.typeConverter = typeConverter;
|
||||
this.map = map;
|
||||
this.key = key;
|
||||
this.mapEntryTypeDescriptor = mapEntryTypeDescriptor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValue() {
|
||||
Object value = this.map.get(this.key);
|
||||
return new TypedValue(value, this.mapEntryTypeDescriptor.getMapValueTypeDescriptor(value));
|
||||
return new TypedValue(value,
|
||||
this.mapEntryTypeDescriptor.getMapValueTypeDescriptor(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -171,71 +176,75 @@ public class Indexer extends SpelNodeImpl {
|
|||
|
||||
private final String name;
|
||||
|
||||
private final EvaluationContext eContext;
|
||||
private final EvaluationContext evaluationContext;
|
||||
|
||||
private final TypeDescriptor targetObjectTypeDescriptor;
|
||||
|
||||
private final TypeDescriptor td;
|
||||
|
||||
public PropertyIndexingValueRef(Object targetObject, String value, EvaluationContext evaluationContext,
|
||||
TypeDescriptor targetObjectTypeDescriptor) {
|
||||
this.targetObject = targetObject;
|
||||
this.name = value;
|
||||
this.eContext = evaluationContext;
|
||||
this.td = targetObjectTypeDescriptor;
|
||||
this.evaluationContext = evaluationContext;
|
||||
this.targetObjectTypeDescriptor = targetObjectTypeDescriptor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValue() {
|
||||
Class<?> targetObjectRuntimeClass = getObjectClass(targetObject);
|
||||
Class<?> targetObjectRuntimeClass = getObjectClass(this.targetObject);
|
||||
try {
|
||||
if (cachedReadName != null && cachedReadName.equals(name) && cachedReadTargetType != null &&
|
||||
cachedReadTargetType.equals(targetObjectRuntimeClass)) {
|
||||
if (Indexer.this.cachedReadName != null && Indexer.this.cachedReadName.equals(this.name) && Indexer.this.cachedReadTargetType != null &&
|
||||
Indexer.this.cachedReadTargetType.equals(targetObjectRuntimeClass)) {
|
||||
// it is OK to use the cached accessor
|
||||
return cachedReadAccessor.read(this.eContext, this.targetObject, this.name);
|
||||
return Indexer.this.cachedReadAccessor.read(this.evaluationContext, this.targetObject, this.name);
|
||||
}
|
||||
List<PropertyAccessor> accessorsToTry =
|
||||
AstUtils.getPropertyAccessorsToTry(targetObjectRuntimeClass, eContext.getPropertyAccessors());
|
||||
|
||||
List<PropertyAccessor> accessorsToTry = AstUtils.getPropertyAccessorsToTry(
|
||||
targetObjectRuntimeClass, this.evaluationContext.getPropertyAccessors());
|
||||
|
||||
if (accessorsToTry != null) {
|
||||
for (PropertyAccessor accessor : accessorsToTry) {
|
||||
if (accessor.canRead(this.eContext, this.targetObject, this.name)) {
|
||||
if (accessor.canRead(this.evaluationContext, this.targetObject, this.name)) {
|
||||
if (accessor instanceof ReflectivePropertyAccessor) {
|
||||
accessor = ((ReflectivePropertyAccessor) accessor).createOptimalAccessor(
|
||||
this.eContext, this.targetObject, this.name);
|
||||
this.evaluationContext, this.targetObject, this.name);
|
||||
}
|
||||
cachedReadAccessor = accessor;
|
||||
cachedReadName = this.name;
|
||||
cachedReadTargetType = targetObjectRuntimeClass;
|
||||
return accessor.read(this.eContext, this.targetObject, this.name);
|
||||
Indexer.this.cachedReadAccessor = accessor;
|
||||
Indexer.this.cachedReadName = this.name;
|
||||
Indexer.this.cachedReadTargetType = targetObjectRuntimeClass;
|
||||
return accessor.read(this.evaluationContext, this.targetObject, this.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (AccessException ex) {
|
||||
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
||||
this.td.toString());
|
||||
this.targetObjectTypeDescriptor.toString());
|
||||
}
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
||||
this.td.toString());
|
||||
this.targetObjectTypeDescriptor.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object newValue) {
|
||||
Class<?> contextObjectClass = getObjectClass(targetObject);
|
||||
Class<?> contextObjectClass = getObjectClass(this.targetObject);
|
||||
try {
|
||||
if (cachedWriteName != null && cachedWriteName.equals(name) && cachedWriteTargetType != null &&
|
||||
cachedWriteTargetType.equals(contextObjectClass)) {
|
||||
if (Indexer.this.cachedWriteName != null && Indexer.this.cachedWriteName.equals(this.name) && Indexer.this.cachedWriteTargetType != null &&
|
||||
Indexer.this.cachedWriteTargetType.equals(contextObjectClass)) {
|
||||
// it is OK to use the cached accessor
|
||||
cachedWriteAccessor.write(this.eContext, this.targetObject, this.name, newValue);
|
||||
Indexer.this.cachedWriteAccessor.write(this.evaluationContext, this.targetObject, this.name, newValue);
|
||||
return;
|
||||
}
|
||||
List<PropertyAccessor> accessorsToTry =
|
||||
AstUtils.getPropertyAccessorsToTry(contextObjectClass, this.eContext.getPropertyAccessors());
|
||||
AstUtils.getPropertyAccessorsToTry(contextObjectClass, this.evaluationContext.getPropertyAccessors());
|
||||
if (accessorsToTry != null) {
|
||||
for (PropertyAccessor accessor : accessorsToTry) {
|
||||
if (accessor.canWrite(this.eContext, this.targetObject, this.name)) {
|
||||
cachedWriteName = this.name;
|
||||
cachedWriteTargetType = contextObjectClass;
|
||||
cachedWriteAccessor = accessor;
|
||||
accessor.write(this.eContext, this.targetObject, this.name, newValue);
|
||||
if (accessor.canWrite(this.evaluationContext, this.targetObject, this.name)) {
|
||||
Indexer.this.cachedWriteName = this.name;
|
||||
Indexer.this.cachedWriteTargetType = contextObjectClass;
|
||||
Indexer.this.cachedWriteAccessor = accessor;
|
||||
accessor.write(this.evaluationContext, this.targetObject, this.name, newValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -267,7 +276,8 @@ public class Indexer extends SpelNodeImpl {
|
|||
|
||||
private final boolean growCollection;
|
||||
|
||||
private int maximumSize;
|
||||
private final int maximumSize;
|
||||
|
||||
|
||||
CollectionIndexingValueRef(Collection collection, int index, TypeDescriptor collectionEntryTypeDescriptor,
|
||||
TypeConverter typeConverter, boolean growCollection, int maximumSize) {
|
||||
|
|
@ -279,6 +289,7 @@ public class Indexer extends SpelNodeImpl {
|
|||
this.maximumSize = maximumSize;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValue() {
|
||||
growCollectionIfNecessary();
|
||||
|
|
@ -356,19 +367,21 @@ public class Indexer extends SpelNodeImpl {
|
|||
|
||||
private final int index;
|
||||
|
||||
private final TypeDescriptor td;
|
||||
private final TypeDescriptor typeDescriptor;
|
||||
|
||||
public StringIndexingLValue(String target, int index, TypeDescriptor td) {
|
||||
|
||||
public StringIndexingLValue(String target, int index, TypeDescriptor typeDescriptor) {
|
||||
this.target = target;
|
||||
this.index = index;
|
||||
this.td = td;
|
||||
this.typeDescriptor = typeDescriptor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValue() {
|
||||
if (this.index >= this.target.length()) {
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.STRING_INDEX_OUT_OF_BOUNDS,
|
||||
this.target.length(), index);
|
||||
this.target.length(), this.index);
|
||||
}
|
||||
return new TypedValue(String.valueOf(this.target.charAt(this.index)));
|
||||
}
|
||||
|
|
@ -376,7 +389,7 @@ public class Indexer extends SpelNodeImpl {
|
|||
@Override
|
||||
public void setValue(Object newValue) {
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
||||
this.td.toString());
|
||||
this.typeDescriptor.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -387,6 +400,7 @@ public class Indexer extends SpelNodeImpl {
|
|||
|
||||
@Override
|
||||
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
|
||||
|
||||
TypedValue context = state.getActiveContextObject();
|
||||
Object targetObject = context.getValue();
|
||||
TypeDescriptor targetObjectTypeDescriptor = context.getTypeDescriptor();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -35,11 +36,13 @@ public class InlineList extends SpelNodeImpl {
|
|||
// if the list is purely literals, it is a constant value and can be computed and cached
|
||||
TypedValue constant = null; // TODO must be immutable list
|
||||
|
||||
|
||||
public InlineList(int pos, SpelNodeImpl... args) {
|
||||
super(pos, args);
|
||||
checkIfConstant();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If all the components of the list are constants, or lists that themselves contain constants, then a constant list
|
||||
* can be built to represent this node. This will speed up later getValue calls and reduce the amount of garbage
|
||||
|
|
@ -55,7 +58,8 @@ public class InlineList extends SpelNodeImpl {
|
|||
if (!inlineList.isConstant()) {
|
||||
isConstant = false;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
isConstant = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +71,8 @@ public class InlineList extends SpelNodeImpl {
|
|||
SpelNode child = getChild(c);
|
||||
if ((child instanceof Literal)) {
|
||||
constantList.add(((Literal) child).getLiteralValue().getValue());
|
||||
} else if (child instanceof InlineList) {
|
||||
}
|
||||
else if (child instanceof InlineList) {
|
||||
constantList.add(((InlineList) child).getConstantValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -77,9 +82,10 @@ public class InlineList extends SpelNodeImpl {
|
|||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException {
|
||||
if (constant != null) {
|
||||
return constant;
|
||||
} else {
|
||||
if (this.constant != null) {
|
||||
return this.constant;
|
||||
}
|
||||
else {
|
||||
List<Object> returnValue = new ArrayList<Object>();
|
||||
int childcount = getChildCount();
|
||||
for (int c = 0; c < childcount; c++) {
|
||||
|
|
@ -109,12 +115,12 @@ public class InlineList extends SpelNodeImpl {
|
|||
* @return whether this list is a constant value
|
||||
*/
|
||||
public boolean isConstant() {
|
||||
return constant != null;
|
||||
return this.constant != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Object> getConstantValue() {
|
||||
return (List<Object>) constant.getValue();
|
||||
return (List<Object>) this.constant.getValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -27,11 +27,13 @@ public class IntLiteral extends Literal {
|
|||
|
||||
private final TypedValue value;
|
||||
|
||||
|
||||
IntLiteral(String payload, int pos, int value) {
|
||||
super(payload, pos);
|
||||
this.value = new TypedValue(value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -28,11 +28,13 @@ public class LongLiteral extends Literal {
|
|||
|
||||
private final TypedValue value;
|
||||
|
||||
|
||||
LongLiteral(String payload, int pos, long value) {
|
||||
super(payload, pos);
|
||||
this.value = new TypedValue(value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ import org.springframework.expression.spel.SpelEvaluationException;
|
|||
import org.springframework.expression.spel.SpelMessage;
|
||||
|
||||
/**
|
||||
* Expression language AST node that represents a method reference.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
|
|
@ -112,8 +114,8 @@ public class MethodReference extends SpelNodeImpl {
|
|||
MethodExecutor executorToUse = this.cachedExecutor;
|
||||
if (executorToUse != null) {
|
||||
try {
|
||||
return executorToUse.execute(
|
||||
state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments);
|
||||
return executorToUse.execute(state.getEvaluationContext(),
|
||||
state.getActiveContextObject().getValue(), arguments);
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
// Two reasons this can occur:
|
||||
|
|
@ -137,8 +139,8 @@ public class MethodReference extends SpelNodeImpl {
|
|||
executorToUse = findAccessorForMethod(this.name, getTypes(arguments), state);
|
||||
this.cachedExecutor = executorToUse;
|
||||
try {
|
||||
return executorToUse.execute(
|
||||
state.getEvaluationContext(), state.getActiveContextObject().getValue(), arguments);
|
||||
return executorToUse.execute(state.getEvaluationContext(),
|
||||
state.getActiveContextObject().getValue(), arguments);
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
// Same unwrapping exception handling as above in above catch block
|
||||
|
|
@ -158,12 +160,10 @@ public class MethodReference extends SpelNodeImpl {
|
|||
if (rootCause instanceof RuntimeException) {
|
||||
throw (RuntimeException) rootCause;
|
||||
}
|
||||
else {
|
||||
throw new ExpressionInvocationTargetException(getStartPosition(),
|
||||
"A problem occurred when trying to execute method '" + this.name +
|
||||
"' on object of type '" + state.getActiveContextObject().getValue().getClass().getName() + "'",
|
||||
rootCause);
|
||||
}
|
||||
throw new ExpressionInvocationTargetException(getStartPosition(),
|
||||
"A problem occurred when trying to execute method '" + this.name +
|
||||
"' on object of type '" + state.getActiveContextObject().getValue().getClass().getName() + "'",
|
||||
rootCause);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -180,42 +180,49 @@ public class MethodReference extends SpelNodeImpl {
|
|||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.name).append("(");
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
if (i > 0)
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(getChild(i).toStringAST());
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private MethodExecutor findAccessorForMethod(String name, List<TypeDescriptor> argumentTypes, ExpressionState state)
|
||||
private MethodExecutor findAccessorForMethod(String name,
|
||||
List<TypeDescriptor> argumentTypes, ExpressionState state)
|
||||
throws SpelEvaluationException {
|
||||
|
||||
return findAccessorForMethod(name,argumentTypes,state.getActiveContextObject().getValue(),state.getEvaluationContext());
|
||||
return findAccessorForMethod(name, argumentTypes,
|
||||
state.getActiveContextObject().getValue(), state.getEvaluationContext());
|
||||
}
|
||||
|
||||
private MethodExecutor findAccessorForMethod(String name,
|
||||
List<TypeDescriptor> argumentTypes, Object contextObject, EvaluationContext eContext)
|
||||
throws SpelEvaluationException {
|
||||
|
||||
List<MethodResolver> mResolvers = eContext.getMethodResolvers();
|
||||
if (mResolvers != null) {
|
||||
for (MethodResolver methodResolver : mResolvers) {
|
||||
List<MethodResolver> methodResolvers = eContext.getMethodResolvers();
|
||||
if (methodResolvers != null) {
|
||||
for (MethodResolver methodResolver : methodResolvers) {
|
||||
try {
|
||||
MethodExecutor cEx = methodResolver.resolve(eContext, contextObject, name, argumentTypes);
|
||||
if (cEx != null) {
|
||||
return cEx;
|
||||
MethodExecutor methodExecutor = methodResolver.resolve(eContext,
|
||||
contextObject, name, argumentTypes);
|
||||
if (methodExecutor != null) {
|
||||
return methodExecutor;
|
||||
}
|
||||
}
|
||||
catch (AccessException ex) {
|
||||
throw new SpelEvaluationException(getStartPosition(),ex, SpelMessage.PROBLEM_LOCATING_METHOD,
|
||||
name, contextObject.getClass());
|
||||
throw new SpelEvaluationException(getStartPosition(), ex,
|
||||
SpelMessage.PROBLEM_LOCATING_METHOD, name,
|
||||
contextObject.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new SpelEvaluationException(getStartPosition(),SpelMessage.METHOD_NOT_FOUND,
|
||||
throw new SpelEvaluationException(
|
||||
getStartPosition(),
|
||||
SpelMessage.METHOD_NOT_FOUND,
|
||||
FormatHelper.formatMethodForMessage(name, argumentTypes),
|
||||
FormatHelper.formatClassNameForMessage(contextObject instanceof Class ? ((Class<?>) contextObject) : contextObject.getClass()));
|
||||
FormatHelper.formatClassNameForMessage(contextObject instanceof Class ? ((Class<?>) contextObject)
|
||||
: contextObject.getClass()));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -229,6 +236,7 @@ public class MethodReference extends SpelNodeImpl {
|
|||
|
||||
private final Object[] arguments;
|
||||
|
||||
|
||||
MethodValueRef(ExpressionState state, EvaluationContext evaluationContext, Object object, Object[] arguments) {
|
||||
this.state = state;
|
||||
this.evaluationContext = evaluationContext;
|
||||
|
|
@ -236,9 +244,10 @@ public class MethodReference extends SpelNodeImpl {
|
|||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValue() {
|
||||
MethodExecutor executorToUse = cachedExecutor;
|
||||
MethodExecutor executorToUse = MethodReference.this.cachedExecutor;
|
||||
if (executorToUse != null) {
|
||||
try {
|
||||
return executorToUse.execute(this.evaluationContext, this.target, this.arguments);
|
||||
|
|
@ -257,21 +266,23 @@ public class MethodReference extends SpelNodeImpl {
|
|||
throwSimpleExceptionIfPossible(this.state, ae);
|
||||
|
||||
// at this point we know it wasn't a user problem so worth a retry if a better candidate can be found
|
||||
cachedExecutor = null;
|
||||
MethodReference.this.cachedExecutor = null;
|
||||
}
|
||||
}
|
||||
|
||||
// either there was no accessor or it no longer existed
|
||||
executorToUse = findAccessorForMethod(name, getTypes(this.arguments), this.target, this.evaluationContext);
|
||||
cachedExecutor = executorToUse;
|
||||
executorToUse = findAccessorForMethod(MethodReference.this.name, getTypes(this.arguments), this.target, this.evaluationContext);
|
||||
MethodReference.this.cachedExecutor = executorToUse;
|
||||
try {
|
||||
return executorToUse.execute(this.evaluationContext, this.target, this.arguments);
|
||||
}
|
||||
catch (AccessException ae) {
|
||||
catch (AccessException ex) {
|
||||
// Same unwrapping exception handling as above in above catch block
|
||||
throwSimpleExceptionIfPossible(this.state, ae);
|
||||
throw new SpelEvaluationException( getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
|
||||
name, this.state.getActiveContextObject().getValue().getClass().getName(), ae.getMessage());
|
||||
throwSimpleExceptionIfPossible(this.state, ex);
|
||||
throw new SpelEvaluationException(getStartPosition(), ex,
|
||||
SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
|
||||
MethodReference.this.name, this.state.getActiveContextObject().getValue().getClass().getName(),
|
||||
ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,6 +19,8 @@ package org.springframework.expression.spel.ast;
|
|||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* Expression language AST node that represents null.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
|
|
@ -28,6 +30,7 @@ public class NullLiteral extends Literal {
|
|||
super(null,pos);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getLiteralValue() {
|
||||
return TypedValue.NULL;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -37,6 +37,7 @@ public class OpAnd extends Operator {
|
|||
super("and", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
if (getBooleanValue(state, getLeftOperand()) == false) {
|
||||
|
|
@ -52,9 +53,9 @@ public class OpAnd extends Operator {
|
|||
assertValueNotNull(value);
|
||||
return value;
|
||||
}
|
||||
catch (SpelEvaluationException ee) {
|
||||
ee.setPosition(operand.getStartPosition());
|
||||
throw ee;
|
||||
catch (SpelEvaluationException ex) {
|
||||
ex.setPosition(operand.getStartPosition());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -33,7 +33,8 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
public class OpDec extends Operator {
|
||||
|
||||
private boolean postfix; // false means prefix
|
||||
private final boolean postfix; // false means prefix
|
||||
|
||||
|
||||
public OpDec(int pos, boolean postfix, SpelNodeImpl... operands) {
|
||||
super("--", pos, operands);
|
||||
|
|
@ -41,6 +42,7 @@ public class OpDec extends Operator {
|
|||
this.postfix = postfix;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
SpelNodeImpl operand = getLeftOperand();
|
||||
|
|
@ -57,26 +59,37 @@ public class OpDec extends Operator {
|
|||
if (operandValue instanceof Number) {
|
||||
Number op1 = (Number) operandValue;
|
||||
if (op1 instanceof Double) {
|
||||
newValue = new TypedValue(op1.doubleValue() - 1.0d, operandTypedValue.getTypeDescriptor());
|
||||
} else if (op1 instanceof Float) {
|
||||
newValue = new TypedValue(op1.floatValue() - 1.0f, operandTypedValue.getTypeDescriptor());
|
||||
} else if (op1 instanceof Long) {
|
||||
newValue = new TypedValue(op1.longValue() - 1L, operandTypedValue.getTypeDescriptor());
|
||||
} else if (op1 instanceof Short) {
|
||||
newValue = new TypedValue(op1.shortValue() - (short)1, operandTypedValue.getTypeDescriptor());
|
||||
} else {
|
||||
newValue = new TypedValue(op1.intValue() - 1, operandTypedValue.getTypeDescriptor());
|
||||
newValue = new TypedValue(op1.doubleValue() - 1.0d,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
else if (op1 instanceof Float) {
|
||||
newValue = new TypedValue(op1.floatValue() - 1.0f,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
else if (op1 instanceof Long) {
|
||||
newValue = new TypedValue(op1.longValue() - 1L,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
else if (op1 instanceof Short) {
|
||||
newValue = new TypedValue(op1.shortValue() - (short) 1,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
else {
|
||||
newValue = new TypedValue(op1.intValue() - 1,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
}
|
||||
if (newValue==null) {
|
||||
try {
|
||||
newValue = state.operate(Operation.SUBTRACT, returnValue.getValue(), 1);
|
||||
} catch (SpelEvaluationException see) {
|
||||
if (see.getMessageCode()==SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES) {
|
||||
}
|
||||
catch (SpelEvaluationException ex) {
|
||||
if (ex.getMessageCode() == SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES) {
|
||||
// This means the operand is not decrementable
|
||||
throw new SpelEvaluationException(operand.getStartPosition(),SpelMessage.OPERAND_NOT_DECREMENTABLE,operand.toStringAST());
|
||||
} else {
|
||||
throw see;
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,16 +97,19 @@ public class OpDec extends Operator {
|
|||
// set the new value
|
||||
try {
|
||||
lvalue.setValue(newValue.getValue());
|
||||
} catch (SpelEvaluationException see) {
|
||||
}
|
||||
catch (SpelEvaluationException see) {
|
||||
// if unable to set the value the operand is not writable (e.g. 1-- )
|
||||
if (see.getMessageCode()==SpelMessage.SETVALUE_NOT_SUPPORTED) {
|
||||
throw new SpelEvaluationException(operand.getStartPosition(),SpelMessage.OPERAND_NOT_DECREMENTABLE);
|
||||
} else {
|
||||
if (see.getMessageCode() == SpelMessage.SETVALUE_NOT_SUPPORTED) {
|
||||
throw new SpelEvaluationException(operand.getStartPosition(),
|
||||
SpelMessage.OPERAND_NOT_DECREMENTABLE);
|
||||
}
|
||||
else {
|
||||
throw see;
|
||||
}
|
||||
}
|
||||
|
||||
if (!postfix) {
|
||||
if (!this.postfix) {
|
||||
// the return value is the new value, not the original value
|
||||
returnValue = newValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -34,6 +34,7 @@ public class OpDivide extends Operator {
|
|||
super("/", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operandOne = getLeftOperand().getValueInternal(state).getValue();
|
||||
|
|
@ -43,9 +44,11 @@ public class OpDivide extends Operator {
|
|||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return new TypedValue(op1.doubleValue() / op2.doubleValue());
|
||||
} else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return new TypedValue(op1.floatValue() / op2.floatValue());
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return new TypedValue(op1.longValue() / op2.longValue());
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -32,8 +32,10 @@ public class OpEQ extends Operator {
|
|||
super("==", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state)
|
||||
throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
|
|
@ -41,18 +43,23 @@ public class OpEQ extends Operator {
|
|||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return BooleanTypedValue.forValue(op1.doubleValue() == op2.doubleValue());
|
||||
} else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return BooleanTypedValue.forValue(op1.floatValue() == op2.floatValue());
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return BooleanTypedValue.forValue(op1.floatValue() == op2.floatValue());
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return BooleanTypedValue.forValue(op1.longValue() == op2.longValue());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return BooleanTypedValue.forValue(op1.intValue() == op2.intValue());
|
||||
}
|
||||
}
|
||||
if (left!=null && (left instanceof Comparable)) {
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) == 0);
|
||||
} else {
|
||||
return BooleanTypedValue.forValue(left==right);
|
||||
if (left != null && (left instanceof Comparable)) {
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left,
|
||||
right) == 0);
|
||||
}
|
||||
else {
|
||||
return BooleanTypedValue.forValue(left == right);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -31,6 +31,7 @@ public class OpGE extends Operator {
|
|||
super(">=", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
|
|
@ -40,11 +41,14 @@ public class OpGE extends Operator {
|
|||
Number rightNumber = (Number) right;
|
||||
if (leftNumber instanceof Double || rightNumber instanceof Double) {
|
||||
return BooleanTypedValue.forValue(leftNumber.doubleValue() >= rightNumber.doubleValue());
|
||||
} else if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
}
|
||||
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
return BooleanTypedValue.forValue(leftNumber.floatValue() >= rightNumber.floatValue());
|
||||
} else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
return BooleanTypedValue.forValue( leftNumber.longValue() >= rightNumber.longValue());
|
||||
} else {
|
||||
}
|
||||
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
return BooleanTypedValue.forValue(leftNumber.longValue() >= rightNumber.longValue());
|
||||
}
|
||||
else {
|
||||
return BooleanTypedValue.forValue(leftNumber.intValue() >= rightNumber.intValue());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -32,6 +32,7 @@ public class OpGT extends Operator {
|
|||
super(">", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
|
|
@ -41,9 +42,11 @@ public class OpGT extends Operator {
|
|||
Number rightNumber = (Number) right;
|
||||
if (leftNumber instanceof Double || rightNumber instanceof Double) {
|
||||
return BooleanTypedValue.forValue(leftNumber.doubleValue() > rightNumber.doubleValue());
|
||||
} else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
}
|
||||
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
return BooleanTypedValue.forValue(leftNumber.longValue() > rightNumber.longValue());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return BooleanTypedValue.forValue(leftNumber.intValue() > rightNumber.intValue());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -33,7 +33,8 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
public class OpInc extends Operator {
|
||||
|
||||
private boolean postfix; // false means prefix
|
||||
private final boolean postfix; // false means prefix
|
||||
|
||||
|
||||
public OpInc(int pos, boolean postfix, SpelNodeImpl... operands) {
|
||||
super("++", pos, operands);
|
||||
|
|
@ -41,6 +42,7 @@ public class OpInc extends Operator {
|
|||
this.postfix = postfix;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
SpelNodeImpl operand = getLeftOperand();
|
||||
|
|
@ -55,43 +57,56 @@ public class OpInc extends Operator {
|
|||
if (operandValue instanceof Number) {
|
||||
Number op1 = (Number) operandValue;
|
||||
if (op1 instanceof Double) {
|
||||
newValue = new TypedValue(op1.doubleValue() + 1.0d, operandTypedValue.getTypeDescriptor());
|
||||
} else if (op1 instanceof Float) {
|
||||
newValue = new TypedValue(op1.floatValue() + 1.0f, operandTypedValue.getTypeDescriptor());
|
||||
} else if (op1 instanceof Long) {
|
||||
newValue = new TypedValue(op1.longValue() + 1L, operandTypedValue.getTypeDescriptor());
|
||||
} else if (op1 instanceof Short) {
|
||||
newValue = new TypedValue(op1.shortValue() + (short)1, operandTypedValue.getTypeDescriptor());
|
||||
} else {
|
||||
newValue = new TypedValue(op1.intValue() + 1, operandTypedValue.getTypeDescriptor());
|
||||
newValue = new TypedValue(op1.doubleValue() + 1.0d,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
else if (op1 instanceof Float) {
|
||||
newValue = new TypedValue(op1.floatValue() + 1.0f,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
else if (op1 instanceof Long) {
|
||||
newValue = new TypedValue(op1.longValue() + 1L,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
else if (op1 instanceof Short) {
|
||||
newValue = new TypedValue(op1.shortValue() + (short) 1,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
else {
|
||||
newValue = new TypedValue(op1.intValue() + 1,
|
||||
operandTypedValue.getTypeDescriptor());
|
||||
}
|
||||
}
|
||||
if (newValue==null) {
|
||||
if (newValue == null) {
|
||||
try {
|
||||
newValue = state.operate(Operation.ADD, returnValue.getValue(), 1);
|
||||
} catch (SpelEvaluationException see) {
|
||||
if (see.getMessageCode()==SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES) {
|
||||
}
|
||||
catch (SpelEvaluationException ex) {
|
||||
if (ex.getMessageCode() == SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES) {
|
||||
// This means the operand is not incrementable
|
||||
throw new SpelEvaluationException(operand.getStartPosition(),SpelMessage.OPERAND_NOT_INCREMENTABLE,operand.toStringAST());
|
||||
} else {
|
||||
throw see;
|
||||
throw new SpelEvaluationException(operand.getStartPosition(),
|
||||
SpelMessage.OPERAND_NOT_INCREMENTABLE, operand.toStringAST());
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
// set the name value
|
||||
try {
|
||||
lvalue.setValue(newValue.getValue());
|
||||
} catch (SpelEvaluationException see) {
|
||||
}
|
||||
catch (SpelEvaluationException see) {
|
||||
// if unable to set the value the operand is not writable (e.g. 1++ )
|
||||
if (see.getMessageCode()==SpelMessage.SETVALUE_NOT_SUPPORTED) {
|
||||
throw new SpelEvaluationException(operand.getStartPosition(),SpelMessage.OPERAND_NOT_INCREMENTABLE);
|
||||
} else {
|
||||
if (see.getMessageCode() == SpelMessage.SETVALUE_NOT_SUPPORTED) {
|
||||
throw new SpelEvaluationException(operand.getStartPosition(),
|
||||
SpelMessage.OPERAND_NOT_INCREMENTABLE);
|
||||
}
|
||||
else {
|
||||
throw see;
|
||||
}
|
||||
}
|
||||
|
||||
if (!postfix) {
|
||||
if (!this.postfix) {
|
||||
// the return value is the new value, not the original value
|
||||
returnValue = newValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -32,8 +32,10 @@ public class OpLE extends Operator {
|
|||
super("<=", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state)
|
||||
throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
|
|
@ -41,15 +43,18 @@ public class OpLE extends Operator {
|
|||
Number rightNumber = (Number) right;
|
||||
if (leftNumber instanceof Double || rightNumber instanceof Double) {
|
||||
return BooleanTypedValue.forValue(leftNumber.doubleValue() <= rightNumber.doubleValue());
|
||||
} else if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
}
|
||||
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
return BooleanTypedValue.forValue(leftNumber.floatValue() <= rightNumber.floatValue());
|
||||
} else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
}
|
||||
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
return BooleanTypedValue.forValue(leftNumber.longValue() <= rightNumber.longValue());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return BooleanTypedValue.forValue(leftNumber.intValue() <= rightNumber.intValue());
|
||||
}
|
||||
}
|
||||
return BooleanTypedValue.forValue( state.getTypeComparator().compare(left, right) <= 0);
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) <= 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -32,8 +32,10 @@ public class OpLT extends Operator {
|
|||
super("<", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state)
|
||||
throws EvaluationException {
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
// TODO could leave all of these to the comparator - just seems quicker to do some here
|
||||
|
|
@ -42,11 +44,14 @@ public class OpLT extends Operator {
|
|||
Number rightNumber = (Number) right;
|
||||
if (leftNumber instanceof Double || rightNumber instanceof Double) {
|
||||
return BooleanTypedValue.forValue(leftNumber.doubleValue() < rightNumber.doubleValue());
|
||||
} else if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
}
|
||||
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
return BooleanTypedValue.forValue(leftNumber.floatValue() < rightNumber.floatValue());
|
||||
} else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
}
|
||||
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
return BooleanTypedValue.forValue(leftNumber.longValue() < rightNumber.longValue());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return BooleanTypedValue.forValue(leftNumber.intValue() < rightNumber.intValue());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -27,11 +27,12 @@ import org.springframework.expression.spel.ExpressionState;
|
|||
* <li>subtraction of doubles (floats are represented as doubles)
|
||||
* <li>subtraction of longs
|
||||
* <li>subtraction of integers
|
||||
* <li>subtraction of an int from a string of one character (effectively decreasing that character), so 'd'-3='a'
|
||||
* <li>subtraction of an int from a string of one character (effectively decreasing that
|
||||
* character), so 'd'-3='a'
|
||||
* </ul>
|
||||
* It can be used as a unary operator for numbers (double/long/int). The standard promotions are performed
|
||||
* when the operand types vary (double-int=double).
|
||||
* For other options it defers to the registered overloader.
|
||||
* It can be used as a unary operator for numbers (double/long/int). The standard
|
||||
* promotions are performed when the operand types vary (double-int=double). For other
|
||||
* options it defers to the registered overloader.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -44,46 +45,61 @@ public class OpMinus extends Operator {
|
|||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
|
||||
SpelNodeImpl leftOp = getLeftOperand();
|
||||
SpelNodeImpl rightOp = getRightOperand();
|
||||
|
||||
if (rightOp == null) {// If only one operand, then this is unary minus
|
||||
Object operand = leftOp.getValueInternal(state).getValue();
|
||||
if (operand instanceof Number) {
|
||||
Number n = (Number) operand;
|
||||
if (operand instanceof Double) {
|
||||
return new TypedValue(0 - n.doubleValue());
|
||||
} else if (operand instanceof Float) {
|
||||
}
|
||||
|
||||
if (operand instanceof Float) {
|
||||
return new TypedValue(0 - n.floatValue());
|
||||
} else if (operand instanceof Long) {
|
||||
}
|
||||
|
||||
if (operand instanceof Long) {
|
||||
return new TypedValue(0 - n.longValue());
|
||||
} else {
|
||||
return new TypedValue(0 - n.intValue());
|
||||
}
|
||||
return new TypedValue(0 - n.intValue());
|
||||
}
|
||||
|
||||
return state.operate(Operation.SUBTRACT, operand, null);
|
||||
} else {
|
||||
Object left = leftOp.getValueInternal(state).getValue();
|
||||
Object right = rightOp.getValueInternal(state).getValue();
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return new TypedValue(op1.doubleValue() - op2.doubleValue());
|
||||
} else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return new TypedValue(op1.floatValue() - op2.floatValue());
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return new TypedValue(op1.longValue() - op2.longValue());
|
||||
} else {
|
||||
return new TypedValue(op1.intValue() - op2.intValue());
|
||||
}
|
||||
} else if (left instanceof String && right instanceof Integer && ((String)left).length()==1) {
|
||||
String theString = (String) left;
|
||||
Integer theInteger = (Integer) right;
|
||||
// implements character - int (ie. b - 1 = a)
|
||||
return new TypedValue(Character.toString((char) (theString.charAt(0) - theInteger)));
|
||||
}
|
||||
return state.operate(Operation.SUBTRACT, left, right);
|
||||
}
|
||||
|
||||
Object left = leftOp.getValueInternal(state).getValue();
|
||||
Object right = rightOp.getValueInternal(state).getValue();
|
||||
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return new TypedValue(op1.doubleValue() - op2.doubleValue());
|
||||
}
|
||||
|
||||
if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return new TypedValue(op1.floatValue() - op2.floatValue());
|
||||
}
|
||||
|
||||
if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return new TypedValue(op1.longValue() - op2.longValue());
|
||||
}
|
||||
|
||||
return new TypedValue(op1.intValue() - op2.intValue());
|
||||
}
|
||||
else if (left instanceof String && right instanceof Integer
|
||||
&& ((String) left).length() == 1) {
|
||||
String theString = (String) left;
|
||||
Integer theInteger = (Integer) right;
|
||||
// implements character - int (ie. b - 1 = a)
|
||||
return new TypedValue(Character.toString((char)
|
||||
(theString.charAt(0) - theInteger)));
|
||||
}
|
||||
|
||||
return state.operate(Operation.SUBTRACT, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -95,8 +111,8 @@ public class OpMinus extends Operator {
|
|||
}
|
||||
@Override
|
||||
public SpelNodeImpl getRightOperand() {
|
||||
if (children.length<2) {return null;}
|
||||
return children[1];
|
||||
if (this.children.length<2) {return null;}
|
||||
return this.children[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -33,6 +33,7 @@ public class OpModulus extends Operator {
|
|||
super("%", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Object operandOne = getLeftOperand().getValueInternal(state).getValue();
|
||||
|
|
@ -42,11 +43,14 @@ public class OpModulus extends Operator {
|
|||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return new TypedValue(op1.doubleValue() % op2.doubleValue());
|
||||
} else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return new TypedValue(op1.floatValue() % op2.floatValue());
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return new TypedValue(op1.longValue() % op2.longValue());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return new TypedValue(op1.intValue() % op2.intValue());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -25,10 +25,11 @@ import org.springframework.expression.spel.ExpressionState;
|
|||
* Implements the {@code multiply} operator.
|
||||
*
|
||||
* <p>Conversions and promotions are handled as defined in
|
||||
* <a href="http://java.sun.com/docs/books/jls/third_edition/html/conversions.html">Section 5.6.2
|
||||
* of the Java Language Specification</a>:
|
||||
* <a href="http://java.sun.com/docs/books/jls/third_edition/html/conversions.html">Section
|
||||
* 5.6.2 of the Java Language Specification</a>:
|
||||
*
|
||||
* <p>If any of the operands is of a reference type, unboxing conversion (Section 5.1.8) is performed. Then:<br>
|
||||
* <p>If any of the operands is of a reference type, unboxing conversion (Section 5.1.8)
|
||||
* is performed. Then:<br>
|
||||
* If either operand is of type double, the other is converted to double.<br>
|
||||
* Otherwise, if either operand is of type float, the other is converted to float.<br>
|
||||
* Otherwise, if either operand is of type long, the other is converted to long.<br>
|
||||
|
|
@ -44,6 +45,7 @@ public class OpMultiply extends Operator {
|
|||
super("*", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements the {@code multiply} operator directly here for certain types
|
||||
* of supported operands and otherwise delegates to any registered overloader
|
||||
|
|
@ -58,23 +60,27 @@ public class OpMultiply extends Operator {
|
|||
*/
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
|
||||
Object operandOne = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object operandTwo = getRightOperand().getValueInternal(state).getValue();
|
||||
|
||||
if (operandOne instanceof Number && operandTwo instanceof Number) {
|
||||
Number leftNumber = (Number) operandOne;
|
||||
Number rightNumber = (Number) operandTwo;
|
||||
if (leftNumber instanceof Double || rightNumber instanceof Double) {
|
||||
return new TypedValue(leftNumber.doubleValue() * rightNumber.doubleValue());
|
||||
return new TypedValue(leftNumber.doubleValue()
|
||||
* rightNumber.doubleValue());
|
||||
}
|
||||
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
|
||||
if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
return new TypedValue(leftNumber.floatValue() * rightNumber.floatValue());
|
||||
}
|
||||
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
|
||||
if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
return new TypedValue(leftNumber.longValue() * rightNumber.longValue());
|
||||
}
|
||||
else {
|
||||
return new TypedValue(leftNumber.intValue() * rightNumber.intValue());
|
||||
}
|
||||
|
||||
return new TypedValue(leftNumber.intValue() * rightNumber.intValue());
|
||||
}
|
||||
else if (operandOne instanceof String && operandTwo instanceof Integer) {
|
||||
int repeats = (Integer) operandTwo;
|
||||
|
|
@ -84,6 +90,7 @@ public class OpMultiply extends Operator {
|
|||
}
|
||||
return new TypedValue(result.toString());
|
||||
}
|
||||
|
||||
return state.operate(Operation.MULTIPLY, operandOne, operandTwo);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -32,29 +32,38 @@ public class OpNE extends Operator {
|
|||
super("!=", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
|
||||
Object left = getLeftOperand().getValueInternal(state).getValue();
|
||||
Object right = getRightOperand().getValueInternal(state).getValue();
|
||||
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
Number op1 = (Number) left;
|
||||
Number op2 = (Number) right;
|
||||
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return BooleanTypedValue.forValue(op1.doubleValue() != op2.doubleValue());
|
||||
} else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return BooleanTypedValue.forValue(op1.floatValue() != op2.floatValue());
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return BooleanTypedValue.forValue(op1.longValue() != op2.longValue());
|
||||
} else {
|
||||
return BooleanTypedValue.forValue(op1.intValue() != op2.intValue());
|
||||
}
|
||||
|
||||
if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return BooleanTypedValue.forValue(op1.floatValue() != op2.floatValue());
|
||||
}
|
||||
|
||||
if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return BooleanTypedValue.forValue(op1.longValue() != op2.longValue());
|
||||
}
|
||||
|
||||
return BooleanTypedValue.forValue(op1.intValue() != op2.intValue());
|
||||
}
|
||||
|
||||
if (left!=null && (left instanceof Comparable)) {
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) != 0);
|
||||
} else {
|
||||
return BooleanTypedValue.forValue(left!=right);
|
||||
if (left != null && (left instanceof Comparable)) {
|
||||
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left,
|
||||
right) != 0);
|
||||
}
|
||||
|
||||
return BooleanTypedValue.forValue(left != right);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -36,6 +36,7 @@ public class OpOr extends Operator {
|
|||
super("or", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
if (getBooleanValue(state, getLeftOperand())) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -32,8 +32,9 @@ import org.springframework.util.Assert;
|
|||
* <li>add integers
|
||||
* <li>concatenate strings
|
||||
* </ul>
|
||||
* It can be used as a unary operator for numbers (double/long/int). The standard promotions are performed
|
||||
* when the operand types vary (double+int=double). For other options it defers to the registered overloader.
|
||||
* It can be used as a unary operator for numbers (double/long/int). The standard
|
||||
* promotions are performed when the operand types vary (double+int=double). For other
|
||||
* options it defers to the registered overloader.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Ivo Smid
|
||||
|
|
@ -46,72 +47,86 @@ public class OpPlus extends Operator {
|
|||
Assert.notEmpty(operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
SpelNodeImpl leftOp = getLeftOperand();
|
||||
SpelNodeImpl rightOp = getRightOperand();
|
||||
|
||||
if (rightOp == null) { // If only one operand, then this is unary plus
|
||||
Object operandOne = leftOp.getValueInternal(state).getValue();
|
||||
if (operandOne instanceof Number) {
|
||||
if (operandOne instanceof Double || operandOne instanceof Long) {
|
||||
return new TypedValue(operandOne);
|
||||
} else if (operandOne instanceof Float) {
|
||||
return new TypedValue(((Number) operandOne).floatValue());
|
||||
} else {
|
||||
return new TypedValue(((Number) operandOne).intValue());
|
||||
}
|
||||
if (operandOne instanceof Float) {
|
||||
return new TypedValue(((Number) operandOne).floatValue());
|
||||
}
|
||||
return new TypedValue(((Number) operandOne).intValue());
|
||||
}
|
||||
return state.operate(Operation.ADD, operandOne, null);
|
||||
}
|
||||
else {
|
||||
final TypedValue operandOneValue = leftOp.getValueInternal(state);
|
||||
final Object operandOne = operandOneValue.getValue();
|
||||
|
||||
final TypedValue operandTwoValue = rightOp.getValueInternal(state);
|
||||
final Object operandTwo = operandTwoValue.getValue();
|
||||
final TypedValue operandOneValue = leftOp.getValueInternal(state);
|
||||
final Object operandOne = operandOneValue.getValue();
|
||||
|
||||
if (operandOne instanceof Number && operandTwo instanceof Number) {
|
||||
Number op1 = (Number) operandOne;
|
||||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return new TypedValue(op1.doubleValue() + op2.doubleValue());
|
||||
} else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return new TypedValue(op1.floatValue() + op2.floatValue());
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return new TypedValue(op1.longValue() + op2.longValue());
|
||||
} else { // TODO what about overflow?
|
||||
return new TypedValue(op1.intValue() + op2.intValue());
|
||||
}
|
||||
} else if (operandOne instanceof String && operandTwo instanceof String) {
|
||||
return new TypedValue(new StringBuilder((String) operandOne).append((String) operandTwo).toString());
|
||||
} else if (operandOne instanceof String) {
|
||||
StringBuilder result = new StringBuilder((String) operandOne);
|
||||
result.append((operandTwo == null ? "null" : convertTypedValueToString(operandTwoValue, state)));
|
||||
return new TypedValue(result.toString());
|
||||
} else if (operandTwo instanceof String) {
|
||||
StringBuilder result = new StringBuilder((operandOne == null ? "null" : convertTypedValueToString(
|
||||
operandOneValue, state)));
|
||||
result.append((String) operandTwo);
|
||||
return new TypedValue(result.toString());
|
||||
final TypedValue operandTwoValue = rightOp.getValueInternal(state);
|
||||
final Object operandTwo = operandTwoValue.getValue();
|
||||
|
||||
if (operandOne instanceof Number && operandTwo instanceof Number) {
|
||||
Number op1 = (Number) operandOne;
|
||||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return new TypedValue(op1.doubleValue() + op2.doubleValue());
|
||||
}
|
||||
return state.operate(Operation.ADD, operandOne, operandTwo);
|
||||
if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return new TypedValue(op1.floatValue() + op2.floatValue());
|
||||
}
|
||||
if (op1 instanceof Long || op2 instanceof Long) {
|
||||
return new TypedValue(op1.longValue() + op2.longValue());
|
||||
}
|
||||
// TODO what about overflow?
|
||||
return new TypedValue(op1.intValue() + op2.intValue());
|
||||
}
|
||||
|
||||
if (operandOne instanceof String && operandTwo instanceof String) {
|
||||
return new TypedValue(new StringBuilder((String) operandOne).append(
|
||||
(String) operandTwo).toString());
|
||||
}
|
||||
|
||||
if (operandOne instanceof String) {
|
||||
StringBuilder result = new StringBuilder((String) operandOne);
|
||||
result.append((operandTwo == null ? "null" : convertTypedValueToString(
|
||||
operandTwoValue, state)));
|
||||
return new TypedValue(result.toString());
|
||||
}
|
||||
|
||||
if (operandTwo instanceof String) {
|
||||
StringBuilder result = new StringBuilder((operandOne == null ? "null"
|
||||
: convertTypedValueToString(operandOneValue, state)));
|
||||
result.append((String) operandTwo);
|
||||
return new TypedValue(result.toString());
|
||||
}
|
||||
|
||||
return state.operate(Operation.ADD, operandOne, operandTwo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
if (children.length<2) { // unary plus
|
||||
if (this.children.length<2) { // unary plus
|
||||
return new StringBuilder().append("+").append(getLeftOperand().toStringAST()).toString();
|
||||
}
|
||||
|
||||
return super.toStringAST();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpelNodeImpl getRightOperand() {
|
||||
if (children.length < 2) {
|
||||
if (this.children.length < 2) {
|
||||
return null;
|
||||
}
|
||||
return children[1];
|
||||
|
||||
return this.children[1];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -127,11 +142,12 @@ public class OpPlus extends Operator {
|
|||
final TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(String.class);
|
||||
|
||||
if (typeConverter.canConvert(value.getTypeDescriptor(), typeDescriptor)) {
|
||||
final Object obj = typeConverter.convertValue(value.getValue(), value.getTypeDescriptor(), typeDescriptor);
|
||||
final Object obj = typeConverter.convertValue(value.getValue(),
|
||||
value.getTypeDescriptor(), typeDescriptor);
|
||||
return String.valueOf(obj);
|
||||
} else {
|
||||
return String.valueOf(value.getValue());
|
||||
}
|
||||
|
||||
return String.valueOf(value.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -16,10 +16,10 @@
|
|||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
|
||||
/**
|
||||
* Common supertype for operators that operate on either one or two operands. In the case of multiply or divide there
|
||||
* would be two operands, but for unary plus or minus, there is only one.
|
||||
* Common supertype for operators that operate on either one or two operands. In the case
|
||||
* of multiply or divide there would be two operands, but for unary plus or minus, there
|
||||
* is only one.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -28,21 +28,23 @@ public abstract class Operator extends SpelNodeImpl {
|
|||
|
||||
String operatorName;
|
||||
|
||||
|
||||
public Operator(String payload,int pos,SpelNodeImpl... operands) {
|
||||
super(pos, operands);
|
||||
this.operatorName = payload;
|
||||
}
|
||||
|
||||
|
||||
public SpelNodeImpl getLeftOperand() {
|
||||
return children[0];
|
||||
return this.children[0];
|
||||
}
|
||||
|
||||
public SpelNodeImpl getRightOperand() {
|
||||
return children[1];
|
||||
return this.children[1];
|
||||
}
|
||||
|
||||
public final String getOperatorName() {
|
||||
return operatorName;
|
||||
return this.operatorName;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -26,9 +26,10 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
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
|
||||
* list - this operator returns true if the left operand is between (using the registered comparator) the two elements
|
||||
* in the list. The definition of between being inclusive follows the SQL BETWEEN definition.
|
||||
* Represents the between operator. The left operand to between must be a single value and
|
||||
* the right operand must be a list - this operator returns true if the left operand is
|
||||
* between (using the registered comparator) the two elements in the list. The definition
|
||||
* of between being inclusive follows the SQL BETWEEN definition.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -40,8 +41,9 @@ public class OperatorBetween extends Operator {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean based on whether a value is in the range expressed. The first operand is any value whilst the
|
||||
* second is a list of two values - those two values being the bounds allowed for the first operand (inclusive).
|
||||
* Returns a boolean based on whether a value is in the range expressed. The first
|
||||
* operand is any value whilst the second is a list of two values - those two values
|
||||
* being the bounds allowed for the first operand (inclusive).
|
||||
* @param state the expression state
|
||||
* @return true if the left operand is in the range specified, false otherwise
|
||||
* @throws EvaluationException if there is a problem evaluating the expression
|
||||
|
|
@ -59,8 +61,10 @@ public class OperatorBetween extends Operator {
|
|||
Object high = l.get(1);
|
||||
TypeComparator comparator = state.getTypeComparator();
|
||||
try {
|
||||
return BooleanTypedValue.forValue((comparator.compare(left, low) >= 0 && comparator.compare(left, high) <= 0));
|
||||
} catch (SpelEvaluationException ex) {
|
||||
return BooleanTypedValue.forValue((comparator.compare(left, low) >= 0 &&
|
||||
comparator.compare(left, high) <= 0));
|
||||
}
|
||||
catch (SpelEvaluationException ex) {
|
||||
ex.setPosition(getStartPosition());
|
||||
throw ex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -24,8 +24,8 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||
|
||||
/**
|
||||
* The operator 'instanceof' checks if an object is of the class specified in the right hand operand,
|
||||
* in the same way that {@code instanceof} does in Java.
|
||||
* The operator 'instanceof' checks if an object is of the class specified in the right
|
||||
* hand operand, in the same way that {@code instanceof} does in Java.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -36,11 +36,13 @@ public class OperatorInstanceof extends Operator {
|
|||
super("instanceof", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare the left operand to see it is an instance of the type specified as the right operand.
|
||||
* The right operand must be a class.
|
||||
* Compare the left operand to see it is an instance of the type specified as the
|
||||
* right operand. The right operand must be a class.
|
||||
* @param state the expression state
|
||||
* @return true if the left operand is an instanceof of the right operand, otherwise false
|
||||
* @return true if the left operand is an instanceof of the right operand, otherwise
|
||||
* false
|
||||
* @throws EvaluationException if there is a problem evaluating the expression
|
||||
*/
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -27,8 +27,9 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
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
|
||||
* will return true when getValue() is called if the first operand matches the regex.
|
||||
* Implements the matches operator. Matches takes two operands. The first is a string and
|
||||
* the second is a java regex. It will return true when getValue() is called if the first
|
||||
* operand matches the regex.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -39,11 +40,14 @@ public class OperatorMatches extends Operator {
|
|||
super("matches", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the first operand matches the regex specified as the second operand.
|
||||
* @param state the expression state
|
||||
* @return true if the first operand matches the regex specified as the second operand, otherwise false
|
||||
* @throws EvaluationException if there is a problem evaluating the expression (e.g. the regex is invalid)
|
||||
* @return true if the first operand matches the regex specified as the second
|
||||
* operand, otherwise false
|
||||
* @throws EvaluationException if there is a problem evaluating the expression (e.g.
|
||||
* the regex is invalid)
|
||||
*/
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -36,18 +36,19 @@ public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so do
|
|||
super(pos, operand);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
try {
|
||||
Boolean value = children[0].getValue(state, Boolean.class);
|
||||
Boolean value = this.children[0].getValue(state, Boolean.class);
|
||||
if (value == null) {
|
||||
throw new SpelEvaluationException(SpelMessage.TYPE_CONVERSION_ERROR, "null", "boolean");
|
||||
}
|
||||
return BooleanTypedValue.forValue(!value);
|
||||
}
|
||||
catch (SpelEvaluationException see) {
|
||||
see.setPosition(getChild(0).getStartPosition());
|
||||
throw see;
|
||||
catch (SpelEvaluationException ex) {
|
||||
ex.setPosition(getChild(0).getStartPosition());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -33,6 +33,7 @@ public class OperatorPower extends Operator {
|
|||
super("^", pos, operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
SpelNodeImpl leftOp = getLeftOperand();
|
||||
|
|
@ -44,18 +45,22 @@ public class OperatorPower extends Operator {
|
|||
Number op1 = (Number) operandOne;
|
||||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return new TypedValue(Math.pow(op1.doubleValue(),op2.doubleValue()));
|
||||
} else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return new TypedValue(Math.pow(op1.doubleValue(), op2.doubleValue()));
|
||||
}
|
||||
else if (op1 instanceof Float || op2 instanceof Float) {
|
||||
return new TypedValue(Math.pow(op1.floatValue(), op2.floatValue()));
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
double d= Math.pow(op1.longValue(), op2.longValue());
|
||||
return new TypedValue((long)d);
|
||||
} else {
|
||||
double d= Math.pow(op1.longValue(), op2.longValue());
|
||||
}
|
||||
else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
double d = Math.pow(op1.longValue(), op2.longValue());
|
||||
return new TypedValue((long) d);
|
||||
}
|
||||
else {
|
||||
double d = Math.pow(op1.longValue(), op2.longValue());
|
||||
if (d > Integer.MAX_VALUE) {
|
||||
return new TypedValue((long)d);
|
||||
} else {
|
||||
return new TypedValue((int)d);
|
||||
return new TypedValue((long) d);
|
||||
}
|
||||
else {
|
||||
return new TypedValue((int) d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -32,8 +32,8 @@ import org.springframework.util.ClassUtils;
|
|||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Represents projection, where a given operation is performed on all elements in some input sequence, returning
|
||||
* a new sequence of the same size. For example:
|
||||
* Represents projection, where a given operation is performed on all elements in some
|
||||
* input sequence, returning a new sequence of the same size. For example:
|
||||
* "{1,2,3,4,5,6,7,8,9,10}.!{#isEven(#this)}" returns "[n, y, n, y, n, y, n, y, n, y]"
|
||||
*
|
||||
* @author Andy Clement
|
||||
|
|
@ -49,6 +49,7 @@ public class Projection extends SpelNodeImpl {
|
|||
this.nullSafe = nullSafe;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
return getValueRef(state).getValue();
|
||||
|
|
@ -81,7 +82,8 @@ public class Projection extends SpelNodeImpl {
|
|||
}
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(result),this); // TODO unable to build correct type descriptor
|
||||
}
|
||||
else if (operand instanceof Collection || operandIsArray) {
|
||||
|
||||
if (operand instanceof Collection || operandIsArray) {
|
||||
Collection<?> data = (operand instanceof Collection ? (Collection<?>) operand :
|
||||
Arrays.asList(ObjectUtils.toObjectArray(operand)));
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
|
|
@ -91,7 +93,7 @@ public class Projection extends SpelNodeImpl {
|
|||
try {
|
||||
state.pushActiveContextObject(new TypedValue(element));
|
||||
state.enterScope("index", idx);
|
||||
Object value = children[0].getValueInternal(state).getValue();
|
||||
Object value = this.children[0].getValueInternal(state).getValue();
|
||||
if (value != null && operandIsArray) {
|
||||
arrayElementType = determineCommonType(arrayElementType, value.getClass());
|
||||
}
|
||||
|
|
@ -113,21 +115,17 @@ public class Projection extends SpelNodeImpl {
|
|||
}
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(result),this);
|
||||
}
|
||||
else {
|
||||
if (operand==null) {
|
||||
if (this.nullSafe) {
|
||||
return ValueRef.NullValueRef.instance;
|
||||
}
|
||||
else {
|
||||
throw new SpelEvaluationException(getStartPosition(),
|
||||
SpelMessage.PROJECTION_NOT_SUPPORTED_ON_TYPE, "null");
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new SpelEvaluationException(getStartPosition(),
|
||||
SpelMessage.PROJECTION_NOT_SUPPORTED_ON_TYPE, operand.getClass().getName());
|
||||
|
||||
if (operand==null) {
|
||||
if (this.nullSafe) {
|
||||
return ValueRef.NullValueRef.instance;
|
||||
}
|
||||
throw new SpelEvaluationException(getStartPosition(),
|
||||
SpelMessage.PROJECTION_NOT_SUPPORTED_ON_TYPE, "null");
|
||||
}
|
||||
|
||||
throw new SpelEvaluationException(getStartPosition(),
|
||||
SpelMessage.PROJECTION_NOT_SUPPORTED_ON_TYPE, operand.getClass().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -68,10 +68,10 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
|
||||
|
||||
static class AccessorLValue implements ValueRef {
|
||||
private PropertyOrFieldReference ref;
|
||||
private TypedValue contextObject;
|
||||
private EvaluationContext eContext;
|
||||
private boolean isAutoGrowNullReferences;
|
||||
private final PropertyOrFieldReference ref;
|
||||
private final TypedValue contextObject;
|
||||
private final EvaluationContext eContext;
|
||||
private final boolean isAutoGrowNullReferences;
|
||||
|
||||
public AccessorLValue(
|
||||
PropertyOrFieldReference propertyOrFieldReference,
|
||||
|
|
@ -85,12 +85,12 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
|
||||
@Override
|
||||
public TypedValue getValue() {
|
||||
return ref.getValueInternal(contextObject,eContext,isAutoGrowNullReferences);
|
||||
return this.ref.getValueInternal(this.contextObject,this.eContext,this.isAutoGrowNullReferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object newValue) {
|
||||
ref.writeProperty(contextObject,eContext, ref.name, newValue);
|
||||
this.ref.writeProperty(this.contextObject,this.eContext, this.ref.name, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -142,7 +142,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
try {
|
||||
if (isWritableProperty(this.name,contextObject,eContext)) {
|
||||
Map<?,?> newMap = HashMap.class.newInstance();
|
||||
writeProperty(contextObject, eContext, name, newMap);
|
||||
writeProperty(contextObject, eContext, this.name, newMap);
|
||||
result = readProperty(contextObject, eContext, this.name);
|
||||
}
|
||||
}
|
||||
|
|
@ -161,7 +161,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
try {
|
||||
if (isWritableProperty(this.name,contextObject,eContext)) {
|
||||
Object newObject = result.getTypeDescriptor().getType().newInstance();
|
||||
writeProperty(contextObject, eContext, name, newObject);
|
||||
writeProperty(contextObject, eContext, this.name, newObject);
|
||||
result = readProperty(contextObject, eContext, this.name);
|
||||
}
|
||||
}
|
||||
|
|
@ -253,7 +253,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
|
||||
private void writeProperty(TypedValue contextObject, EvaluationContext eContext, String name, Object newValue) throws SpelEvaluationException {
|
||||
|
||||
if (contextObject.getValue() == null && nullSafe) {
|
||||
if (contextObject.getValue() == null && this.nullSafe) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -21,7 +21,8 @@ import org.springframework.expression.TypedValue;
|
|||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
* Represents a dot separated sequence of strings that indicate a package qualified type reference.
|
||||
* Represents a dot separated sequence of strings that indicate a package qualified type
|
||||
* reference.
|
||||
*
|
||||
* <p>Example: "java.lang.String" as in the expression "new java.lang.String('hello')"
|
||||
*
|
||||
|
|
@ -33,17 +34,19 @@ public class QualifiedIdentifier extends SpelNodeImpl {
|
|||
// TODO safe to cache? dont think so
|
||||
private TypedValue value;
|
||||
|
||||
|
||||
public QualifiedIdentifier(int pos,SpelNodeImpl... operands) {
|
||||
super(pos,operands);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
// Cache the concatenation of child identifiers
|
||||
if (this.value == null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
Object value = children[i].getValueInternal(state).getValue();
|
||||
Object value = this.children[i].getValueInternal(state).getValue();
|
||||
if (i > 0 && !value.toString().startsWith("$")) {
|
||||
sb.append(".");
|
||||
}
|
||||
|
|
@ -59,7 +62,8 @@ public class QualifiedIdentifier extends SpelNodeImpl {
|
|||
StringBuilder sb = new StringBuilder();
|
||||
if (this.value != null) {
|
||||
sb.append(this.value.getValue());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
if (i > 0) {
|
||||
sb.append(".");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,6 +19,8 @@ package org.springframework.expression.spel.ast;
|
|||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* Expression language AST node that represents a real literal.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
|
|
@ -26,11 +28,13 @@ public class RealLiteral extends Literal {
|
|||
|
||||
private final TypedValue value;
|
||||
|
||||
|
||||
public RealLiteral(String payload, int pos, double value) {
|
||||
super(payload, pos);
|
||||
this.value = new TypedValue(value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
|
|
|
|||
|
|
@ -47,14 +47,18 @@ import org.springframework.util.ObjectUtils;
|
|||
*/
|
||||
public class Selection extends SpelNodeImpl {
|
||||
|
||||
public final static int ALL = 0; // ?[]
|
||||
public final static int FIRST = 1; // ^[]
|
||||
public final static int LAST = 2; // $[]
|
||||
public static final int ALL = 0; // ?[]
|
||||
|
||||
public static final int FIRST = 1; // ^[]
|
||||
|
||||
public static final int LAST = 2; // $[]
|
||||
|
||||
private final int variant;
|
||||
|
||||
private final boolean nullSafe;
|
||||
|
||||
public Selection(boolean nullSafe, int variant,int pos,SpelNodeImpl expression) {
|
||||
|
||||
public Selection(boolean nullSafe, int variant, int pos, SpelNodeImpl expression) {
|
||||
super(pos, expression != null ? new SpelNodeImpl[] { expression }
|
||||
: new SpelNodeImpl[] {});
|
||||
Assert.notNull(expression, "Expression must not be null");
|
||||
|
|
@ -72,7 +76,7 @@ public class Selection extends SpelNodeImpl {
|
|||
TypedValue op = state.getActiveContextObject();
|
||||
Object operand = op.getValue();
|
||||
|
||||
SpelNodeImpl selectionCriteria = children[0];
|
||||
SpelNodeImpl selectionCriteria = this.children[0];
|
||||
if (operand instanceof Map) {
|
||||
Map<?, ?> mapdata = (Map<?, ?>) operand;
|
||||
// TODO don't lose generic info for the new map
|
||||
|
|
@ -85,32 +89,38 @@ public class Selection extends SpelNodeImpl {
|
|||
Object o = selectionCriteria.getValueInternal(state).getValue();
|
||||
if (o instanceof Boolean) {
|
||||
if (((Boolean) o).booleanValue() == true) {
|
||||
if (variant == FIRST) {
|
||||
if (this.variant == FIRST) {
|
||||
result.put(entry.getKey(),entry.getValue());
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(result),this);
|
||||
}
|
||||
result.put(entry.getKey(),entry.getValue());
|
||||
lastKey = entry.getKey();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw new SpelEvaluationException(selectionCriteria.getStartPosition(),
|
||||
SpelMessage.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST());
|
||||
}
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
}
|
||||
if ((variant == FIRST || variant == LAST) && result.size() == 0) {
|
||||
if ((this.variant == FIRST || this.variant == LAST) && result.size() == 0) {
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(null),this);
|
||||
}
|
||||
if (variant == LAST) {
|
||||
|
||||
if (this.variant == LAST) {
|
||||
Map<Object, Object> resultMap = new HashMap<Object, Object>();
|
||||
Object lastValue = result.get(lastKey);
|
||||
resultMap.put(lastKey,lastValue);
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(resultMap),this);
|
||||
}
|
||||
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(result),this);
|
||||
} else if ((operand instanceof Collection) || ObjectUtils.isArray(operand)) {
|
||||
}
|
||||
|
||||
if ((operand instanceof Collection) || ObjectUtils.isArray(operand)) {
|
||||
List<Object> data = new ArrayList<Object>();
|
||||
Collection<?> c = (operand instanceof Collection) ?
|
||||
(Collection<?>) operand : Arrays.asList(ObjectUtils.toObjectArray(operand));
|
||||
|
|
@ -124,64 +134,64 @@ public class Selection extends SpelNodeImpl {
|
|||
Object o = selectionCriteria.getValueInternal(state).getValue();
|
||||
if (o instanceof Boolean) {
|
||||
if (((Boolean) o).booleanValue() == true) {
|
||||
if (variant == FIRST) {
|
||||
if (this.variant == FIRST) {
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(element),this);
|
||||
}
|
||||
result.add(element);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw new SpelEvaluationException(selectionCriteria.getStartPosition(),
|
||||
SpelMessage.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST());
|
||||
}
|
||||
idx++;
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
state.exitScope();
|
||||
state.popActiveContextObject();
|
||||
}
|
||||
}
|
||||
if ((variant == FIRST || variant == LAST) && result.size() == 0) {
|
||||
|
||||
if ((this.variant == FIRST || this.variant == LAST) && result.size() == 0) {
|
||||
return ValueRef.NullValueRef.instance;
|
||||
}
|
||||
if (variant == LAST) {
|
||||
|
||||
if (this.variant == LAST) {
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(result.get(result.size() - 1)),this);
|
||||
}
|
||||
|
||||
if (operand instanceof Collection) {
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(result),this);
|
||||
}
|
||||
else {
|
||||
Class<?> elementType = ClassUtils.resolvePrimitiveIfNecessary(op.getTypeDescriptor().getElementTypeDescriptor().getType());
|
||||
Object resultArray = Array.newInstance(elementType, result.size());
|
||||
System.arraycopy(result.toArray(), 0, resultArray, 0, result.size());
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(resultArray),this);
|
||||
}
|
||||
} else {
|
||||
if (operand==null) {
|
||||
if (nullSafe) {
|
||||
return ValueRef.NullValueRef.instance;
|
||||
} else {
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INVALID_TYPE_FOR_SELECTION,
|
||||
"null");
|
||||
}
|
||||
} else {
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INVALID_TYPE_FOR_SELECTION,
|
||||
operand.getClass().getName());
|
||||
}
|
||||
Class<?> elementType = ClassUtils.resolvePrimitiveIfNecessary(op.getTypeDescriptor().getElementTypeDescriptor().getType());
|
||||
Object resultArray = Array.newInstance(elementType, result.size());
|
||||
System.arraycopy(result.toArray(), 0, resultArray, 0, result.size());
|
||||
return new ValueRef.TypedValueHolderValueRef(new TypedValue(resultArray),this);
|
||||
}
|
||||
if (operand==null) {
|
||||
if (this.nullSafe) {
|
||||
return ValueRef.NullValueRef.instance;
|
||||
}
|
||||
throw new SpelEvaluationException(getStartPosition(),
|
||||
SpelMessage.INVALID_TYPE_FOR_SELECTION, "null");
|
||||
}
|
||||
throw new SpelEvaluationException(getStartPosition(),
|
||||
SpelMessage.INVALID_TYPE_FOR_SELECTION, operand.getClass().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
switch (variant) {
|
||||
case ALL:
|
||||
sb.append("?[");
|
||||
break;
|
||||
case FIRST:
|
||||
sb.append("^[");
|
||||
break;
|
||||
case LAST:
|
||||
sb.append("$[");
|
||||
break;
|
||||
switch (this.variant) {
|
||||
case ALL:
|
||||
sb.append("?[");
|
||||
break;
|
||||
case FIRST:
|
||||
sb.append("^[");
|
||||
break;
|
||||
case LAST:
|
||||
sb.append("$[");
|
||||
break;
|
||||
}
|
||||
return sb.append(getChild(0).toStringAST()).append("]").toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -27,7 +27,8 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
|||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The common supertype of all AST nodes in a parsed Spring Expression Language format expression.
|
||||
* The common supertype of all AST nodes in a parsed Spring Expression Language format
|
||||
* expression.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -37,9 +38,12 @@ public abstract class SpelNodeImpl implements SpelNode {
|
|||
private static SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0];
|
||||
|
||||
protected int pos; // start = top 16bits, end = bottom 16bits
|
||||
|
||||
protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
|
||||
|
||||
private SpelNodeImpl parent;
|
||||
|
||||
|
||||
public SpelNodeImpl(int pos, SpelNodeImpl... operands) {
|
||||
this.pos = pos;
|
||||
// pos combines start and end so can never be zero because tokens cannot be zero length
|
||||
|
|
@ -52,11 +56,14 @@ public abstract class SpelNodeImpl implements SpelNode {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
protected SpelNodeImpl getPreviousChild() {
|
||||
SpelNodeImpl result = null;
|
||||
if (parent != null) {
|
||||
for (SpelNodeImpl child : parent.children) {
|
||||
if (this==child) break;
|
||||
if (this.parent != null) {
|
||||
for (SpelNodeImpl child : this.parent.children) {
|
||||
if (this==child) {
|
||||
break;
|
||||
}
|
||||
result = child;
|
||||
}
|
||||
}
|
||||
|
|
@ -67,21 +74,22 @@ public abstract class SpelNodeImpl implements SpelNode {
|
|||
* @return true if the next child is one of the specified classes
|
||||
*/
|
||||
protected boolean nextChildIs(Class... clazzes) {
|
||||
if (parent!=null) {
|
||||
SpelNodeImpl[] peers = parent.children;
|
||||
for (int i=0,max=peers.length;i<max;i++) {
|
||||
if (peers[i]==this) {
|
||||
if ((i+1)>=max) {
|
||||
return false;
|
||||
} else {
|
||||
Class clazz = peers[i+1].getClass();
|
||||
for (Class desiredClazz: clazzes) {
|
||||
if (clazz.equals(desiredClazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this.parent != null) {
|
||||
SpelNodeImpl[] peers = this.parent.children;
|
||||
for (int i = 0, max = peers.length; i < max; i++) {
|
||||
if (peers[i] == this) {
|
||||
if ((i + 1) >= max) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Class clazz = peers[i + 1].getClass();
|
||||
for (Class desiredClazz : clazzes) {
|
||||
if (clazz.equals(desiredClazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +100,8 @@ public abstract class SpelNodeImpl implements SpelNode {
|
|||
public final Object getValue(ExpressionState expressionState) throws EvaluationException {
|
||||
if (expressionState != null) {
|
||||
return getValueInternal(expressionState).getValue();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// configuration not set - does that matter?
|
||||
return getValue(new ExpressionState(new StandardEvaluationContext()));
|
||||
}
|
||||
|
|
@ -102,7 +111,8 @@ public abstract class SpelNodeImpl implements SpelNode {
|
|||
public final TypedValue getTypedValue(ExpressionState expressionState) throws EvaluationException {
|
||||
if (expressionState != null) {
|
||||
return getValueInternal(expressionState);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// configuration not set - does that matter?
|
||||
return getTypedValue(new ExpressionState(new StandardEvaluationContext()));
|
||||
}
|
||||
|
|
@ -116,17 +126,18 @@ public abstract class SpelNodeImpl implements SpelNode {
|
|||
|
||||
@Override
|
||||
public void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException {
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.SETVALUE_NOT_SUPPORTED, getClass());
|
||||
throw new SpelEvaluationException(getStartPosition(),
|
||||
SpelMessage.SETVALUE_NOT_SUPPORTED, getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpelNode getChild(int index) {
|
||||
return children[index];
|
||||
return this.children[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount() {
|
||||
return children.length;
|
||||
return this.children.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -148,15 +159,15 @@ public abstract class SpelNodeImpl implements SpelNode {
|
|||
|
||||
@Override
|
||||
public int getStartPosition() {
|
||||
return (pos>>16);
|
||||
return (this.pos>>16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEndPosition() {
|
||||
return (pos&0xffff);
|
||||
return (this.pos&0xffff);
|
||||
}
|
||||
|
||||
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
|
||||
throw new SpelEvaluationException(pos,SpelMessage.NOT_ASSIGNABLE,toStringAST());
|
||||
throw new SpelEvaluationException(this.pos,SpelMessage.NOT_ASSIGNABLE,toStringAST());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -19,6 +19,8 @@ package org.springframework.expression.spel.ast;
|
|||
import org.springframework.expression.TypedValue;
|
||||
|
||||
/**
|
||||
* Expression language AST node that represents a string literal.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
|
|
@ -27,6 +29,7 @@ public class StringLiteral extends Literal {
|
|||
|
||||
private final TypedValue value;
|
||||
|
||||
|
||||
public StringLiteral(String payload, int pos, String value) {
|
||||
super(payload,pos);
|
||||
// TODO should these have been skipped being created by the parser rules? or not?
|
||||
|
|
@ -34,6 +37,7 @@ public class StringLiteral extends Literal {
|
|||
this.value = new TypedValue(value.replaceAll("''", "'").replaceAll("\"\"", "\""));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getLiteralValue() {
|
||||
return this.value;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -37,22 +37,24 @@ public class Ternary extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
/**
|
||||
* Evaluate the condition and if true evaluate the first alternative, otherwise evaluate the second alternative.
|
||||
* Evaluate the condition and if true evaluate the first alternative, otherwise
|
||||
* evaluate the second alternative.
|
||||
* @param state the expression state
|
||||
* @throws EvaluationException if the condition does not evaluate correctly to a boolean or there is a problem
|
||||
* executing the chosen alternative
|
||||
* @throws EvaluationException if the condition does not evaluate correctly to a
|
||||
* boolean or there is a problem executing the chosen alternative
|
||||
*/
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
Boolean value = children[0].getValue(state, Boolean.class);
|
||||
Boolean value = this.children[0].getValue(state, Boolean.class);
|
||||
if (value == null) {
|
||||
throw new SpelEvaluationException(getChild(0).getStartPosition(),
|
||||
SpelMessage.TYPE_CONVERSION_ERROR, "null", "boolean");
|
||||
}
|
||||
if (value.booleanValue()) {
|
||||
return children[1].getValueInternal(state);
|
||||
} else {
|
||||
return children[2].getValueInternal(state);
|
||||
return this.children[1].getValueInternal(state);
|
||||
}
|
||||
else {
|
||||
return this.children[2].getValueInternal(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -16,26 +16,45 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
/**
|
||||
* Captures primitive types and their corresponding class objects, plus one special entry that represents all reference
|
||||
* (non-primitive) types.
|
||||
* Captures primitive types and their corresponding class objects, plus one special entry
|
||||
* that represents all reference (non-primitive) types.
|
||||
*
|
||||
* @author Andy Clement
|
||||
*/
|
||||
public enum TypeCode {
|
||||
|
||||
OBJECT(Object.class), BOOLEAN(Boolean.TYPE), BYTE(Byte.TYPE), CHAR(Character.TYPE), //
|
||||
SHORT(Short.TYPE), INT(Integer.TYPE), LONG(Long.TYPE), FLOAT(Float.TYPE), DOUBLE(Double.TYPE);
|
||||
OBJECT(Object.class),
|
||||
|
||||
BOOLEAN(Boolean.TYPE),
|
||||
|
||||
BYTE(Byte.TYPE),
|
||||
|
||||
CHAR(Character.TYPE),
|
||||
|
||||
SHORT(Short.TYPE),
|
||||
|
||||
INT(Integer.TYPE),
|
||||
|
||||
LONG(Long.TYPE),
|
||||
|
||||
FLOAT(Float.TYPE),
|
||||
|
||||
DOUBLE(Double.TYPE);
|
||||
|
||||
|
||||
private Class<?> type;
|
||||
|
||||
|
||||
TypeCode(Class<?> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
return this.type;
|
||||
}
|
||||
|
||||
|
||||
public static TypeCode forName(String name) {
|
||||
String searchingFor = name.toUpperCase();
|
||||
TypeCode[] tcs = values();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -29,21 +29,23 @@ import org.springframework.expression.spel.ExpressionState;
|
|||
*/
|
||||
public class TypeReference extends SpelNodeImpl {
|
||||
|
||||
private int dimensions;
|
||||
private final int dimensions;
|
||||
|
||||
public TypeReference(int pos,SpelNodeImpl qualifiedId) {
|
||||
|
||||
public TypeReference(int pos, SpelNodeImpl qualifiedId) {
|
||||
this(pos,qualifiedId,0);
|
||||
}
|
||||
|
||||
public TypeReference(int pos,SpelNodeImpl qualifiedId,int dims) {
|
||||
public TypeReference(int pos, SpelNodeImpl qualifiedId, int dims) {
|
||||
super(pos,qualifiedId);
|
||||
this.dimensions = dims;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
// TODO possible optimization here if we cache the discovered type reference, but can we do that?
|
||||
String typename = (String) children[0].getValueInternal(state).getValue();
|
||||
String typename = (String) this.children[0].getValueInternal(state).getValue();
|
||||
if (typename.indexOf(".") == -1 && Character.isLowerCase(typename.charAt(0))) {
|
||||
TypeCode tc = TypeCode.valueOf(typename.toUpperCase());
|
||||
if (tc != TypeCode.OBJECT) {
|
||||
|
|
@ -59,8 +61,8 @@ public class TypeReference extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
private Class makeArrayIfNecessary(Class clazz) {
|
||||
if (dimensions!=0) {
|
||||
for (int i=0;i<dimensions;i++) {
|
||||
if (this.dimensions!=0) {
|
||||
for (int i=0;i<this.dimensions;i++) {
|
||||
Object o = Array.newInstance(clazz, 0);
|
||||
clazz = o.getClass();
|
||||
}
|
||||
|
|
@ -73,7 +75,7 @@ public class TypeReference extends SpelNodeImpl {
|
|||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("T(");
|
||||
sb.append(getChild(0).toStringAST());
|
||||
for (int d=0;d<dimensions;d++) {
|
||||
for (int d=0;d<this.dimensions;d++) {
|
||||
sb.append("[]");
|
||||
}
|
||||
sb.append(")");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -33,6 +33,27 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
*/
|
||||
public interface ValueRef {
|
||||
|
||||
/**
|
||||
* Returns the value this ValueRef points to, it should not require expression
|
||||
* component re-evaluation.
|
||||
* @return the value
|
||||
*/
|
||||
TypedValue getValue();
|
||||
|
||||
/**
|
||||
* Sets the value this ValueRef points to, it should not require expression component
|
||||
* re-evaluation.
|
||||
* @param newValue the new value
|
||||
*/
|
||||
void setValue(Object newValue);
|
||||
|
||||
/**
|
||||
* Indicates whether calling setValue(Object) is supported.
|
||||
* @return true if setValue() is supported for this value reference.
|
||||
*/
|
||||
boolean isWritable();
|
||||
|
||||
|
||||
/**
|
||||
* A ValueRef for the null value.
|
||||
*/
|
||||
|
|
@ -60,13 +81,14 @@ public interface ValueRef {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A ValueRef holder for a single value, which cannot be set.
|
||||
*/
|
||||
static class TypedValueHolderValueRef implements ValueRef {
|
||||
|
||||
private TypedValue typedValue;
|
||||
private SpelNodeImpl node; // used only for error reporting
|
||||
private final TypedValue typedValue;
|
||||
private final SpelNodeImpl node; // used only for error reporting
|
||||
|
||||
public TypedValueHolderValueRef(TypedValue typedValue,SpelNodeImpl node) {
|
||||
this.typedValue = typedValue;
|
||||
|
|
@ -91,23 +113,4 @@ public interface ValueRef {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value this ValueRef points to, it should not require expression
|
||||
* component re-evaluation.
|
||||
* @return the value
|
||||
*/
|
||||
TypedValue getValue();
|
||||
|
||||
/**
|
||||
* Sets the value this ValueRef points to, it should not require expression component
|
||||
* re-evaluation.
|
||||
* @param newValue the new value
|
||||
*/
|
||||
void setValue(Object newValue);
|
||||
|
||||
/**
|
||||
* Indicates whether calling setValue(Object) is supported.
|
||||
* @return true if setValue() is supported for this value reference.
|
||||
*/
|
||||
boolean isWritable();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -22,7 +22,8 @@ import org.springframework.expression.spel.ExpressionState;
|
|||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
|
||||
/**
|
||||
* Represents a variable reference, eg. #someVar. Note this is different to a *local* variable like $someVar
|
||||
* Represents a variable reference, eg. #someVar. Note this is different to a *local*
|
||||
* variable like $someVar
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -30,46 +31,17 @@ import org.springframework.expression.spel.SpelEvaluationException;
|
|||
public class VariableReference extends SpelNodeImpl {
|
||||
|
||||
// Well known variables:
|
||||
private final static String THIS = "this"; // currently active context object
|
||||
private final static String ROOT = "root"; // root context object
|
||||
private static final String THIS = "this"; // currently active context object
|
||||
|
||||
private static final String ROOT = "root"; // root context object
|
||||
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
public VariableReference(String variableName, int pos) {
|
||||
super(pos);
|
||||
name = variableName;
|
||||
}
|
||||
|
||||
|
||||
class VariableRef implements ValueRef {
|
||||
|
||||
private String name;
|
||||
private TypedValue value;
|
||||
private EvaluationContext eContext;
|
||||
|
||||
public VariableRef(String name, TypedValue value,
|
||||
EvaluationContext evaluationContext) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.eContext = evaluationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object newValue) {
|
||||
eContext.setVariable(name, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.name = variableName;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -114,4 +86,39 @@ public class VariableReference extends SpelNodeImpl {
|
|||
return !(this.name.equals(THIS) || this.name.equals(ROOT));
|
||||
}
|
||||
|
||||
|
||||
class VariableRef implements ValueRef {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final TypedValue value;
|
||||
|
||||
private final EvaluationContext evaluationContext;
|
||||
|
||||
|
||||
public VariableRef(String name, TypedValue value,
|
||||
EvaluationContext evaluationContext) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.evaluationContext = evaluationContext;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypedValue getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object newValue) {
|
||||
this.evaluationContext.setVariable(this.name, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
|
||||
private static final Pattern VALID_QUALIFIED_ID_PATTERN = Pattern.compile("[\\p{L}\\p{N}_$]+");
|
||||
|
||||
|
||||
// The expression being parsed
|
||||
private String expressionString;
|
||||
|
||||
|
|
@ -57,9 +58,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
private int tokenStreamPointer;
|
||||
|
||||
// For rules that build nodes, they are stacked here for return
|
||||
private Stack<SpelNodeImpl> constructedNodes = new Stack<SpelNodeImpl>();
|
||||
private final Stack<SpelNodeImpl> constructedNodes = new Stack<SpelNodeImpl>();
|
||||
|
||||
private SpelParserConfiguration configuration;
|
||||
private final SpelParserConfiguration configuration;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -77,16 +78,16 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
this.expressionString = expressionString;
|
||||
Tokenizer tokenizer = new Tokenizer(expressionString);
|
||||
tokenizer.process();
|
||||
tokenStream = tokenizer.getTokens();
|
||||
tokenStreamLength = tokenStream.size();
|
||||
tokenStreamPointer = 0;
|
||||
constructedNodes.clear();
|
||||
this.tokenStream = tokenizer.getTokens();
|
||||
this.tokenStreamLength = this.tokenStream.size();
|
||||
this.tokenStreamPointer = 0;
|
||||
this.constructedNodes.clear();
|
||||
SpelNodeImpl ast = eatExpression();
|
||||
if (moreTokens()) {
|
||||
throw new SpelParseException(peekToken().startpos,SpelMessage.MORE_INPUT,toString(nextToken()));
|
||||
}
|
||||
Assert.isTrue(constructedNodes.isEmpty());
|
||||
return new SpelExpression(expressionString, ast, configuration);
|
||||
Assert.isTrue(this.constructedNodes.isEmpty());
|
||||
return new SpelExpression(expressionString, ast, this.configuration);
|
||||
}
|
||||
catch (InternalParseException ipe) {
|
||||
throw ipe.getCause();
|
||||
|
|
@ -110,7 +111,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
nextToken();
|
||||
SpelNodeImpl assignedValue = eatLogicalOrExpression();
|
||||
return new Assign(toPos(t),expr,assignedValue);
|
||||
} else if (t.kind==TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b)
|
||||
}
|
||||
|
||||
if (t.kind==TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b)
|
||||
if (expr==null) {
|
||||
expr = new NullLiteral(toPos(t.startpos-1,t.endpos-2));
|
||||
}
|
||||
|
|
@ -120,7 +123,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
valueIfNull = new NullLiteral(toPos(t.startpos+1,t.endpos+1));
|
||||
}
|
||||
return new Elvis(toPos(t),expr,valueIfNull);
|
||||
} else if (t.kind==TokenKind.QMARK) { // a?b:c
|
||||
}
|
||||
|
||||
if (t.kind==TokenKind.QMARK) { // a?b:c
|
||||
if (expr==null) {
|
||||
expr = new NullLiteral(toPos(t.startpos-1,t.endpos-1));
|
||||
}
|
||||
|
|
@ -167,31 +172,38 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
SpelNodeImpl rhExpr = eatSumExpression();
|
||||
checkOperands(t,expr,rhExpr);
|
||||
TokenKind tk = relationalOperatorToken.kind;
|
||||
|
||||
if (relationalOperatorToken.isNumericRelationalOperator()) {
|
||||
int pos = toPos(t);
|
||||
if (tk==TokenKind.GT) {
|
||||
return new OpGT(pos,expr,rhExpr);
|
||||
} else if (tk==TokenKind.LT) {
|
||||
return new OpLT(pos,expr,rhExpr);
|
||||
} else if (tk==TokenKind.LE) {
|
||||
return new OpLE(pos,expr,rhExpr);
|
||||
} else if (tk==TokenKind.GE) {
|
||||
return new OpGE(pos,expr,rhExpr);
|
||||
} else if (tk == TokenKind.EQ) {
|
||||
return new OpEQ(pos,expr,rhExpr);
|
||||
} else {
|
||||
Assert.isTrue(tk == TokenKind.NE);
|
||||
return new OpNE(pos,expr,rhExpr);
|
||||
if (tk == TokenKind.GT) {
|
||||
return new OpGT(pos, expr, rhExpr);
|
||||
}
|
||||
if (tk == TokenKind.LT) {
|
||||
return new OpLT(pos, expr, rhExpr);
|
||||
}
|
||||
if (tk == TokenKind.LE) {
|
||||
return new OpLE(pos, expr, rhExpr);
|
||||
}
|
||||
if (tk == TokenKind.GE) {
|
||||
return new OpGE(pos, expr, rhExpr);
|
||||
}
|
||||
if (tk == TokenKind.EQ) {
|
||||
return new OpEQ(pos, expr, rhExpr);
|
||||
}
|
||||
Assert.isTrue(tk == TokenKind.NE);
|
||||
return new OpNE(pos, expr, rhExpr);
|
||||
}
|
||||
if (tk==TokenKind.INSTANCEOF) {
|
||||
return new OperatorInstanceof(toPos(t),expr,rhExpr);
|
||||
} else if (tk==TokenKind.MATCHES) {
|
||||
return new OperatorMatches(toPos(t),expr,rhExpr);
|
||||
} else {
|
||||
Assert.isTrue(tk==TokenKind.BETWEEN);
|
||||
return new org.springframework.expression.spel.ast.OperatorBetween(toPos(t),expr,rhExpr);
|
||||
|
||||
if (tk == TokenKind.INSTANCEOF) {
|
||||
return new OperatorInstanceof(toPos(t), expr, rhExpr);
|
||||
}
|
||||
|
||||
if (tk == TokenKind.MATCHES) {
|
||||
return new OperatorMatches(toPos(t), expr, rhExpr);
|
||||
}
|
||||
|
||||
Assert.isTrue(tk == TokenKind.BETWEEN);
|
||||
return new OperatorBetween(toPos(t), expr, rhExpr);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
|
@ -199,14 +211,15 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
//sumExpression: productExpression ( (PLUS^ | MINUS^) productExpression)*;
|
||||
private SpelNodeImpl eatSumExpression() {
|
||||
SpelNodeImpl expr = eatProductExpression();
|
||||
while (peekToken(TokenKind.PLUS,TokenKind.MINUS,TokenKind.INC)) {
|
||||
while (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.INC)) {
|
||||
Token t = nextToken();//consume PLUS or MINUS or INC
|
||||
SpelNodeImpl rhExpr = eatProductExpression();
|
||||
checkRightOperand(t,rhExpr);
|
||||
if (t.kind==TokenKind.PLUS) {
|
||||
expr = new OpPlus(toPos(t),expr,rhExpr);
|
||||
} else if (t.kind==TokenKind.MINUS) {
|
||||
expr = new OpMinus(toPos(t),expr,rhExpr);
|
||||
if (t.kind == TokenKind.PLUS) {
|
||||
expr = new OpPlus(toPos(t), expr, rhExpr);
|
||||
}
|
||||
else if (t.kind == TokenKind.MINUS) {
|
||||
expr = new OpMinus(toPos(t), expr, rhExpr);
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
|
|
@ -215,17 +228,19 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
// productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ;
|
||||
private SpelNodeImpl eatProductExpression() {
|
||||
SpelNodeImpl expr = eatPowerIncDecExpression();
|
||||
while (peekToken(TokenKind.STAR,TokenKind.DIV,TokenKind.MOD)) {
|
||||
while (peekToken(TokenKind.STAR, TokenKind.DIV, TokenKind.MOD)) {
|
||||
Token t = nextToken(); // consume STAR/DIV/MOD
|
||||
SpelNodeImpl rhExpr = eatPowerIncDecExpression();
|
||||
checkOperands(t,expr,rhExpr);
|
||||
if (t.kind==TokenKind.STAR) {
|
||||
expr = new OpMultiply(toPos(t),expr,rhExpr);
|
||||
} else if (t.kind==TokenKind.DIV) {
|
||||
expr = new OpDivide(toPos(t),expr,rhExpr);
|
||||
} else {
|
||||
Assert.isTrue(t.kind==TokenKind.MOD);
|
||||
expr = new OpModulus(toPos(t),expr,rhExpr);
|
||||
if (t.kind == TokenKind.STAR) {
|
||||
expr = new OpMultiply(toPos(t), expr, rhExpr);
|
||||
}
|
||||
else if (t.kind == TokenKind.DIV) {
|
||||
expr = new OpDivide(toPos(t), expr, rhExpr);
|
||||
}
|
||||
else {
|
||||
Assert.isTrue(t.kind == TokenKind.MOD);
|
||||
expr = new OpModulus(toPos(t), expr, rhExpr);
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
|
|
@ -239,41 +254,45 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
SpelNodeImpl rhExpr = eatUnaryExpression();
|
||||
checkRightOperand(t,rhExpr);
|
||||
return new OperatorPower(toPos(t),expr, rhExpr);
|
||||
} else if (expr!=null && peekToken(TokenKind.INC,TokenKind.DEC)) {
|
||||
}
|
||||
|
||||
if (expr!=null && peekToken(TokenKind.INC,TokenKind.DEC)) {
|
||||
Token t = nextToken();//consume INC/DEC
|
||||
if (t.getKind()==TokenKind.INC) {
|
||||
return new OpInc(toPos(t),true,expr);
|
||||
} else {
|
||||
return new OpDec(toPos(t),true,expr);
|
||||
}
|
||||
return new OpDec(toPos(t),true,expr);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
// unaryExpression: (PLUS^ | MINUS^ | BANG^ | INC^ | DEC^) unaryExpression | primaryExpression ;
|
||||
private SpelNodeImpl eatUnaryExpression() {
|
||||
if (peekToken(TokenKind.PLUS,TokenKind.MINUS,TokenKind.NOT)) {
|
||||
if (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.NOT)) {
|
||||
Token t = nextToken();
|
||||
SpelNodeImpl expr = eatUnaryExpression();
|
||||
if (t.kind==TokenKind.NOT) {
|
||||
return new OperatorNot(toPos(t),expr);
|
||||
} else if (t.kind==TokenKind.PLUS) {
|
||||
return new OpPlus(toPos(t),expr);
|
||||
} else {
|
||||
Assert.isTrue(t.kind==TokenKind.MINUS);
|
||||
return new OpMinus(toPos(t),expr);
|
||||
if (t.kind == TokenKind.NOT) {
|
||||
return new OperatorNot(toPos(t), expr);
|
||||
}
|
||||
} else if (peekToken(TokenKind.INC,TokenKind.DEC)) {
|
||||
Token t = nextToken();
|
||||
SpelNodeImpl expr = eatUnaryExpression();
|
||||
if (t.getKind()==TokenKind.INC) {
|
||||
return new OpInc(toPos(t),false,expr);
|
||||
} else {
|
||||
return new OpDec(toPos(t),false,expr);
|
||||
|
||||
if (t.kind == TokenKind.PLUS) {
|
||||
return new OpPlus(toPos(t), expr);
|
||||
}
|
||||
} else {
|
||||
return eatPrimaryExpression();
|
||||
Assert.isTrue(t.kind == TokenKind.MINUS);
|
||||
return new OpMinus(toPos(t), expr);
|
||||
|
||||
}
|
||||
if (peekToken(TokenKind.INC, TokenKind.DEC)) {
|
||||
Token t = nextToken();
|
||||
SpelNodeImpl expr = eatUnaryExpression();
|
||||
if (t.getKind() == TokenKind.INC) {
|
||||
return new OpInc(toPos(t), false, expr);
|
||||
}
|
||||
return new OpDec(toPos(t), false, expr);
|
||||
}
|
||||
|
||||
return eatPrimaryExpression();
|
||||
}
|
||||
|
||||
// primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?);
|
||||
|
|
@ -284,11 +303,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
while (maybeEatNode()) {
|
||||
nodes.add(pop());
|
||||
}
|
||||
if (nodes.size()==1) {
|
||||
if (nodes.size() == 1) {
|
||||
return nodes.get(0);
|
||||
} else {
|
||||
return new CompoundExpression(toPos(start.getStartPosition(),nodes.get(nodes.size()-1).getEndPosition()),nodes.toArray(new SpelNodeImpl[nodes.size()]));
|
||||
}
|
||||
return new CompoundExpression(toPos(start.getStartPosition(),
|
||||
nodes.get(nodes.size() - 1).getEndPosition()),
|
||||
nodes.toArray(new SpelNodeImpl[nodes.size()]));
|
||||
}
|
||||
|
||||
// node : ((DOT dottedNode) | (SAFE_NAVI dottedNode) | nonDottedNode)+;
|
||||
|
|
@ -299,6 +319,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
} else {
|
||||
expr = maybeEatNonDottedNode();
|
||||
}
|
||||
|
||||
if (expr==null) {
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -328,15 +349,19 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
// ;
|
||||
private SpelNodeImpl eatDottedNode() {
|
||||
Token t = nextToken();// it was a '.' or a '?.'
|
||||
boolean nullSafeNavigation = t.kind==TokenKind.SAFE_NAVI;
|
||||
if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) {
|
||||
boolean nullSafeNavigation = t.kind == TokenKind.SAFE_NAVI;
|
||||
if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar()
|
||||
|| maybeEatProjection(nullSafeNavigation)
|
||||
|| maybeEatSelection(nullSafeNavigation)) {
|
||||
return pop();
|
||||
}
|
||||
if (peekToken()==null) {
|
||||
if (peekToken() == null) {
|
||||
// unexpectedly ran out of data
|
||||
raiseInternalException(t.startpos,SpelMessage.OOD);
|
||||
} else {
|
||||
raiseInternalException(t.startpos,SpelMessage.UNEXPECTED_DATA_AFTER_DOT,toString(peekToken()));
|
||||
raiseInternalException(t.startpos, SpelMessage.OOD);
|
||||
}
|
||||
else {
|
||||
raiseInternalException(t.startpos, SpelMessage.UNEXPECTED_DATA_AFTER_DOT,
|
||||
toString(peekToken()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -354,13 +379,15 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
Token t = nextToken();
|
||||
Token functionOrVariableName = eatToken(TokenKind.IDENTIFIER);
|
||||
SpelNodeImpl[] args = maybeEatMethodArgs();
|
||||
if (args==null) {
|
||||
push(new VariableReference(functionOrVariableName.data,toPos(t.startpos,functionOrVariableName.endpos)));
|
||||
return true;
|
||||
} else {
|
||||
push(new FunctionReference(functionOrVariableName.data,toPos(t.startpos,functionOrVariableName.endpos),args));
|
||||
if (args == null) {
|
||||
push(new VariableReference(functionOrVariableName.data, toPos(t.startpos,
|
||||
functionOrVariableName.endpos)));
|
||||
return true;
|
||||
}
|
||||
|
||||
push(new FunctionReference(functionOrVariableName.data, toPos(t.startpos,
|
||||
functionOrVariableName.endpos), args));
|
||||
return true;
|
||||
}
|
||||
|
||||
// methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!;
|
||||
|
|
@ -376,7 +403,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
|
||||
private void eatConstructorArgs(List<SpelNodeImpl> accumulatedArguments) {
|
||||
if (!peekToken(TokenKind.LPAREN)) {
|
||||
throw new InternalParseException(new SpelParseException(expressionString,positionOf(peekToken()),SpelMessage.MISSING_CONSTRUCTOR_ARGS));
|
||||
throw new InternalParseException(new SpelParseException(this.expressionString,positionOf(peekToken()),SpelMessage.MISSING_CONSTRUCTOR_ARGS));
|
||||
}
|
||||
consumeArguments(accumulatedArguments);
|
||||
eatToken(TokenKind.RPAREN);
|
||||
|
|
@ -391,27 +418,28 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
do {
|
||||
nextToken();// consume ( (first time through) or comma (subsequent times)
|
||||
Token t = peekToken();
|
||||
if (t==null) {
|
||||
raiseInternalException(pos,SpelMessage.RUN_OUT_OF_ARGUMENTS);
|
||||
if (t == null) {
|
||||
raiseInternalException(pos, SpelMessage.RUN_OUT_OF_ARGUMENTS);
|
||||
}
|
||||
if (t.kind!=TokenKind.RPAREN) {
|
||||
if (t.kind != TokenKind.RPAREN) {
|
||||
accumulatedArguments.add(eatExpression());
|
||||
}
|
||||
next = peekToken();
|
||||
} while (next!=null && next.kind==TokenKind.COMMA);
|
||||
if (next==null) {
|
||||
raiseInternalException(pos,SpelMessage.RUN_OUT_OF_ARGUMENTS);
|
||||
}
|
||||
while (next != null && next.kind == TokenKind.COMMA);
|
||||
|
||||
if (next == null) {
|
||||
raiseInternalException(pos, SpelMessage.RUN_OUT_OF_ARGUMENTS);
|
||||
}
|
||||
}
|
||||
|
||||
private int positionOf(Token t) {
|
||||
if (t==null) {
|
||||
if (t == null) {
|
||||
// if null assume the problem is because the right token was
|
||||
// not found at the end of the expression
|
||||
return expressionString.length();
|
||||
} else {
|
||||
return t.startpos;
|
||||
return this.expressionString.length();
|
||||
}
|
||||
return t.startpos;
|
||||
}
|
||||
|
||||
//startNode
|
||||
|
|
@ -428,17 +456,26 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
private SpelNodeImpl eatStartNode() {
|
||||
if (maybeEatLiteral()) {
|
||||
return pop();
|
||||
} else if (maybeEatParenExpression()) {
|
||||
}
|
||||
else if (maybeEatParenExpression()) {
|
||||
return pop();
|
||||
} else if (maybeEatTypeReference() || maybeEatNullReference() || maybeEatConstructorReference() || maybeEatMethodOrProperty(false) || maybeEatFunctionOrVar()) {
|
||||
}
|
||||
else if (maybeEatTypeReference() || maybeEatNullReference()
|
||||
|| maybeEatConstructorReference() || maybeEatMethodOrProperty(false)
|
||||
|| maybeEatFunctionOrVar()) {
|
||||
return pop();
|
||||
} else if (maybeEatBeanReference()) {
|
||||
}
|
||||
else if (maybeEatBeanReference()) {
|
||||
return pop();
|
||||
} else if (maybeEatProjection(false) || maybeEatSelection(false) || maybeEatIndexer()) {
|
||||
}
|
||||
else if (maybeEatProjection(false) || maybeEatSelection(false)
|
||||
|| maybeEatIndexer()) {
|
||||
return pop();
|
||||
} else if (maybeEatInlineList()) {
|
||||
}
|
||||
else if (maybeEatInlineList()) {
|
||||
return pop();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -453,16 +490,19 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
if (peekToken(TokenKind.IDENTIFIER)) {
|
||||
beanNameToken = eatToken(TokenKind.IDENTIFIER);
|
||||
beanname = beanNameToken.data;
|
||||
} else if (peekToken(TokenKind.LITERAL_STRING)) {
|
||||
}
|
||||
else if (peekToken(TokenKind.LITERAL_STRING)) {
|
||||
beanNameToken = eatToken(TokenKind.LITERAL_STRING);
|
||||
beanname = beanNameToken.stringValue();
|
||||
beanname = beanname.substring(1, beanname.length() - 1);
|
||||
} else {
|
||||
raiseInternalException(beanRefToken.startpos,SpelMessage.INVALID_BEAN_REFERENCE);
|
||||
}
|
||||
else {
|
||||
raiseInternalException(beanRefToken.startpos,
|
||||
SpelMessage.INVALID_BEAN_REFERENCE);
|
||||
}
|
||||
|
||||
BeanReference beanReference = new BeanReference(toPos(beanNameToken),beanname);
|
||||
constructedNodes.push(beanReference);
|
||||
this.constructedNodes.push(beanReference);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -485,7 +525,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
dims++;
|
||||
}
|
||||
eatToken(TokenKind.RPAREN);
|
||||
constructedNodes.push(new TypeReference(toPos(typeName),node,dims));
|
||||
this.constructedNodes.push(new TypeReference(toPos(typeName),node,dims));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -498,7 +538,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
return false;
|
||||
}
|
||||
nextToken();
|
||||
constructedNodes.push(new NullLiteral(toPos(nullToken)));
|
||||
this.constructedNodes.push(new NullLiteral(toPos(nullToken)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -507,46 +547,48 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
//projection: PROJECT^ expression RCURLY!;
|
||||
private boolean maybeEatProjection(boolean nullSafeNavigation) {
|
||||
Token t = peekToken();
|
||||
if (!peekToken(TokenKind.PROJECT,true)) {
|
||||
if (!peekToken(TokenKind.PROJECT, true)) {
|
||||
return false;
|
||||
}
|
||||
SpelNodeImpl expr = eatExpression();
|
||||
eatToken(TokenKind.RSQUARE);
|
||||
constructedNodes.push(new Projection(nullSafeNavigation, toPos(t), expr));
|
||||
this.constructedNodes.push(new Projection(nullSafeNavigation, toPos(t), expr));
|
||||
return true;
|
||||
}
|
||||
|
||||
// list = LCURLY (element (COMMA element)*) RCURLY
|
||||
private boolean maybeEatInlineList() {
|
||||
Token t = peekToken();
|
||||
if (!peekToken(TokenKind.LCURLY,true)) {
|
||||
if (!peekToken(TokenKind.LCURLY, true)) {
|
||||
return false;
|
||||
}
|
||||
SpelNodeImpl expr = null;
|
||||
Token closingCurly = peekToken();
|
||||
if (peekToken(TokenKind.RCURLY,true)) {
|
||||
if (peekToken(TokenKind.RCURLY, true)) {
|
||||
// empty list '[]'
|
||||
expr = new InlineList(toPos(t.startpos,closingCurly.endpos));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
List<SpelNodeImpl> listElements = new ArrayList<SpelNodeImpl>();
|
||||
do {
|
||||
listElements.add(eatExpression());
|
||||
} while (peekToken(TokenKind.COMMA,true));
|
||||
|
||||
closingCurly = eatToken(TokenKind.RCURLY);
|
||||
expr = new InlineList(toPos(t.startpos,closingCurly.endpos),listElements.toArray(new SpelNodeImpl[listElements.size()]));
|
||||
}
|
||||
constructedNodes.push(expr);
|
||||
this.constructedNodes.push(expr);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean maybeEatIndexer() {
|
||||
Token t = peekToken();
|
||||
if (!peekToken(TokenKind.LSQUARE,true)) {
|
||||
if (!peekToken(TokenKind.LSQUARE, true)) {
|
||||
return false;
|
||||
}
|
||||
SpelNodeImpl expr = eatExpression();
|
||||
eatToken(TokenKind.RSQUARE);
|
||||
constructedNodes.push(new Indexer(toPos(t),expr));
|
||||
this.constructedNodes.push(new Indexer(toPos(t),expr));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -561,12 +603,14 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
raiseInternalException(toPos(t), SpelMessage.MISSING_SELECTION_EXPRESSION);
|
||||
}
|
||||
eatToken(TokenKind.RSQUARE);
|
||||
if (t.kind==TokenKind.SELECT_FIRST) {
|
||||
constructedNodes.push(new Selection(nullSafeNavigation,Selection.FIRST,toPos(t),expr));
|
||||
} else if (t.kind==TokenKind.SELECT_LAST) {
|
||||
constructedNodes.push(new Selection(nullSafeNavigation,Selection.LAST,toPos(t),expr));
|
||||
} else {
|
||||
constructedNodes.push(new Selection(nullSafeNavigation,Selection.ALL,toPos(t),expr));
|
||||
if (t.kind == TokenKind.SELECT_FIRST) {
|
||||
this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.FIRST, toPos(t), expr));
|
||||
}
|
||||
else if (t.kind == TokenKind.SELECT_LAST) {
|
||||
this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.LAST, toPos(t), expr));
|
||||
}
|
||||
else {
|
||||
this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.ALL, toPos(t), expr));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -587,7 +631,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
if(qualifiedIdPieces.isEmpty()) {
|
||||
if(node == null) {
|
||||
raiseInternalException( expressionString.length(), SpelMessage.OOD);
|
||||
raiseInternalException( this.expressionString.length(), SpelMessage.OOD);
|
||||
}
|
||||
raiseInternalException(node.startpos, SpelMessage.NOT_EXPECTED_TOKEN,
|
||||
"qualified ID", node.getKind().toString().toLowerCase());
|
||||
|
|
@ -617,13 +661,13 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
// property
|
||||
push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName)));
|
||||
return true;
|
||||
} else {
|
||||
// methodreference
|
||||
push(new MethodReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName),args));
|
||||
// TODO what is the end position for a method reference? the name or the last arg?
|
||||
return true;
|
||||
}
|
||||
// methodreference
|
||||
push(new MethodReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName),args));
|
||||
// TODO what is the end position for a method reference? the name or the last arg?
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
|
@ -642,7 +686,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
while (peekToken(TokenKind.LSQUARE,true)) {
|
||||
if (!peekToken(TokenKind.RSQUARE)) {
|
||||
dimensions.add(eatExpression());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
dimensions.add(null);
|
||||
}
|
||||
eatToken(TokenKind.RSQUARE);
|
||||
|
|
@ -652,11 +697,13 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
push(new ConstructorReference(toPos(newToken), dimensions.toArray(new SpelNodeImpl[dimensions.size()]),
|
||||
nodes.toArray(new SpelNodeImpl[nodes.size()])));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// regular constructor invocation
|
||||
eatConstructorArgs(nodes);
|
||||
// TODO correct end position?
|
||||
push(new ConstructorReference(toPos(newToken), nodes.toArray(new SpelNodeImpl[nodes.size()])));
|
||||
push(new ConstructorReference(toPos(newToken),
|
||||
nodes.toArray(new SpelNodeImpl[nodes.size()])));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -664,11 +711,11 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
|
||||
private void push(SpelNodeImpl newNode) {
|
||||
constructedNodes.push(newNode);
|
||||
this.constructedNodes.push(newNode);
|
||||
}
|
||||
|
||||
private SpelNodeImpl pop() {
|
||||
return constructedNodes.pop();
|
||||
return this.constructedNodes.pop();
|
||||
}
|
||||
|
||||
// literal
|
||||
|
|
@ -684,25 +731,34 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
if (t==null) {
|
||||
return false;
|
||||
}
|
||||
if (t.kind==TokenKind.LITERAL_INT) {
|
||||
if (t.kind == TokenKind.LITERAL_INT) {
|
||||
push(Literal.getIntLiteral(t.data, toPos(t), 10));
|
||||
} else if (t.kind==TokenKind.LITERAL_LONG) {
|
||||
}
|
||||
else if (t.kind == TokenKind.LITERAL_LONG) {
|
||||
push(Literal.getLongLiteral(t.data, toPos(t), 10));
|
||||
} else if (t.kind==TokenKind.LITERAL_HEXINT) {
|
||||
}
|
||||
else if (t.kind == TokenKind.LITERAL_HEXINT) {
|
||||
push(Literal.getIntLiteral(t.data, toPos(t), 16));
|
||||
} else if (t.kind==TokenKind.LITERAL_HEXLONG) {
|
||||
}
|
||||
else if (t.kind == TokenKind.LITERAL_HEXLONG) {
|
||||
push(Literal.getLongLiteral(t.data, toPos(t), 16));
|
||||
} else if (t.kind==TokenKind.LITERAL_REAL) {
|
||||
push(Literal.getRealLiteral(t.data, toPos(t),false));
|
||||
} else if (t.kind==TokenKind.LITERAL_REAL_FLOAT) {
|
||||
}
|
||||
else if (t.kind == TokenKind.LITERAL_REAL) {
|
||||
push(Literal.getRealLiteral(t.data, toPos(t), false));
|
||||
}
|
||||
else if (t.kind == TokenKind.LITERAL_REAL_FLOAT) {
|
||||
push(Literal.getRealLiteral(t.data, toPos(t), true));
|
||||
} else if (peekIdentifierToken("true")) {
|
||||
push(new BooleanLiteral(t.data,toPos(t),true));
|
||||
} else if (peekIdentifierToken("false")) {
|
||||
push(new BooleanLiteral(t.data,toPos(t),false));
|
||||
} else if (t.kind==TokenKind.LITERAL_STRING) {
|
||||
push(new StringLiteral(t.data,toPos(t),t.data));
|
||||
} else {
|
||||
}
|
||||
else if (peekIdentifierToken("true")) {
|
||||
push(new BooleanLiteral(t.data, toPos(t), true));
|
||||
}
|
||||
else if (peekIdentifierToken("false")) {
|
||||
push(new BooleanLiteral(t.data, toPos(t), false));
|
||||
}
|
||||
else if (t.kind == TokenKind.LITERAL_STRING) {
|
||||
push(new StringLiteral(t.data, toPos(t), t.data));
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
nextToken();
|
||||
|
|
@ -717,7 +773,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
eatToken(TokenKind.RPAREN);
|
||||
push(expr);
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -737,9 +794,11 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
String idString = t.stringValue();
|
||||
if (idString.equalsIgnoreCase("instanceof")) {
|
||||
return t.asInstanceOfToken();
|
||||
} else if (idString.equalsIgnoreCase("matches")) {
|
||||
}
|
||||
if (idString.equalsIgnoreCase("matches")) {
|
||||
return t.asMatchesToken();
|
||||
} else if (idString.equalsIgnoreCase("between")) {
|
||||
}
|
||||
if (idString.equalsIgnoreCase("between")) {
|
||||
return t.asBetweenToken();
|
||||
}
|
||||
}
|
||||
|
|
@ -749,7 +808,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
private Token eatToken(TokenKind expectedKind) {
|
||||
Token t = nextToken();
|
||||
if (t==null) {
|
||||
raiseInternalException( expressionString.length(), SpelMessage.OOD);
|
||||
raiseInternalException( this.expressionString.length(), SpelMessage.OOD);
|
||||
}
|
||||
if (t.kind!=expectedKind) {
|
||||
raiseInternalException(t.startpos,SpelMessage.NOT_EXPECTED_TOKEN, expectedKind.toString().toLowerCase(),t.getKind().toString().toLowerCase());
|
||||
|
|
@ -768,32 +827,36 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
Token t = peekToken();
|
||||
if (t.kind==desiredTokenKind) {
|
||||
if (consumeIfMatched) {
|
||||
tokenStreamPointer++;
|
||||
this.tokenStreamPointer++;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (desiredTokenKind == TokenKind.IDENTIFIER) {
|
||||
// might be one of the textual forms of the operators (e.g. NE for != ) - in which case we can treat it as an identifier
|
||||
// The list is represented here: Tokenizer.alternativeOperatorNames and those ones are in order in the TokenKind enum
|
||||
if (t.kind.ordinal()>=TokenKind.DIV.ordinal() && t.kind.ordinal()<=TokenKind.NOT.ordinal() && t.data!=null) {
|
||||
// if t.data were null, we'd know it wasn't the textual form, it was the symbol form
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (desiredTokenKind == TokenKind.IDENTIFIER) {
|
||||
// might be one of the textual forms of the operators (e.g. NE for != ) - in which case we can treat it as an identifier
|
||||
// The list is represented here: Tokenizer.alternativeOperatorNames and those ones are in order in the TokenKind enum
|
||||
if (t.kind.ordinal()>=TokenKind.DIV.ordinal() && t.kind.ordinal()<=TokenKind.NOT.ordinal() && t.data!=null) {
|
||||
// if t.data were null, we'd know it wasn't the textual form, it was the symbol form
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean peekToken(TokenKind possible1,TokenKind possible2) {
|
||||
if (!moreTokens()) return false;
|
||||
if (!moreTokens()) {
|
||||
return false;
|
||||
}
|
||||
Token t = peekToken();
|
||||
return t.kind==possible1 || t.kind==possible2;
|
||||
return t.kind == possible1 || t.kind == possible2;
|
||||
}
|
||||
|
||||
private boolean peekToken(TokenKind possible1,TokenKind possible2, TokenKind possible3) {
|
||||
if (!moreTokens()) return false;
|
||||
if (!moreTokens()) {
|
||||
return false;
|
||||
}
|
||||
Token t = peekToken();
|
||||
return t.kind==possible1 || t.kind==possible2 || t.kind==possible3;
|
||||
return t.kind == possible1 || t.kind == possible2 || t.kind == possible3;
|
||||
}
|
||||
|
||||
private boolean peekIdentifierToken(String identifierString) {
|
||||
|
|
@ -805,39 +868,42 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
|
||||
private boolean peekSelectToken() {
|
||||
if (!moreTokens()) return false;
|
||||
if (!moreTokens()) {
|
||||
return false;
|
||||
}
|
||||
Token t = peekToken();
|
||||
return t.kind==TokenKind.SELECT || t.kind==TokenKind.SELECT_FIRST || t.kind==TokenKind.SELECT_LAST;
|
||||
return t.kind == TokenKind.SELECT || t.kind == TokenKind.SELECT_FIRST
|
||||
|| t.kind == TokenKind.SELECT_LAST;
|
||||
}
|
||||
|
||||
private boolean moreTokens() {
|
||||
return tokenStreamPointer<tokenStream.size();
|
||||
return this.tokenStreamPointer<this.tokenStream.size();
|
||||
}
|
||||
|
||||
private Token nextToken() {
|
||||
if (tokenStreamPointer>=tokenStreamLength) {
|
||||
if (this.tokenStreamPointer >= this.tokenStreamLength) {
|
||||
return null;
|
||||
}
|
||||
return tokenStream.get(tokenStreamPointer++);
|
||||
return this.tokenStream.get(this.tokenStreamPointer++);
|
||||
}
|
||||
|
||||
private Token peekToken() {
|
||||
if (tokenStreamPointer>=tokenStreamLength) {
|
||||
if (this.tokenStreamPointer >= this.tokenStreamLength) {
|
||||
return null;
|
||||
}
|
||||
return tokenStream.get(tokenStreamPointer);
|
||||
return this.tokenStream.get(this.tokenStreamPointer);
|
||||
}
|
||||
|
||||
private void raiseInternalException(int pos, SpelMessage message,Object... inserts) {
|
||||
throw new InternalParseException(new SpelParseException(expressionString,pos,message,inserts));
|
||||
private void raiseInternalException(int pos, SpelMessage message, Object... inserts) {
|
||||
throw new InternalParseException(new SpelParseException(this.expressionString,
|
||||
pos, message, inserts));
|
||||
}
|
||||
|
||||
public String toString(Token t) {
|
||||
if (t.getKind().hasPayload()) {
|
||||
return t.stringValue();
|
||||
} else {
|
||||
return t.kind.toString().toLowerCase();
|
||||
}
|
||||
return t.kind.toString().toLowerCase();
|
||||
}
|
||||
|
||||
private void checkOperands(Token token, SpelNodeImpl left, SpelNodeImpl right) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -30,10 +30,10 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
|||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@code SpelExpression} represents a parsed (valid) expression that is ready
|
||||
* to be evaluated in a specified context. An expression can be evaluated
|
||||
* standalone or in a specified context. During expression evaluation the context
|
||||
* may be asked to resolve references to types, beans, properties, and methods.
|
||||
* A {@code SpelExpression} represents a parsed (valid) expression that is ready to be
|
||||
* evaluated in a specified context. An expression can be evaluated standalone or in a
|
||||
* specified context. During expression evaluation the context may be asked to resolve
|
||||
* references to types, beans, properties, and methods.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -64,51 +64,51 @@ public class SpelExpression implements Expression {
|
|||
|
||||
@Override
|
||||
public Object getValue() throws EvaluationException {
|
||||
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), configuration);
|
||||
return ast.getValue(expressionState);
|
||||
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration);
|
||||
return this.ast.getValue(expressionState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(Object rootObject) throws EvaluationException {
|
||||
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), configuration);
|
||||
return ast.getValue(expressionState);
|
||||
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration);
|
||||
return this.ast.getValue(expressionState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValue(Class<T> expectedResultType) throws EvaluationException {
|
||||
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), configuration);
|
||||
TypedValue typedResultValue = ast.getTypedValue(expressionState);
|
||||
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration);
|
||||
TypedValue typedResultValue = this.ast.getTypedValue(expressionState);
|
||||
return ExpressionUtils.convertTypedValue(expressionState.getEvaluationContext(), typedResultValue, expectedResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValue(Object rootObject, Class<T> expectedResultType) throws EvaluationException {
|
||||
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), configuration);
|
||||
TypedValue typedResultValue = ast.getTypedValue(expressionState);
|
||||
ExpressionState expressionState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration);
|
||||
TypedValue typedResultValue = this.ast.getTypedValue(expressionState);
|
||||
return ExpressionUtils.convertTypedValue(expressionState.getEvaluationContext(), typedResultValue, expectedResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(EvaluationContext context) throws EvaluationException {
|
||||
Assert.notNull(context, "The EvaluationContext is required");
|
||||
return ast.getValue(new ExpressionState(context, configuration));
|
||||
return this.ast.getValue(new ExpressionState(context, this.configuration));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException {
|
||||
Assert.notNull(context, "The EvaluationContext is required");
|
||||
return ast.getValue(new ExpressionState(context, toTypedValue(rootObject), configuration));
|
||||
return this.ast.getValue(new ExpressionState(context, toTypedValue(rootObject), this.configuration));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValue(EvaluationContext context, Class<T> expectedResultType) throws EvaluationException {
|
||||
TypedValue typedResultValue = ast.getTypedValue(new ExpressionState(context, configuration));
|
||||
TypedValue typedResultValue = this.ast.getTypedValue(new ExpressionState(context, this.configuration));
|
||||
return ExpressionUtils.convertTypedValue(context, typedResultValue, expectedResultType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getValue(EvaluationContext context, Object rootObject, Class<T> expectedResultType) throws EvaluationException {
|
||||
TypedValue typedResultValue = ast.getTypedValue(new ExpressionState(context, toTypedValue(rootObject), configuration));
|
||||
TypedValue typedResultValue = this.ast.getTypedValue(new ExpressionState(context, toTypedValue(rootObject), this.configuration));
|
||||
return ExpressionUtils.convertTypedValue(context, typedResultValue, expectedResultType);
|
||||
}
|
||||
|
||||
|
|
@ -125,15 +125,15 @@ public class SpelExpression implements Expression {
|
|||
@Override
|
||||
public Class<?> getValueType(EvaluationContext context) throws EvaluationException {
|
||||
Assert.notNull(context, "The EvaluationContext is required");
|
||||
ExpressionState eState = new ExpressionState(context, configuration);
|
||||
TypeDescriptor typeDescriptor = ast.getValueInternal(eState).getTypeDescriptor();
|
||||
ExpressionState eState = new ExpressionState(context, this.configuration);
|
||||
TypeDescriptor typeDescriptor = this.ast.getValueInternal(eState).getTypeDescriptor();
|
||||
return typeDescriptor != null ? typeDescriptor.getType() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException {
|
||||
ExpressionState eState = new ExpressionState(context, toTypedValue(rootObject), configuration);
|
||||
TypeDescriptor typeDescriptor = ast.getValueInternal(eState).getTypeDescriptor();
|
||||
ExpressionState eState = new ExpressionState(context, toTypedValue(rootObject), this.configuration);
|
||||
TypeDescriptor typeDescriptor = this.ast.getValueInternal(eState).getTypeDescriptor();
|
||||
return typeDescriptor != null ? typeDescriptor.getType() : null;
|
||||
}
|
||||
|
||||
|
|
@ -144,61 +144,61 @@ public class SpelExpression implements Expression {
|
|||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException {
|
||||
ExpressionState eState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), configuration);
|
||||
return ast.getValueInternal(eState).getTypeDescriptor();
|
||||
ExpressionState eState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration);
|
||||
return this.ast.getValueInternal(eState).getTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
|
||||
Assert.notNull(context, "The EvaluationContext is required");
|
||||
ExpressionState eState = new ExpressionState(context, configuration);
|
||||
return ast.getValueInternal(eState).getTypeDescriptor();
|
||||
ExpressionState eState = new ExpressionState(context, this.configuration);
|
||||
return this.ast.getValueInternal(eState).getTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException {
|
||||
Assert.notNull(context, "The EvaluationContext is required");
|
||||
ExpressionState eState = new ExpressionState(context, toTypedValue(rootObject), configuration);
|
||||
return ast.getValueInternal(eState).getTypeDescriptor();
|
||||
ExpressionState eState = new ExpressionState(context, toTypedValue(rootObject), this.configuration);
|
||||
return this.ast.getValueInternal(eState).getTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExpressionString() {
|
||||
return expression;
|
||||
return this.expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(EvaluationContext context) throws EvaluationException {
|
||||
Assert.notNull(context, "The EvaluationContext is required");
|
||||
return ast.isWritable(new ExpressionState(context, configuration));
|
||||
return this.ast.isWritable(new ExpressionState(context, this.configuration));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(Object rootObject) throws EvaluationException {
|
||||
return ast.isWritable(new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), configuration));
|
||||
return this.ast.isWritable(new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException {
|
||||
Assert.notNull(context, "The EvaluationContext is required");
|
||||
return ast.isWritable(new ExpressionState(context, toTypedValue(rootObject), configuration));
|
||||
return this.ast.isWritable(new ExpressionState(context, toTypedValue(rootObject), this.configuration));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EvaluationContext context, Object value) throws EvaluationException {
|
||||
Assert.notNull(context, "The EvaluationContext is required");
|
||||
ast.setValue(new ExpressionState(context, configuration), value);
|
||||
this.ast.setValue(new ExpressionState(context, this.configuration), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object rootObject, Object value) throws EvaluationException {
|
||||
ast.setValue(new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), configuration), value);
|
||||
this.ast.setValue(new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException {
|
||||
Assert.notNull(context, "The EvaluationContext is required");
|
||||
ast.setValue(new ExpressionState(context, toTypedValue(rootObject), configuration), value);
|
||||
this.ast.setValue(new ExpressionState(context, toTypedValue(rootObject), this.configuration), value);
|
||||
}
|
||||
|
||||
// impl only
|
||||
|
|
@ -207,7 +207,7 @@ public class SpelExpression implements Expression {
|
|||
* @return return the Abstract Syntax Tree for the expression
|
||||
*/
|
||||
public SpelNode getAST() {
|
||||
return ast;
|
||||
return this.ast;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -217,7 +217,7 @@ public class SpelExpression implements Expression {
|
|||
* @return the string representation of the AST
|
||||
*/
|
||||
public String toStringAST() {
|
||||
return ast.toStringAST();
|
||||
return this.ast.toStringAST();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -225,10 +225,10 @@ public class SpelExpression implements Expression {
|
|||
* @return the default evaluation context
|
||||
*/
|
||||
public EvaluationContext getEvaluationContext() {
|
||||
if (defaultContext == null) {
|
||||
defaultContext = new StandardEvaluationContext();
|
||||
if (this.defaultContext == null) {
|
||||
this.defaultContext = new StandardEvaluationContext();
|
||||
}
|
||||
return defaultContext;
|
||||
return this.defaultContext;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,7 +17,8 @@
|
|||
package org.springframework.expression.spel.standard;
|
||||
|
||||
/**
|
||||
* Holder for a kind of token, the associated data and its position in the input data stream (start/end).
|
||||
* Holder for a kind of token, the associated data and its position in the input data
|
||||
* stream (start/end).
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
|
|
@ -25,12 +26,17 @@ package org.springframework.expression.spel.standard;
|
|||
class Token {
|
||||
|
||||
TokenKind kind;
|
||||
|
||||
String data;
|
||||
|
||||
int startpos; // index of first character
|
||||
|
||||
int endpos; // index of char after the last character
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for use when there is no particular data for the token (eg. TRUE or '+')
|
||||
* Constructor for use when there is no particular data for the token (eg. TRUE or
|
||||
* '+')
|
||||
* @param startpos the exact start
|
||||
* @param endpos the index to the last character
|
||||
*/
|
||||
|
|
@ -47,42 +53,42 @@ class Token {
|
|||
|
||||
|
||||
public TokenKind getKind() {
|
||||
return kind;
|
||||
return this.kind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("[").append(kind.toString());
|
||||
if (kind.hasPayload()) {
|
||||
s.append(":").append(data);
|
||||
s.append("[").append(this.kind.toString());
|
||||
if (this.kind.hasPayload()) {
|
||||
s.append(":").append(this.data);
|
||||
}
|
||||
s.append("]");
|
||||
s.append("(").append(startpos).append(",").append(endpos).append(")");
|
||||
s.append("(").append(this.startpos).append(",").append(this.endpos).append(")");
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public boolean isIdentifier() {
|
||||
return kind==TokenKind.IDENTIFIER;
|
||||
return this.kind==TokenKind.IDENTIFIER;
|
||||
}
|
||||
|
||||
public boolean isNumericRelationalOperator() {
|
||||
return kind==TokenKind.GT || kind==TokenKind.GE || kind==TokenKind.LT || kind==TokenKind.LE || kind==TokenKind.EQ || kind==TokenKind.NE;
|
||||
return this.kind==TokenKind.GT || this.kind==TokenKind.GE || this.kind==TokenKind.LT || this.kind==TokenKind.LE || this.kind==TokenKind.EQ || this.kind==TokenKind.NE;
|
||||
}
|
||||
|
||||
public String stringValue() {
|
||||
return data;
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public Token asInstanceOfToken() {
|
||||
return new Token(TokenKind.INSTANCEOF,startpos,endpos);
|
||||
return new Token(TokenKind.INSTANCEOF,this.startpos,this.endpos);
|
||||
}
|
||||
|
||||
public Token asMatchesToken() {
|
||||
return new Token(TokenKind.MATCHES,startpos,endpos);
|
||||
return new Token(TokenKind.MATCHES,this.startpos,this.endpos);
|
||||
}
|
||||
|
||||
public Token asBetweenToken() {
|
||||
return new Token(TokenKind.BETWEEN,startpos,endpos);
|
||||
return new Token(TokenKind.BETWEEN,this.startpos,this.endpos);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -17,44 +17,135 @@
|
|||
package org.springframework.expression.spel.standard;
|
||||
|
||||
/**
|
||||
* Token Kinds.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
enum TokenKind {
|
||||
|
||||
// ordered by priority - operands first
|
||||
LITERAL_INT, LITERAL_LONG, LITERAL_HEXINT, LITERAL_HEXLONG, LITERAL_STRING, LITERAL_REAL, LITERAL_REAL_FLOAT,
|
||||
LPAREN("("), RPAREN(")"), COMMA(","), IDENTIFIER,
|
||||
COLON(":"),HASH("#"),RSQUARE("]"), LSQUARE("["),
|
||||
LCURLY("{"),RCURLY("}"),
|
||||
DOT("."), PLUS("+"), STAR("*"), MINUS("-"), SELECT_FIRST("^["), SELECT_LAST("$["), QMARK("?"), PROJECT("!["),
|
||||
DIV("/"), GE(">="), GT(">"), LE("<="), LT("<"), EQ("=="), NE("!="),
|
||||
MOD("%"), NOT("!"), ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"),
|
||||
SELECT("?["), POWER("^"),
|
||||
ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@"), SYMBOLIC_OR("||"), SYMBOLIC_AND("&&"), INC("++"), DEC("--")
|
||||
;
|
||||
|
||||
LITERAL_INT,
|
||||
|
||||
LITERAL_LONG,
|
||||
|
||||
LITERAL_HEXINT,
|
||||
|
||||
LITERAL_HEXLONG,
|
||||
|
||||
LITERAL_STRING,
|
||||
|
||||
LITERAL_REAL,
|
||||
|
||||
LITERAL_REAL_FLOAT,
|
||||
|
||||
LPAREN("("),
|
||||
|
||||
RPAREN(")"),
|
||||
|
||||
COMMA(","),
|
||||
|
||||
IDENTIFIER,
|
||||
|
||||
COLON(":"),
|
||||
|
||||
HASH("#"),
|
||||
|
||||
RSQUARE("]"),
|
||||
|
||||
LSQUARE("["),
|
||||
|
||||
LCURLY("{"),
|
||||
|
||||
RCURLY("}"),
|
||||
|
||||
DOT("."),
|
||||
|
||||
PLUS("+"),
|
||||
|
||||
STAR("*"),
|
||||
|
||||
MINUS("-"),
|
||||
|
||||
SELECT_FIRST("^["),
|
||||
|
||||
SELECT_LAST("$["),
|
||||
|
||||
QMARK("?"),
|
||||
|
||||
PROJECT("!["),
|
||||
|
||||
DIV("/"),
|
||||
|
||||
GE(">="),
|
||||
|
||||
GT(">"),
|
||||
|
||||
LE("<="),
|
||||
|
||||
LT("<"),
|
||||
|
||||
EQ("=="),
|
||||
|
||||
NE("!="),
|
||||
|
||||
MOD("%"),
|
||||
|
||||
NOT("!"),
|
||||
|
||||
ASSIGN("="),
|
||||
|
||||
INSTANCEOF("instanceof"),
|
||||
|
||||
MATCHES("matches"),
|
||||
|
||||
BETWEEN("between"),
|
||||
|
||||
SELECT("?["),
|
||||
|
||||
POWER("^"),
|
||||
|
||||
ELVIS("?:"),
|
||||
|
||||
SAFE_NAVI("?."),
|
||||
|
||||
BEAN_REF("@"),
|
||||
|
||||
SYMBOLIC_OR("||"),
|
||||
|
||||
SYMBOLIC_AND("&&"),
|
||||
|
||||
INC("++"),
|
||||
|
||||
DEC("--");
|
||||
|
||||
|
||||
char[] tokenChars;
|
||||
|
||||
private boolean hasPayload; // is there more to this token than simply the kind
|
||||
|
||||
|
||||
private TokenKind(String tokenString) {
|
||||
tokenChars = tokenString.toCharArray();
|
||||
hasPayload = tokenChars.length==0;
|
||||
this.tokenChars = tokenString.toCharArray();
|
||||
this.hasPayload = this.tokenChars.length==0;
|
||||
}
|
||||
|
||||
private TokenKind() {
|
||||
this("");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name()+(tokenChars.length!=0?"("+new String(tokenChars)+")":"");
|
||||
return this.name()+(this.tokenChars.length!=0?"("+new String(this.tokenChars)+")":"");
|
||||
}
|
||||
|
||||
public boolean hasPayload() {
|
||||
return hasPayload;
|
||||
return this.hasPayload;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return tokenChars.length;
|
||||
return this.tokenChars.length;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,276 +34,337 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
class Tokenizer {
|
||||
|
||||
// if this is changed, it must remain sorted
|
||||
private static final String[] ALTERNATIVE_OPERATOR_NAMES = { "DIV", "EQ", "GE", "GT",
|
||||
"LE", "LT", "MOD", "NE", "NOT" };
|
||||
|
||||
private static final byte FLAGS[] = new byte[256];
|
||||
|
||||
private static final byte IS_DIGIT = 0x01;
|
||||
|
||||
private static final byte IS_HEXDIGIT = 0x02;
|
||||
|
||||
private static final byte IS_ALPHA = 0x04;
|
||||
|
||||
static {
|
||||
for (int ch = '0'; ch <= '9'; ch++) {
|
||||
FLAGS[ch] |= IS_DIGIT | IS_HEXDIGIT;
|
||||
}
|
||||
for (int ch = 'A'; ch <= 'F'; ch++) {
|
||||
FLAGS[ch] |= IS_HEXDIGIT;
|
||||
}
|
||||
for (int ch = 'a'; ch <= 'f'; ch++) {
|
||||
FLAGS[ch] |= IS_HEXDIGIT;
|
||||
}
|
||||
for (int ch = 'A'; ch <= 'Z'; ch++) {
|
||||
FLAGS[ch] |= IS_ALPHA;
|
||||
}
|
||||
for (int ch = 'a'; ch <= 'z'; ch++) {
|
||||
FLAGS[ch] |= IS_ALPHA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String expressionString;
|
||||
|
||||
char[] toProcess;
|
||||
|
||||
int pos;
|
||||
|
||||
int max;
|
||||
|
||||
List<Token> tokens = new ArrayList<Token>();
|
||||
|
||||
|
||||
public Tokenizer(String inputdata) {
|
||||
this.expressionString = inputdata;
|
||||
this.toProcess = (inputdata+"\0").toCharArray();
|
||||
this.max = toProcess.length;
|
||||
this.toProcess = (inputdata + "\0").toCharArray();
|
||||
this.max = this.toProcess.length;
|
||||
this.pos = 0;
|
||||
process();
|
||||
}
|
||||
|
||||
|
||||
public void process() {
|
||||
while (pos<max) {
|
||||
char ch = toProcess[pos];
|
||||
while (this.pos < this.max) {
|
||||
char ch = this.toProcess[this.pos];
|
||||
if (isAlphabetic(ch)) {
|
||||
lexIdentifier();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
switch (ch) {
|
||||
case '+':
|
||||
if (isTwoCharToken(TokenKind.INC)) {
|
||||
pushPairToken(TokenKind.INC);
|
||||
} else {
|
||||
pushCharToken(TokenKind.PLUS);
|
||||
}
|
||||
break;
|
||||
case '_': // the other way to start an identifier
|
||||
lexIdentifier();
|
||||
break;
|
||||
case '-':
|
||||
if (isTwoCharToken(TokenKind.DEC)) {
|
||||
pushPairToken(TokenKind.DEC);
|
||||
} else {
|
||||
pushCharToken(TokenKind.MINUS);
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
pushCharToken(TokenKind.COLON);
|
||||
break;
|
||||
case '.':
|
||||
pushCharToken(TokenKind.DOT);
|
||||
break;
|
||||
case ',':
|
||||
pushCharToken(TokenKind.COMMA);
|
||||
break;
|
||||
case '*':
|
||||
pushCharToken(TokenKind.STAR);
|
||||
break;
|
||||
case '/':
|
||||
pushCharToken(TokenKind.DIV);
|
||||
break;
|
||||
case '%':
|
||||
pushCharToken(TokenKind.MOD);
|
||||
break;
|
||||
case '(':
|
||||
pushCharToken(TokenKind.LPAREN);
|
||||
break;
|
||||
case ')':
|
||||
pushCharToken(TokenKind.RPAREN);
|
||||
break;
|
||||
case '[':
|
||||
pushCharToken(TokenKind.LSQUARE);
|
||||
break;
|
||||
case '#':
|
||||
pushCharToken(TokenKind.HASH);
|
||||
break;
|
||||
case ']':
|
||||
pushCharToken(TokenKind.RSQUARE);
|
||||
break;
|
||||
case '{':
|
||||
pushCharToken(TokenKind.LCURLY);
|
||||
break;
|
||||
case '}':
|
||||
pushCharToken(TokenKind.RCURLY);
|
||||
break;
|
||||
case '@':
|
||||
pushCharToken(TokenKind.BEAN_REF);
|
||||
break;
|
||||
case '^':
|
||||
if (isTwoCharToken(TokenKind.SELECT_FIRST)) {
|
||||
pushPairToken(TokenKind.SELECT_FIRST);
|
||||
} else {
|
||||
pushCharToken(TokenKind.POWER);
|
||||
}
|
||||
break;
|
||||
case '!':
|
||||
if (isTwoCharToken(TokenKind.NE)) {
|
||||
pushPairToken(TokenKind.NE);
|
||||
} else if (isTwoCharToken(TokenKind.PROJECT)) {
|
||||
pushPairToken(TokenKind.PROJECT);
|
||||
} else {
|
||||
pushCharToken(TokenKind.NOT);
|
||||
}
|
||||
break;
|
||||
case '=':
|
||||
if (isTwoCharToken(TokenKind.EQ)) {
|
||||
pushPairToken(TokenKind.EQ);
|
||||
} else {
|
||||
pushCharToken(TokenKind.ASSIGN);
|
||||
}
|
||||
break;
|
||||
case '&':
|
||||
if (!isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
|
||||
throw new InternalParseException(new SpelParseException(
|
||||
expressionString, pos,
|
||||
SpelMessage.MISSING_CHARACTER, "&"));
|
||||
}
|
||||
pushPairToken(TokenKind.SYMBOLIC_AND);
|
||||
break;
|
||||
case '|':
|
||||
if (!isTwoCharToken(TokenKind.SYMBOLIC_OR)) {
|
||||
throw new InternalParseException(new SpelParseException(
|
||||
expressionString, pos,
|
||||
SpelMessage.MISSING_CHARACTER, "|"));
|
||||
}
|
||||
pushPairToken(TokenKind.SYMBOLIC_OR);
|
||||
break;
|
||||
case '?':
|
||||
if (isTwoCharToken(TokenKind.SELECT)) {
|
||||
pushPairToken(TokenKind.SELECT);
|
||||
} else if (isTwoCharToken(TokenKind.ELVIS)) {
|
||||
pushPairToken(TokenKind.ELVIS);
|
||||
} else if (isTwoCharToken(TokenKind.SAFE_NAVI)) {
|
||||
pushPairToken(TokenKind.SAFE_NAVI);
|
||||
} else {
|
||||
pushCharToken(TokenKind.QMARK);
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
if (isTwoCharToken(TokenKind.SELECT_LAST)) {
|
||||
pushPairToken(TokenKind.SELECT_LAST);
|
||||
} else {
|
||||
case '+':
|
||||
if (isTwoCharToken(TokenKind.INC)) {
|
||||
pushPairToken(TokenKind.INC);
|
||||
}
|
||||
else {
|
||||
pushCharToken(TokenKind.PLUS);
|
||||
}
|
||||
break;
|
||||
case '_': // the other way to start an identifier
|
||||
lexIdentifier();
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if (isTwoCharToken(TokenKind.GE)) {
|
||||
pushPairToken(TokenKind.GE);
|
||||
} else {
|
||||
pushCharToken(TokenKind.GT);
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
if (isTwoCharToken(TokenKind.LE)) {
|
||||
pushPairToken(TokenKind.LE);
|
||||
} else {
|
||||
pushCharToken(TokenKind.LT);
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
lexNumericLiteral(ch=='0');
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
// drift over white space
|
||||
pos++;
|
||||
break;
|
||||
case '\'':
|
||||
lexQuotedStringLiteral();
|
||||
break;
|
||||
case '"':
|
||||
lexDoubleQuotedStringLiteral();
|
||||
break;
|
||||
case 0:
|
||||
// hit sentinel at end of value
|
||||
pos++; // will take us to the end
|
||||
break;
|
||||
case '\\':
|
||||
throw new InternalParseException(new SpelParseException(expressionString,pos,SpelMessage.UNEXPECTED_ESCAPE_CHAR));
|
||||
default:
|
||||
throw new IllegalStateException("Cannot handle ("+Integer.valueOf(ch)+") '"+ch+"'");
|
||||
break;
|
||||
case '-':
|
||||
if (isTwoCharToken(TokenKind.DEC)) {
|
||||
pushPairToken(TokenKind.DEC);
|
||||
}
|
||||
else {
|
||||
pushCharToken(TokenKind.MINUS);
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
pushCharToken(TokenKind.COLON);
|
||||
break;
|
||||
case '.':
|
||||
pushCharToken(TokenKind.DOT);
|
||||
break;
|
||||
case ',':
|
||||
pushCharToken(TokenKind.COMMA);
|
||||
break;
|
||||
case '*':
|
||||
pushCharToken(TokenKind.STAR);
|
||||
break;
|
||||
case '/':
|
||||
pushCharToken(TokenKind.DIV);
|
||||
break;
|
||||
case '%':
|
||||
pushCharToken(TokenKind.MOD);
|
||||
break;
|
||||
case '(':
|
||||
pushCharToken(TokenKind.LPAREN);
|
||||
break;
|
||||
case ')':
|
||||
pushCharToken(TokenKind.RPAREN);
|
||||
break;
|
||||
case '[':
|
||||
pushCharToken(TokenKind.LSQUARE);
|
||||
break;
|
||||
case '#':
|
||||
pushCharToken(TokenKind.HASH);
|
||||
break;
|
||||
case ']':
|
||||
pushCharToken(TokenKind.RSQUARE);
|
||||
break;
|
||||
case '{':
|
||||
pushCharToken(TokenKind.LCURLY);
|
||||
break;
|
||||
case '}':
|
||||
pushCharToken(TokenKind.RCURLY);
|
||||
break;
|
||||
case '@':
|
||||
pushCharToken(TokenKind.BEAN_REF);
|
||||
break;
|
||||
case '^':
|
||||
if (isTwoCharToken(TokenKind.SELECT_FIRST)) {
|
||||
pushPairToken(TokenKind.SELECT_FIRST);
|
||||
}
|
||||
else {
|
||||
pushCharToken(TokenKind.POWER);
|
||||
}
|
||||
break;
|
||||
case '!':
|
||||
if (isTwoCharToken(TokenKind.NE)) {
|
||||
pushPairToken(TokenKind.NE);
|
||||
}
|
||||
else if (isTwoCharToken(TokenKind.PROJECT)) {
|
||||
pushPairToken(TokenKind.PROJECT);
|
||||
}
|
||||
else {
|
||||
pushCharToken(TokenKind.NOT);
|
||||
}
|
||||
break;
|
||||
case '=':
|
||||
if (isTwoCharToken(TokenKind.EQ)) {
|
||||
pushPairToken(TokenKind.EQ);
|
||||
}
|
||||
else {
|
||||
pushCharToken(TokenKind.ASSIGN);
|
||||
}
|
||||
break;
|
||||
case '&':
|
||||
if (!isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
|
||||
throw new InternalParseException(new SpelParseException(
|
||||
this.expressionString, this.pos, SpelMessage.MISSING_CHARACTER,
|
||||
"&"));
|
||||
}
|
||||
pushPairToken(TokenKind.SYMBOLIC_AND);
|
||||
break;
|
||||
case '|':
|
||||
if (!isTwoCharToken(TokenKind.SYMBOLIC_OR)) {
|
||||
throw new InternalParseException(new SpelParseException(
|
||||
this.expressionString, this.pos, SpelMessage.MISSING_CHARACTER,
|
||||
"|"));
|
||||
}
|
||||
pushPairToken(TokenKind.SYMBOLIC_OR);
|
||||
break;
|
||||
case '?':
|
||||
if (isTwoCharToken(TokenKind.SELECT)) {
|
||||
pushPairToken(TokenKind.SELECT);
|
||||
}
|
||||
else if (isTwoCharToken(TokenKind.ELVIS)) {
|
||||
pushPairToken(TokenKind.ELVIS);
|
||||
}
|
||||
else if (isTwoCharToken(TokenKind.SAFE_NAVI)) {
|
||||
pushPairToken(TokenKind.SAFE_NAVI);
|
||||
}
|
||||
else {
|
||||
pushCharToken(TokenKind.QMARK);
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
if (isTwoCharToken(TokenKind.SELECT_LAST)) {
|
||||
pushPairToken(TokenKind.SELECT_LAST);
|
||||
}
|
||||
else {
|
||||
lexIdentifier();
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if (isTwoCharToken(TokenKind.GE)) {
|
||||
pushPairToken(TokenKind.GE);
|
||||
}
|
||||
else {
|
||||
pushCharToken(TokenKind.GT);
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
if (isTwoCharToken(TokenKind.LE)) {
|
||||
pushPairToken(TokenKind.LE);
|
||||
}
|
||||
else {
|
||||
pushCharToken(TokenKind.LT);
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
lexNumericLiteral(ch == '0');
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
// drift over white space
|
||||
this.pos++;
|
||||
break;
|
||||
case '\'':
|
||||
lexQuotedStringLiteral();
|
||||
break;
|
||||
case '"':
|
||||
lexDoubleQuotedStringLiteral();
|
||||
break;
|
||||
case 0:
|
||||
// hit sentinel at end of value
|
||||
this.pos++; // will take us to the end
|
||||
break;
|
||||
case '\\':
|
||||
throw new InternalParseException(
|
||||
new SpelParseException(this.expressionString, this.pos,
|
||||
SpelMessage.UNEXPECTED_ESCAPE_CHAR));
|
||||
default:
|
||||
throw new IllegalStateException("Cannot handle ("
|
||||
+ Integer.valueOf(ch) + ") '" + ch + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Token> getTokens() {
|
||||
return tokens;
|
||||
return this.tokens;
|
||||
}
|
||||
|
||||
// STRING_LITERAL: '\''! (APOS|~'\'')* '\''!;
|
||||
private void lexQuotedStringLiteral() {
|
||||
int start = pos;
|
||||
int start = this.pos;
|
||||
boolean terminated = false;
|
||||
while (!terminated) {
|
||||
pos++;
|
||||
char ch = toProcess[pos];
|
||||
if (ch=='\'') {
|
||||
this.pos++;
|
||||
char ch = this.toProcess[this.pos];
|
||||
if (ch == '\'') {
|
||||
// may not be the end if the char after is also a '
|
||||
if (toProcess[pos+1]=='\'') {
|
||||
pos++; // skip over that too, and continue
|
||||
} else {
|
||||
if (this.toProcess[this.pos + 1] == '\'') {
|
||||
this.pos++; // skip over that too, and continue
|
||||
}
|
||||
else {
|
||||
terminated = true;
|
||||
}
|
||||
}
|
||||
if (ch==0) {
|
||||
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NON_TERMINATING_QUOTED_STRING));
|
||||
if (ch == 0) {
|
||||
throw new InternalParseException(new SpelParseException(this.expressionString,
|
||||
start, SpelMessage.NON_TERMINATING_QUOTED_STRING));
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos));
|
||||
this.pos++;
|
||||
this.tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start, this.pos), start, this.pos));
|
||||
}
|
||||
|
||||
// DQ_STRING_LITERAL: '"'! (~'"')* '"'!;
|
||||
// DQ_STRING_LITERAL: '"'! (~'"')* '"'!;
|
||||
private void lexDoubleQuotedStringLiteral() {
|
||||
int start = pos;
|
||||
int start = this.pos;
|
||||
boolean terminated = false;
|
||||
while (!terminated) {
|
||||
pos++;
|
||||
char ch = toProcess[pos];
|
||||
if (ch=='"') {
|
||||
this.pos++;
|
||||
char ch = this.toProcess[this.pos];
|
||||
if (ch == '"') {
|
||||
// may not be the end if the char after is also a "
|
||||
if (toProcess[pos+1]=='"') {
|
||||
pos++; // skip over that too, and continue
|
||||
} else {
|
||||
if (this.toProcess[this.pos + 1] == '"') {
|
||||
this.pos++; // skip over that too, and continue
|
||||
}
|
||||
else {
|
||||
terminated = true;
|
||||
}
|
||||
}
|
||||
if (ch==0) {
|
||||
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING));
|
||||
if (ch == 0) {
|
||||
throw new InternalParseException(new SpelParseException(this.expressionString,
|
||||
start, SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING));
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos));
|
||||
this.pos++;
|
||||
this.tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start, this.pos), start, this.pos));
|
||||
}
|
||||
|
||||
// REAL_LITERAL :
|
||||
// ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
|
||||
// ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
|
||||
// ((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) |
|
||||
// ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX));
|
||||
// fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' );
|
||||
// fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f';
|
||||
//
|
||||
// fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ;
|
||||
// fragment SIGN : '+' | '-' ;
|
||||
// fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd';
|
||||
// INTEGER_LITERAL
|
||||
// : (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?;
|
||||
// REAL_LITERAL :
|
||||
// ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
|
||||
// ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
|
||||
// ((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) |
|
||||
// ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX));
|
||||
// fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' );
|
||||
// fragment HEX_DIGIT :
|
||||
// '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f';
|
||||
//
|
||||
// fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)*
|
||||
// (DECIMAL_DIGIT)+ ;
|
||||
// fragment SIGN : '+' | '-' ;
|
||||
// fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd';
|
||||
// INTEGER_LITERAL
|
||||
// : (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?;
|
||||
|
||||
private void lexNumericLiteral(boolean firstCharIsZero) {
|
||||
boolean isReal = false;
|
||||
int start = pos;
|
||||
char ch = toProcess[pos+1];
|
||||
boolean isHex = ch=='x' || ch=='X';
|
||||
int start = this.pos;
|
||||
char ch = this.toProcess[this.pos + 1];
|
||||
boolean isHex = ch == 'x' || ch == 'X';
|
||||
|
||||
// deal with hexadecimal
|
||||
if (firstCharIsZero && isHex) {
|
||||
pos=pos+1;
|
||||
this.pos = this.pos + 1;
|
||||
do {
|
||||
pos++;
|
||||
} while (isHexadecimalDigit(toProcess[pos]));
|
||||
if (isChar('L','l')) {
|
||||
pushHexIntToken(subarray(start+2,pos),true, start, pos);
|
||||
pos++;
|
||||
} else {
|
||||
pushHexIntToken(subarray(start+2,pos),false, start, pos);
|
||||
this.pos++;
|
||||
}
|
||||
while (isHexadecimalDigit(this.toProcess[this.pos]));
|
||||
if (isChar('L', 'l')) {
|
||||
pushHexIntToken(subarray(start + 2, this.pos), true, start, this.pos);
|
||||
this.pos++;
|
||||
}
|
||||
else {
|
||||
pushHexIntToken(subarray(start + 2, this.pos), false, start, this.pos);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -312,134 +373,150 @@ class Tokenizer {
|
|||
|
||||
// Consume first part of number
|
||||
do {
|
||||
pos++;
|
||||
} while (isDigit(toProcess[pos]));
|
||||
this.pos++;
|
||||
}
|
||||
while (isDigit(this.toProcess[this.pos]));
|
||||
|
||||
// a '.' indicates this number is a real
|
||||
ch = toProcess[pos];
|
||||
if (ch=='.') {
|
||||
ch = this.toProcess[this.pos];
|
||||
if (ch == '.') {
|
||||
isReal = true;
|
||||
int dotpos = pos;
|
||||
int dotpos = this.pos;
|
||||
// carry on consuming digits
|
||||
do {
|
||||
pos++;
|
||||
} while (isDigit(toProcess[pos]));
|
||||
if (pos == dotpos + 1) {
|
||||
this.pos++;
|
||||
}
|
||||
while (isDigit(this.toProcess[this.pos]));
|
||||
if (this.pos == dotpos + 1) {
|
||||
// the number is something like '3.'. It is really an int but may be
|
||||
// part of something like '3.toString()'. In this case process it as
|
||||
// an int and leave the dot as a separate token.
|
||||
pos = dotpos;
|
||||
pushIntToken(subarray(start, pos), false, start, pos);
|
||||
this.pos = dotpos;
|
||||
pushIntToken(subarray(start, this.pos), false, start, this.pos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int endOfNumber = pos;
|
||||
int endOfNumber = this.pos;
|
||||
|
||||
// Now there may or may not be an exponent
|
||||
|
||||
// is it a long ?
|
||||
if (isChar('L','l')) {
|
||||
if (isChar('L', 'l')) {
|
||||
if (isReal) { // 3.4L - not allowed
|
||||
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.REAL_CANNOT_BE_LONG));
|
||||
throw new InternalParseException(new SpelParseException(this.expressionString,
|
||||
start, SpelMessage.REAL_CANNOT_BE_LONG));
|
||||
}
|
||||
pushIntToken(subarray(start, endOfNumber), true, start, endOfNumber);
|
||||
pos++;
|
||||
} else if (isExponentChar(toProcess[pos])) {
|
||||
this.pos++;
|
||||
}
|
||||
else if (isExponentChar(this.toProcess[this.pos])) {
|
||||
isReal = true; // if it wasn't before, it is now
|
||||
pos++;
|
||||
char possibleSign = toProcess[pos];
|
||||
this.pos++;
|
||||
char possibleSign = this.toProcess[this.pos];
|
||||
if (isSign(possibleSign)) {
|
||||
pos++;
|
||||
this.pos++;
|
||||
}
|
||||
|
||||
// exponent digits
|
||||
do {
|
||||
pos++;
|
||||
} while (isDigit(toProcess[pos]));
|
||||
boolean isFloat = false;
|
||||
if (isFloatSuffix(toProcess[pos])) {
|
||||
isFloat = true;
|
||||
endOfNumber = ++pos;
|
||||
} else if (isDoubleSuffix(toProcess[pos])) {
|
||||
endOfNumber = ++pos;
|
||||
this.pos++;
|
||||
}
|
||||
pushRealToken(subarray(start,pos), isFloat, start, pos);
|
||||
} else {
|
||||
ch = toProcess[pos];
|
||||
while (isDigit(this.toProcess[this.pos]));
|
||||
boolean isFloat = false;
|
||||
if (isFloatSuffix(this.toProcess[this.pos])) {
|
||||
isFloat = true;
|
||||
endOfNumber = ++this.pos;
|
||||
}
|
||||
else if (isDoubleSuffix(this.toProcess[this.pos])) {
|
||||
endOfNumber = ++this.pos;
|
||||
}
|
||||
pushRealToken(subarray(start, this.pos), isFloat, start, this.pos);
|
||||
}
|
||||
else {
|
||||
ch = this.toProcess[this.pos];
|
||||
boolean isFloat = false;
|
||||
if (isFloatSuffix(ch)) {
|
||||
isReal = true;
|
||||
isFloat = true;
|
||||
endOfNumber = ++pos;
|
||||
} else if (isDoubleSuffix(ch)) {
|
||||
endOfNumber = ++this.pos;
|
||||
}
|
||||
else if (isDoubleSuffix(ch)) {
|
||||
isReal = true;
|
||||
endOfNumber = ++pos;
|
||||
endOfNumber = ++this.pos;
|
||||
}
|
||||
if (isReal) {
|
||||
pushRealToken(subarray(start,endOfNumber), isFloat, start, endOfNumber);
|
||||
} else {
|
||||
pushIntToken(subarray(start,endOfNumber), false, start, endOfNumber);
|
||||
pushRealToken(subarray(start, endOfNumber), isFloat, start, endOfNumber);
|
||||
}
|
||||
else {
|
||||
pushIntToken(subarray(start, endOfNumber), false, start, endOfNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if this is changed, it must remain sorted
|
||||
private static final String[] alternativeOperatorNames = { "DIV","EQ","GE","GT","LE","LT","MOD","NE","NOT"};
|
||||
|
||||
private void lexIdentifier() {
|
||||
int start = pos;
|
||||
int start = this.pos;
|
||||
do {
|
||||
pos++;
|
||||
} while (isIdentifier(toProcess[pos]));
|
||||
char[] subarray = subarray(start,pos);
|
||||
this.pos++;
|
||||
}
|
||||
while (isIdentifier(this.toProcess[this.pos]));
|
||||
char[] subarray = subarray(start, this.pos);
|
||||
|
||||
// Check if this is the alternative (textual) representation of an operator (see alternativeOperatorNames)
|
||||
if ((pos-start)==2 || (pos-start)==3) {
|
||||
// Check if this is the alternative (textual) representation of an operator (see
|
||||
// alternativeOperatorNames)
|
||||
if ((this.pos - start) == 2 || (this.pos - start) == 3) {
|
||||
String asString = new String(subarray).toUpperCase();
|
||||
int idx = Arrays.binarySearch(alternativeOperatorNames,asString);
|
||||
if (idx>=0) {
|
||||
pushOneCharOrTwoCharToken(TokenKind.valueOf(asString),start,subarray);
|
||||
int idx = Arrays.binarySearch(ALTERNATIVE_OPERATOR_NAMES, asString);
|
||||
if (idx >= 0) {
|
||||
pushOneCharOrTwoCharToken(TokenKind.valueOf(asString), start, subarray);
|
||||
return;
|
||||
}
|
||||
}
|
||||
tokens.add(new Token(TokenKind.IDENTIFIER,subarray,start,pos));
|
||||
this.tokens.add(new Token(TokenKind.IDENTIFIER, subarray, start, this.pos));
|
||||
}
|
||||
|
||||
private void pushIntToken(char[] data,boolean isLong, int start, int end) {
|
||||
private void pushIntToken(char[] data, boolean isLong, int start, int end) {
|
||||
if (isLong) {
|
||||
tokens.add(new Token(TokenKind.LITERAL_LONG,data, start, end));
|
||||
} else {
|
||||
tokens.add(new Token(TokenKind.LITERAL_INT,data, start, end));
|
||||
this.tokens.add(new Token(TokenKind.LITERAL_LONG, data, start, end));
|
||||
}
|
||||
else {
|
||||
this.tokens.add(new Token(TokenKind.LITERAL_INT, data, start, end));
|
||||
}
|
||||
}
|
||||
|
||||
private void pushHexIntToken(char[] data,boolean isLong, int start, int end) {
|
||||
if (data.length==0) {
|
||||
private void pushHexIntToken(char[] data, boolean isLong, int start, int end) {
|
||||
if (data.length == 0) {
|
||||
if (isLong) {
|
||||
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NOT_A_LONG,expressionString.substring(start,end+1)));
|
||||
} else {
|
||||
throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NOT_AN_INTEGER,expressionString.substring(start,end)));
|
||||
throw new InternalParseException(new SpelParseException(this.expressionString,
|
||||
start, SpelMessage.NOT_A_LONG, this.expressionString.substring(start,
|
||||
end + 1)));
|
||||
}
|
||||
else {
|
||||
throw new InternalParseException(new SpelParseException(this.expressionString,
|
||||
start, SpelMessage.NOT_AN_INTEGER, this.expressionString.substring(
|
||||
start, end)));
|
||||
}
|
||||
}
|
||||
if (isLong) {
|
||||
tokens.add(new Token(TokenKind.LITERAL_HEXLONG, data, start, end));
|
||||
} else {
|
||||
tokens.add(new Token(TokenKind.LITERAL_HEXINT, data, start, end));
|
||||
this.tokens.add(new Token(TokenKind.LITERAL_HEXLONG, data, start, end));
|
||||
}
|
||||
else {
|
||||
this.tokens.add(new Token(TokenKind.LITERAL_HEXINT, data, start, end));
|
||||
}
|
||||
}
|
||||
|
||||
private void pushRealToken(char[] data, boolean isFloat, int start, int end) {
|
||||
if (isFloat) {
|
||||
tokens.add(new Token(TokenKind.LITERAL_REAL_FLOAT, data, start, end));
|
||||
} else {
|
||||
tokens.add(new Token(TokenKind.LITERAL_REAL, data, start, end));
|
||||
this.tokens.add(new Token(TokenKind.LITERAL_REAL_FLOAT, data, start, end));
|
||||
}
|
||||
else {
|
||||
this.tokens.add(new Token(TokenKind.LITERAL_REAL, data, start, end));
|
||||
}
|
||||
}
|
||||
|
||||
private char[] subarray(int start, int end) {
|
||||
char[] result = new char[end - start];
|
||||
System.arraycopy(toProcess, start, result, 0, end - start);
|
||||
System.arraycopy(this.toProcess, start, result, 0, end - start);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -448,98 +525,74 @@ class Tokenizer {
|
|||
*/
|
||||
private boolean isTwoCharToken(TokenKind kind) {
|
||||
Assert.isTrue(kind.tokenChars.length == 2);
|
||||
Assert.isTrue(toProcess[pos] == kind.tokenChars[0]);
|
||||
return toProcess[pos+1] == kind.tokenChars[1];
|
||||
Assert.isTrue(this.toProcess[this.pos] == kind.tokenChars[0]);
|
||||
return this.toProcess[this.pos + 1] == kind.tokenChars[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a token of just one character in length.
|
||||
*/
|
||||
private void pushCharToken(TokenKind kind) {
|
||||
tokens.add(new Token(kind,pos,pos+1));
|
||||
pos++;
|
||||
this.tokens.add(new Token(kind, this.pos, this.pos + 1));
|
||||
this.pos++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a token of two characters in length.
|
||||
*/
|
||||
private void pushPairToken(TokenKind kind) {
|
||||
tokens.add(new Token(kind,pos,pos+2));
|
||||
pos+=2;
|
||||
this.tokens.add(new Token(kind, this.pos, this.pos + 2));
|
||||
this.pos += 2;
|
||||
}
|
||||
|
||||
private void pushOneCharOrTwoCharToken(TokenKind kind, int pos, char[] data) {
|
||||
tokens.add(new Token(kind,data,pos,pos+kind.getLength()));
|
||||
this.tokens.add(new Token(kind, data, pos, pos + kind.getLength()));
|
||||
}
|
||||
|
||||
// ID: ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'$'|'0'..'9'|DOT_ESCAPED)*;
|
||||
// ID: ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'$'|'0'..'9'|DOT_ESCAPED)*;
|
||||
private boolean isIdentifier(char ch) {
|
||||
return isAlphabetic(ch) || isDigit(ch) || ch=='_' || ch=='$';
|
||||
return isAlphabetic(ch) || isDigit(ch) || ch == '_' || ch == '$';
|
||||
}
|
||||
|
||||
private boolean isChar(char a,char b) {
|
||||
char ch = toProcess[pos];
|
||||
return ch==a || ch==b;
|
||||
private boolean isChar(char a, char b) {
|
||||
char ch = this.toProcess[this.pos];
|
||||
return ch == a || ch == b;
|
||||
}
|
||||
|
||||
private boolean isExponentChar(char ch) {
|
||||
return ch=='e' || ch=='E';
|
||||
return ch == 'e' || ch == 'E';
|
||||
}
|
||||
|
||||
private boolean isFloatSuffix(char ch) {
|
||||
return ch=='f' || ch=='F';
|
||||
return ch == 'f' || ch == 'F';
|
||||
}
|
||||
|
||||
private boolean isDoubleSuffix(char ch) {
|
||||
return ch=='d' || ch=='D';
|
||||
return ch == 'd' || ch == 'D';
|
||||
}
|
||||
|
||||
private boolean isSign(char ch) {
|
||||
return ch=='+' || ch=='-';
|
||||
return ch == '+' || ch == '-';
|
||||
}
|
||||
|
||||
private boolean isDigit(char ch) {
|
||||
if (ch>255) {
|
||||
if (ch > 255) {
|
||||
return false;
|
||||
}
|
||||
return (flags[ch] & IS_DIGIT)!=0;
|
||||
return (FLAGS[ch] & IS_DIGIT) != 0;
|
||||
}
|
||||
|
||||
private boolean isAlphabetic(char ch) {
|
||||
if (ch>255) {
|
||||
if (ch > 255) {
|
||||
return false;
|
||||
}
|
||||
return (flags[ch] & IS_ALPHA)!=0;
|
||||
return (FLAGS[ch] & IS_ALPHA) != 0;
|
||||
}
|
||||
|
||||
private boolean isHexadecimalDigit(char ch) {
|
||||
if (ch>255) {
|
||||
if (ch > 255) {
|
||||
return false;
|
||||
}
|
||||
return (flags[ch] & IS_HEXDIGIT)!=0;
|
||||
return (FLAGS[ch] & IS_HEXDIGIT) != 0;
|
||||
}
|
||||
|
||||
private static final byte flags[] = new byte[256];
|
||||
private static final byte IS_DIGIT=0x01;
|
||||
private static final byte IS_HEXDIGIT=0x02;
|
||||
private static final byte IS_ALPHA=0x04;
|
||||
|
||||
static {
|
||||
for (int ch='0';ch<='9';ch++) {
|
||||
flags[ch]|=IS_DIGIT | IS_HEXDIGIT;
|
||||
}
|
||||
for (int ch='A';ch<='F';ch++) {
|
||||
flags[ch]|= IS_HEXDIGIT;
|
||||
}
|
||||
for (int ch='a';ch<='f';ch++) {
|
||||
flags[ch]|= IS_HEXDIGIT;
|
||||
}
|
||||
for (int ch='A';ch<='Z';ch++) {
|
||||
flags[ch]|= IS_ALPHA;
|
||||
}
|
||||
for (int ch='a';ch<='z';ch++) {
|
||||
flags[ch]|= IS_ALPHA;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -35,12 +35,7 @@ public class BooleanTypedValue extends TypedValue {
|
|||
|
||||
|
||||
public static BooleanTypedValue forValue(boolean b) {
|
||||
if (b) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
return (b ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -42,13 +42,15 @@ import org.springframework.util.MethodInvoker;
|
|||
public class ReflectionHelper {
|
||||
|
||||
/**
|
||||
* Compare argument arrays and return information about whether they match. A supplied type converter
|
||||
* and conversionAllowed flag allow for matches to take into account that a type may be transformed
|
||||
* into a different type by the converter.
|
||||
* Compare argument arrays and return information about whether they match. A supplied
|
||||
* type converter and conversionAllowed flag allow for matches to take into account
|
||||
* that a type may be transformed into a different type by the converter.
|
||||
* @param expectedArgTypes the array of types the method/constructor is expecting
|
||||
* @param suppliedArgTypes the array of types that are being supplied at the point of invocation
|
||||
* @param suppliedArgTypes the array of types that are being supplied at the point of
|
||||
* invocation
|
||||
* @param typeConverter a registered type converter
|
||||
* @return a MatchInfo object indicating what kind of match it was or null if it was not a match
|
||||
* @return a MatchInfo object indicating what kind of match it was or null if it was
|
||||
* not a match
|
||||
*/
|
||||
static ArgumentsMatchInfo compareArguments(
|
||||
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) {
|
||||
|
|
@ -199,6 +201,7 @@ public class ReflectionHelper {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If already confirmed it cannot be a match, then return
|
||||
if (match == null) {
|
||||
return null;
|
||||
|
|
@ -381,57 +384,74 @@ public class ReflectionHelper {
|
|||
// method the arguments should have been converted to the box form of the required type.
|
||||
Class<?> componentType = requiredParameterTypes[parameterCount-1].getComponentType();
|
||||
if (componentType.isPrimitive()) {
|
||||
if (componentType==Integer.TYPE) {
|
||||
int[] repackagedArguments = (int[]) Array.newInstance(componentType, arraySize);
|
||||
if (componentType == Integer.TYPE) {
|
||||
int[] repackagedArguments = (int[]) Array.newInstance(componentType,
|
||||
arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Integer)args[parameterCount + i - 1]).intValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
} else if(componentType==Float.TYPE) {
|
||||
float[] repackagedArguments = (float[]) Array.newInstance(componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Float)args[parameterCount + i - 1]).floatValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
} else if(componentType==Double.TYPE) {
|
||||
double[] repackagedArguments = (double[]) Array.newInstance(componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Double)args[parameterCount + i - 1]).doubleValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
} else if(componentType==Short.TYPE) {
|
||||
short[] repackagedArguments = (short[]) Array.newInstance(componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Short)args[parameterCount + i - 1]).shortValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
} else if(componentType==Character.TYPE) {
|
||||
char[] repackagedArguments = (char[]) Array.newInstance(componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Character)args[parameterCount + i - 1]).charValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
} else if(componentType==Byte.TYPE) {
|
||||
byte[] repackagedArguments = (byte[]) Array.newInstance(componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Byte)args[parameterCount + i - 1]).byteValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
} else if(componentType==Boolean.TYPE) {
|
||||
boolean[] repackagedArguments = (boolean[]) Array.newInstance(componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Boolean)args[parameterCount + i - 1]).booleanValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
} else if(componentType==Long.TYPE) {
|
||||
long[] repackagedArguments = (long[]) Array.newInstance(componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Long)args[parameterCount + i - 1]).longValue();
|
||||
repackagedArguments[i] = ((Integer) args[parameterCount + i - 1]).intValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
}
|
||||
} else {
|
||||
Object[] repackagedArguments = (Object[]) Array.newInstance(componentType, arraySize);
|
||||
else if (componentType == Float.TYPE) {
|
||||
float[] repackagedArguments = (float[]) Array.newInstance(
|
||||
componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Float) args[parameterCount + i - 1]).floatValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
}
|
||||
else if (componentType == Double.TYPE) {
|
||||
double[] repackagedArguments = (double[]) Array.newInstance(
|
||||
componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Double) args[parameterCount + i - 1]).doubleValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
}
|
||||
else if (componentType == Short.TYPE) {
|
||||
short[] repackagedArguments = (short[]) Array.newInstance(
|
||||
componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Short) args[parameterCount + i - 1]).shortValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
}
|
||||
else if (componentType == Character.TYPE) {
|
||||
char[] repackagedArguments = (char[]) Array.newInstance(
|
||||
componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Character) args[parameterCount + i - 1]).charValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
}
|
||||
else if (componentType == Byte.TYPE) {
|
||||
byte[] repackagedArguments = (byte[]) Array.newInstance(
|
||||
componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Byte) args[parameterCount + i - 1]).byteValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
}
|
||||
else if (componentType == Boolean.TYPE) {
|
||||
boolean[] repackagedArguments = (boolean[]) Array.newInstance(
|
||||
componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Boolean) args[parameterCount + i - 1]).booleanValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
}
|
||||
else if (componentType == Long.TYPE) {
|
||||
long[] repackagedArguments = (long[]) Array.newInstance(
|
||||
componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = ((Long) args[parameterCount + i - 1]).longValue();
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Object[] repackagedArguments = (Object[]) Array.newInstance(
|
||||
componentType, arraySize);
|
||||
// Copy all but the varargs arguments
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
repackagedArguments[i] = args[parameterCount + i - 1];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -25,7 +25,8 @@ import org.springframework.expression.TypedValue;
|
|||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A simple ConstructorExecutor implementation that runs a constructor using reflective invocation.
|
||||
* A simple ConstructorExecutor implementation that runs a constructor using reflective
|
||||
* invocation.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -32,7 +32,8 @@ import org.springframework.expression.EvaluationException;
|
|||
import org.springframework.expression.TypeConverter;
|
||||
|
||||
/**
|
||||
* A constructor resolver that uses reflection to locate the constructor that should be invoked
|
||||
* A constructor resolver that uses reflection to locate the constructor that should be
|
||||
* invoked
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -43,10 +44,12 @@ public class ReflectiveConstructorResolver implements ConstructorResolver {
|
|||
/**
|
||||
* Locate a constructor on the type. There are three kinds of match that might occur:
|
||||
* <ol>
|
||||
* <li>An exact match where the types of the arguments match the types of the constructor
|
||||
* <li>An in-exact match where the types we are looking for are subtypes of those defined on the constructor
|
||||
* <li>A match where we are able to convert the arguments into those expected by the constructor, according to the
|
||||
* registered type converter.
|
||||
* <li>An exact match where the types of the arguments match the types of the
|
||||
* constructor
|
||||
* <li>An in-exact match where the types we are looking for are subtypes of those
|
||||
* defined on the constructor
|
||||
* <li>A match where we are able to convert the arguments into those expected by the
|
||||
* constructor, according to the registered type converter.
|
||||
* </ol>
|
||||
*/
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ import org.springframework.expression.spel.SpelEvaluationException;
|
|||
import org.springframework.expression.spel.SpelMessage;
|
||||
|
||||
/**
|
||||
* Reflection-based {@link MethodResolver} used by default in {@link StandardEvaluationContext}
|
||||
* unless explicit method resolvers have been specified.
|
||||
* Reflection-based {@link MethodResolver} used by default in
|
||||
* {@link StandardEvaluationContext} unless explicit method resolvers have been specified.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -53,8 +53,6 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
*/
|
||||
public class ReflectiveMethodResolver implements MethodResolver {
|
||||
|
||||
private static Method[] NO_METHODS = new Method[0];
|
||||
|
||||
private Map<Class<?>, MethodFilter> filters = null;
|
||||
|
||||
// Using distance will ensure a more accurate match is discovered,
|
||||
|
|
@ -78,6 +76,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
|||
this.useDistance = useDistance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Locate a method on a type. There are three kinds of match that might occur:
|
||||
* <ol>
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ import org.springframework.util.ReflectionUtils;
|
|||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Simple PropertyAccessor that uses reflection to access properties for reading and writing.
|
||||
* A property can be accessed if it is accessible as a field on the object or through a
|
||||
* getter (if being read) or a setter (if being written).
|
||||
* Simple PropertyAccessor that uses reflection to access properties for reading and
|
||||
* writing. A property can be accessed if it is accessible as a field on the object or
|
||||
* through a getter (if being read) or a setter (if being written).
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -242,8 +242,8 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
*/
|
||||
public void registerMethodFilter(Class<?> type, MethodFilter filter) throws IllegalStateException {
|
||||
ensureMethodResolversInitialized();
|
||||
if (reflectiveMethodResolver != null) {
|
||||
reflectiveMethodResolver.registerMethodFilter(type, filter);
|
||||
if (this.reflectiveMethodResolver != null) {
|
||||
this.reflectiveMethodResolver.registerMethodFilter(type, filter);
|
||||
} else {
|
||||
throw new IllegalStateException("Method filter cannot be set as the reflective method resolver is not in use");
|
||||
}
|
||||
|
|
@ -272,7 +272,7 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
private synchronized void initializeMethodResolvers() {
|
||||
if (this.methodResolvers == null) {
|
||||
List<MethodResolver> defaultResolvers = new ArrayList<MethodResolver>();
|
||||
defaultResolvers.add(reflectiveMethodResolver = new ReflectiveMethodResolver());
|
||||
defaultResolvers.add(this.reflectiveMethodResolver = new ReflectiveMethodResolver());
|
||||
this.methodResolvers = defaultResolvers;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -21,7 +21,8 @@ import org.springframework.expression.spel.SpelEvaluationException;
|
|||
import org.springframework.expression.spel.SpelMessage;
|
||||
|
||||
/**
|
||||
* A simple basic TypeComparator implementation. It supports comparison of numbers and types implementing Comparable.
|
||||
* A simple basic TypeComparator implementation. It supports comparison of numbers and
|
||||
* types implementing Comparable.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -35,7 +36,8 @@ public class StandardTypeComparator implements TypeComparator {
|
|||
// If one is null, check if the other is
|
||||
if (left == null) {
|
||||
return right == null ? 0 : -1;
|
||||
} else if (right == null) {
|
||||
}
|
||||
else if (right == null) {
|
||||
return 1; // left cannot be null
|
||||
}
|
||||
|
||||
|
|
@ -46,20 +48,24 @@ public class StandardTypeComparator implements TypeComparator {
|
|||
if (leftNumber instanceof Double || rightNumber instanceof Double) {
|
||||
double d1 = leftNumber.doubleValue();
|
||||
double d2 = rightNumber.doubleValue();
|
||||
return Double.compare(d1,d2);
|
||||
} else if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
return Double.compare(d1, d2);
|
||||
}
|
||||
|
||||
if (leftNumber instanceof Float || rightNumber instanceof Float) {
|
||||
float f1 = leftNumber.floatValue();
|
||||
float f2 = rightNumber.floatValue();
|
||||
return Float.compare(f1,f2);
|
||||
} else if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
return Float.compare(f1, f2);
|
||||
}
|
||||
|
||||
if (leftNumber instanceof Long || rightNumber instanceof Long) {
|
||||
Long l1 = leftNumber.longValue();
|
||||
Long l2 = rightNumber.longValue();
|
||||
return l1.compareTo(l2);
|
||||
} else {
|
||||
Integer i1 = leftNumber.intValue();
|
||||
Integer i2 = rightNumber.intValue();
|
||||
return i1.compareTo(i2);
|
||||
}
|
||||
|
||||
Integer i1 = leftNumber.intValue();
|
||||
Integer i2 = rightNumber.intValue();
|
||||
return i1.compareTo(i2);
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -78,12 +84,15 @@ public class StandardTypeComparator implements TypeComparator {
|
|||
if (left == null || right == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (left instanceof Number && right instanceof Number) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (left instanceof Comparable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -27,8 +27,8 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link TypeConverter} interface,
|
||||
* delegating to a core Spring {@link ConversionService}.
|
||||
* Default implementation of the {@link TypeConverter} interface, delegating to a core
|
||||
* Spring {@link ConversionService}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Andy Clement
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
|
|
@ -27,8 +27,9 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A default implementation of a TypeLocator that uses the context classloader (or any classloader set upon it). It
|
||||
* supports 'well known' packages so if a type cannot be found it will try the registered imports to locate it.
|
||||
* A default implementation of a TypeLocator that uses the context classloader (or any
|
||||
* classloader set upon it). It supports 'well known' packages so if a type cannot be
|
||||
* found it will try the registered imports to locate it.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -36,7 +37,7 @@ import org.springframework.util.ClassUtils;
|
|||
*/
|
||||
public class StandardTypeLocator implements TypeLocator {
|
||||
|
||||
private ClassLoader loader;
|
||||
private final ClassLoader loader;
|
||||
|
||||
private final List<String> knownPackagePrefixes = new ArrayList<String>();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue