diff --git a/spring-expression/src/main/java/org/springframework/expression/ConstructorExecutor.java b/spring-expression/src/main/java/org/springframework/expression/ConstructorExecutor.java index bb04735237..71efb3039a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/ConstructorExecutor.java +++ b/spring-expression/src/main/java/org/springframework/expression/ConstructorExecutor.java @@ -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. + *

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; diff --git a/spring-expression/src/main/java/org/springframework/expression/ConstructorResolver.java b/spring-expression/src/main/java/org/springframework/expression/ConstructorResolver.java index e1892d86c0..d942978af9 100644 --- a/spring-expression/src/main/java/org/springframework/expression/ConstructorResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/ConstructorResolver.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/EvaluationContext.java b/spring-expression/src/main/java/org/springframework/expression/EvaluationContext.java index 27a83cab37..a4953fe06d 100644 --- a/spring-expression/src/main/java/org/springframework/expression/EvaluationContext.java +++ b/spring-expression/src/main/java/org/springframework/expression/EvaluationContext.java @@ -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. * *

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 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(); diff --git a/spring-expression/src/main/java/org/springframework/expression/Expression.java b/spring-expression/src/main/java/org/springframework/expression/Expression.java index fdad75b17f..b72a353d70 100644 --- a/spring-expression/src/main/java/org/springframework/expression/Expression.java +++ b/spring-expression/src/main/java/org/springframework/expression/Expression.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/ExpressionException.java b/spring-expression/src/main/java/org/springframework/expression/ExpressionException.java index ecea713cad..240c8053be 100644 --- a/spring-expression/src/main/java/org/springframework/expression/ExpressionException.java +++ b/spring-expression/src/main/java/org/springframework/expression/ExpressionException.java @@ -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; } } diff --git a/spring-expression/src/main/java/org/springframework/expression/ExpressionInvocationTargetException.java b/spring-expression/src/main/java/org/springframework/expression/ExpressionInvocationTargetException.java index a6b11fb26a..30a4e00843 100644 --- a/spring-expression/src/main/java/org/springframework/expression/ExpressionInvocationTargetException.java +++ b/spring-expression/src/main/java/org/springframework/expression/ExpressionInvocationTargetException.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/MethodExecutor.java b/spring-expression/src/main/java/org/springframework/expression/MethodExecutor.java index bd4dd74516..1506f98630 100644 --- a/spring-expression/src/main/java/org/springframework/expression/MethodExecutor.java +++ b/spring-expression/src/main/java/org/springframework/expression/MethodExecutor.java @@ -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. * - *

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. + *

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; diff --git a/spring-expression/src/main/java/org/springframework/expression/MethodFilter.java b/spring-expression/src/main/java/org/springframework/expression/MethodFilter.java index 50992dd798..d7c6e20cbd 100644 --- a/spring-expression/src/main/java/org/springframework/expression/MethodFilter.java +++ b/spring-expression/src/main/java/org/springframework/expression/MethodFilter.java @@ -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 */ diff --git a/spring-expression/src/main/java/org/springframework/expression/MethodResolver.java b/spring-expression/src/main/java/org/springframework/expression/MethodResolver.java index 75cdc5eab8..d3bdb78c96 100644 --- a/spring-expression/src/main/java/org/springframework/expression/MethodResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/MethodResolver.java @@ -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 argumentTypes) throws AccessException; diff --git a/spring-expression/src/main/java/org/springframework/expression/Operation.java b/spring-expression/src/main/java/org/springframework/expression/Operation.java index 01b805905b..f4b9673704 100644 --- a/spring-expression/src/main/java/org/springframework/expression/Operation.java +++ b/spring-expression/src/main/java/org/springframework/expression/Operation.java @@ -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 } diff --git a/spring-expression/src/main/java/org/springframework/expression/OperatorOverloader.java b/spring-expression/src/main/java/org/springframework/expression/OperatorOverloader.java index 29c165111b..7291575c9c 100644 --- a/spring-expression/src/main/java/org/springframework/expression/OperatorOverloader.java +++ b/spring-expression/src/main/java/org/springframework/expression/OperatorOverloader.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/ParserContext.java b/spring-expression/src/main/java/org/springframework/expression/ParserContext.java index 87a442c6b3..9617feb247 100644 --- a/spring-expression/src/main/java/org/springframework/expression/ParserContext.java +++ b/spring-expression/src/main/java/org/springframework/expression/ParserContext.java @@ -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: *

 	 * 	   Some literal text
 	 *     Hello #{name.firstName}!
 	 *     #{3 + 4}
 	 * 
- * * @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() { diff --git a/spring-expression/src/main/java/org/springframework/expression/PropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/PropertyAccessor.java index e14c30ba68..a8222c25ab 100644 --- a/spring-expression/src/main/java/org/springframework/expression/PropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/PropertyAccessor.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/TypeComparator.java b/spring-expression/src/main/java/org/springframework/expression/TypeComparator.java index 1dfb41adc7..c939fcab11 100644 --- a/spring-expression/src/main/java/org/springframework/expression/TypeComparator.java +++ b/spring-expression/src/main/java/org/springframework/expression/TypeComparator.java @@ -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; diff --git a/spring-expression/src/main/java/org/springframework/expression/TypeConverter.java b/spring-expression/src/main/java/org/springframework/expression/TypeConverter.java index e6145ab20e..bb7b26b386 100644 --- a/spring-expression/src/main/java/org/springframework/expression/TypeConverter.java +++ b/spring-expression/src/main/java/org/springframework/expression/TypeConverter.java @@ -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 */ diff --git a/spring-expression/src/main/java/org/springframework/expression/TypeLocator.java b/spring-expression/src/main/java/org/springframework/expression/TypeLocator.java index 4a22a82c19..7fade5cb7b 100644 --- a/spring-expression/src/main/java/org/springframework/expression/TypeLocator.java +++ b/spring-expression/src/main/java/org/springframework/expression/TypeLocator.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/TypedValue.java b/spring-expression/src/main/java/org/springframework/expression/TypedValue.java index 67ecb99ad2..12fb458293 100644 --- a/spring-expression/src/main/java/org/springframework/expression/TypedValue.java +++ b/spring-expression/src/main/java/org/springframework/expression/TypedValue.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java b/spring-expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java index a24a545479..1ddd5f9143 100644 --- a/spring-expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java @@ -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: + * *
- * "Hello ${getName()}"
- * - * 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()}" + * + * + * 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 getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException { Object value = getValue(context); - return ExpressionUtils.convert(context, value, expectedResultType); + return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType); } @Override public T getValue(Class 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 getValue(Object rootObject, Class desiredResultType) throws EvaluationException { Object value = getValue(rootObject); - return ExpressionUtils.convert(null, value, desiredResultType); + return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType); } @Override public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) throws EvaluationException { Object value = getValue(context,rootObject); - return ExpressionUtils.convert(context, value, desiredResultType); + return ExpressionUtils.convertTypedValue(context, new TypedValue(value), desiredResultType); } @Override diff --git a/spring-expression/src/main/java/org/springframework/expression/common/ExpressionUtils.java b/spring-expression/src/main/java/org/springframework/expression/common/ExpressionUtils.java index cc959c799e..696d1eedf9 100644 --- a/spring-expression/src/main/java/org/springframework/expression/common/ExpressionUtils.java +++ b/spring-expression/src/main/java/org/springframework/expression/common/ExpressionUtils.java @@ -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 convert(EvaluationContext context, Object value, Class 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 convertTypedValue(EvaluationContext context, TypedValue typedValue, Class targetType) { diff --git a/spring-expression/src/main/java/org/springframework/expression/common/LiteralExpression.java b/spring-expression/src/main/java/org/springframework/expression/common/LiteralExpression.java index ea6742ae07..c9b1878ff3 100644 --- a/spring-expression/src/main/java/org/springframework/expression/common/LiteralExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/common/LiteralExpression.java @@ -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 getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException { Object value = getValue(context); - return ExpressionUtils.convert(context, value, expectedResultType); + return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType); } @Override public T getValue(Class 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 getValue(Object rootObject, Class 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 getValue(EvaluationContext context, Object rootObject, Class 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"); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java b/spring-expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java index 82b6ab07bb..c74371e998 100644 --- a/spring-expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java +++ b/spring-expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java @@ -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 expressions = new LinkedList(); 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 stack = new Stack(); - while (posIt also acts as a place for to define common utility routines that the various Ast nodes might need. + *

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 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); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelEvaluationException.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelEvaluationException.java index 7c7a3f6f1c..80a604f690 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelEvaluationException.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelEvaluationException.java @@ -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; } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java index c6d95a9413..b61125af33 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java @@ -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. - *

- * 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. + * + *

When a message is formatted, it will have this kind of form * *

  * EL1004E: (pos 34): Type cannot be found 'String'
  * 
* - * 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(); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelNode.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelNode.java index 6e2ba93f3f..0699445702 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelNode.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelNode.java @@ -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); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParseException.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParseException.java index 1935b3ba61..2a623ddccc 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParseException.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParseException.java @@ -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; } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java index ccadb93061..20932fa9b2 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java @@ -30,7 +30,7 @@ public class SpelParserConfiguration { private final boolean autoGrowCollections; - private int maximumAutoGrowSize; + private final int maximumAutoGrowSize; /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Assign.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Assign.java index c472ed6393..7d2c045121 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Assign.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Assign.java @@ -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. * *

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(); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/AstUtils.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/AstUtils.java index 92eb3036fa..98cccc4985 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/AstUtils.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/AstUtils.java @@ -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 */ diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java index 35636fe806..b0be644e1f 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java @@ -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(); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java index 84878ee131..5aa748c8c0 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java @@ -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; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java index b632adec5e..688670c142 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java @@ -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(); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java index c6a25931fb..a16cc55788 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java @@ -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 argumentTypes, - ExpressionState state) throws SpelEvaluationException { + private ConstructorExecutor findExecutorForConstructor(String typename, + List argumentTypes, ExpressionState state) + throws SpelEvaluationException { EvaluationContext eContext = state.getEvaluationContext(); List 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; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java index b37548a5a2..7c44d0635c 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java @@ -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(); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FloatLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FloatLiteral.java index c63ee9a8ce..6d7be2b481 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FloatLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FloatLiteral.java @@ -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; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FormatHelper.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FormatHelper.java index 1d3b853e29..8719f49526 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FormatHelper.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FormatHelper.java @@ -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(); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java index db69a05945..642c4497ee 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java @@ -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. * - *

Functions are very simplistic, the arguments are not part of the definition (right now), - * so the names must be unique. + *

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; } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Identifier.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Identifier.java index e174535301..d258fbb993 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Identifier.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Identifier.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java index 4f919beec2..82e7db4259 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java @@ -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 accessorsToTry = - AstUtils.getPropertyAccessorsToTry(targetObjectRuntimeClass, eContext.getPropertyAccessors()); + + List 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 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(); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java index 1839d203c4..cae9002f40 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java @@ -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 returnValue = new ArrayList(); 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 getConstantValue() { - return (List) constant.getValue(); + return (List) this.constant.getValue(); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java index cafbd17d28..a648144901 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java @@ -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; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/LongLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/LongLiteral.java index 3d69e3fa10..3404411dbb 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/LongLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/LongLiteral.java @@ -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; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java index 26c5179005..e01e1e1403 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java @@ -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 argumentTypes, ExpressionState state) + private MethodExecutor findAccessorForMethod(String name, + List 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 argumentTypes, Object contextObject, EvaluationContext eContext) throws SpelEvaluationException { - List mResolvers = eContext.getMethodResolvers(); - if (mResolvers != null) { - for (MethodResolver methodResolver : mResolvers) { + List 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()); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java index 7ec4c6105a..5f7beb80f8 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java @@ -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; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpAnd.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpAnd.java index b2140d11e0..c6c69df23f 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpAnd.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpAnd.java @@ -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; } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDec.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDec.java index 7536ddfa2a..0a5a1236d7 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDec.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDec.java @@ -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; } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java index ca8130dbff..844e2aa1d8 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java @@ -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 { diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpEQ.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpEQ.java index 17f9eb8faf..1121cc840a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpEQ.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpEQ.java @@ -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); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGE.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGE.java index a267b7037e..6e1294e461 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGE.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGE.java @@ -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()); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGT.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGT.java index e2b088a2f5..3d751c976d 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGT.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGT.java @@ -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()); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpInc.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpInc.java index eb829e608a..43937ca953 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpInc.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpInc.java @@ -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; } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLE.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLE.java index a09c7c7fb7..47424db204 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLE.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLE.java @@ -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); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLT.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLT.java index 0f0e12d045..dc8916dda8 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLT.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLT.java @@ -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()); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java index 1afb3b28c4..143dfd9014 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java @@ -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; *
  • subtraction of doubles (floats are represented as doubles) *
  • subtraction of longs *
  • subtraction of integers - *
  • subtraction of an int from a string of one character (effectively decreasing that character), so 'd'-3='a' + *
  • subtraction of an int from a string of one character (effectively decreasing that + * character), so 'd'-3='a' * - * 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]; } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpModulus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpModulus.java index 559c43b55e..48b511229d 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpModulus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpModulus.java @@ -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()); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java index 42b0259416..e795dff8b8 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java @@ -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. * *

    Conversions and promotions are handled as defined in - * Section 5.6.2 - * of the Java Language Specification: + * Section + * 5.6.2 of the Java Language Specification: * - *

    If any of the operands is of a reference type, unboxing conversion (Section 5.1.8) is performed. Then:
    + *

    If any of the operands is of a reference type, unboxing conversion (Section 5.1.8) + * is performed. Then:
    * If either operand is of type double, the other is converted to double.
    * Otherwise, if either operand is of type float, the other is converted to float.
    * Otherwise, if either operand is of type long, the other is converted to long.
    @@ -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); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpNE.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpNE.java index 558ccb9763..fdf65c24d7 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpNE.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpNE.java @@ -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); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpOr.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpOr.java index c4d3cd4cf4..ce21a1cb9a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpOr.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpOr.java @@ -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())) { diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java index 7443dd141c..53dad0ff2b 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java @@ -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; *

  • add integers *
  • concatenate strings * - * 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()); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java index 863f1a218f..637ba71185 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java @@ -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; } /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorBetween.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorBetween.java index d18695275e..7f38830d7a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorBetween.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorBetween.java @@ -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; } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java index bf7d0edc91..2f50e86c82 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorMatches.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorMatches.java index 24b7ea46de..573c80de42 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorMatches.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorMatches.java @@ -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 { diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java index 33ae9e0d97..3e5be7217a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java @@ -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; } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorPower.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorPower.java index 0c41e6a8dc..f05e1b7a88 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorPower.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorPower.java @@ -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); } } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Projection.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Projection.java index 226063cf7c..d7fcb505d1 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Projection.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Projection.java @@ -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 result = new ArrayList(); @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java index 043a57e6fd..93c16bf3e4 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java @@ -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; } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java index 427e33b767..99b4b13f53 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java @@ -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. * *

    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("."); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java index df2c110319..2a7f3d8744 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java @@ -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; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Selection.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Selection.java index 710e975921..dfb838042f 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Selection.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Selection.java @@ -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 resultMap = new HashMap(); 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 data = new ArrayList(); 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(); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java index 7964824a3c..f913035d0c 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/SpelNodeImpl.java @@ -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) { - 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()); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java index efcd829726..3755a86284 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java @@ -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; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java index 3ee71fc88f..c637adfb86 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java @@ -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); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeCode.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeCode.java index e8a2ac231a..6a477af880 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeCode.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeCode.java @@ -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(); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java index 9f9bb0af59..9471486338 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java @@ -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 constructedNodes = new Stack(); + private final Stack constructedNodes = new Stack(); - 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 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 listElements = new ArrayList(); 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=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) { diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java index dfefb5516d..18afa0be62 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java @@ -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 getValue(Class 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 getValue(Object rootObject, Class 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 getValue(EvaluationContext context, Class 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 getValue(EvaluationContext context, Object rootObject, Class 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; } /** diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Token.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Token.java index 12b71d6b6d..69e4d3a625 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Token.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Token.java @@ -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); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java index d0b42deea2..c50ac090ba 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java @@ -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; } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java index 4223a40542..cd2c6128b0 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java @@ -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 tokens = new ArrayList(); + 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': - 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 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; - } - } - } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/BooleanTypedValue.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/BooleanTypedValue.java index 6b407e8d0b..70093eeaf6 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/BooleanTypedValue.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/BooleanTypedValue.java @@ -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); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java index 68e47d8533..cce6b0c3cb 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java @@ -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 expectedArgTypes, List 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]; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java index e2601c893b..46202c5274 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java index 36d48cbf87..3d26c61c49 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java @@ -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: *
      - *
    1. An exact match where the types of the arguments match the types of the constructor - *
    2. An in-exact match where the types we are looking for are subtypes of those defined on the constructor - *
    3. A match where we are able to convert the arguments into those expected by the constructor, according to the - * registered type converter. + *
    4. An exact match where the types of the arguments match the types of the + * constructor + *
    5. An in-exact match where the types we are looking for are subtypes of those + * defined on the constructor + *
    6. A match where we are able to convert the arguments into those expected by the + * constructor, according to the registered type converter. *
    */ @Override diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java index fe2f5aa1d1..eb195f12e2 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java @@ -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, 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: *
      diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index ca38218661..ddf3ad8631 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java index ce03b4927c..7f11c0d7b3 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java @@ -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 defaultResolvers = new ArrayList(); - defaultResolvers.add(reflectiveMethodResolver = new ReflectiveMethodResolver()); + defaultResolvers.add(this.reflectiveMethodResolver = new ReflectiveMethodResolver()); this.methodResolvers = defaultResolvers; } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeComparator.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeComparator.java index 92aafb28bc..fad32af97d 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeComparator.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeComparator.java @@ -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; } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java index 0500dde5d5..2104b058c3 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java @@ -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 diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java index 319985fe8a..8fea968184 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java @@ -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 knownPackagePrefixes = new ArrayList();