Index: 3rdParty_sources/spring/org/springframework/expression/AccessException.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/AccessException.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/AccessException.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * An AccessException is thrown by an accessor if it has an unexpected problem.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+@SuppressWarnings("serial")
+public class AccessException extends Exception {
+
+ /**
+ * Create an AccessException with a specific message and cause.
+ * @param message the message
+ * @param cause the cause
+ */
+ public AccessException(String message, Exception cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Create an AccessException with a specific message.
+ * @param message the message
+ */
+ public AccessException(String message) {
+ super(message);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/BeanResolver.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/BeanResolver.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/BeanResolver.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * A bean resolver can be registered with the evaluation context
+ * and will kick in for {@code @myBeanName} still expressions.
+ *
+ * @author Andy Clement
+ * @since 3.0.3
+ */
+public interface BeanResolver {
+
+ /**
+ * Look up the named bean and return it.
+ * @param context the current evaluation context
+ * @param beanName the name of the bean to lookup
+ * @return an object representing the bean
+ * @throws AccessException if there is an unexpected problem resolving the named bean
+ */
+ Object resolve(EvaluationContext context, String beanName) throws AccessException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/ConstructorExecutor.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/ConstructorExecutor.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/ConstructorExecutor.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+
+// 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.
+ *
+ *
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
+ */
+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
+ * @return the new object
+ * @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;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/ConstructorResolver.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/ConstructorResolver.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/ConstructorResolver.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+import 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.
+ *
+ * @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).
+ * @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
+ * @return a ConstructorExecutor that can invoke the constructor, or null if non found
+ */
+ ConstructorExecutor resolve(EvaluationContext context, String typeName, List argumentTypes)
+ throws AccessException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/EvaluationContext.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/EvaluationContext.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/EvaluationContext.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+import java.util.List;
+
+/**
+ * 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.
+ *
+ * @author Andy Clement
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+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.
+ */
+ TypedValue getRootObject();
+
+ /**
+ * Return a list of resolvers that will be asked in turn to locate a constructor.
+ */
+ List getConstructorResolvers();
+
+ /**
+ * Return a list of resolvers that will be asked in turn to locate a method.
+ */
+ List getMethodResolvers();
+
+ /**
+ * Return a list of accessors that will be asked in turn to read/write a property.
+ */
+ List getPropertyAccessors();
+
+ /**
+ * Return a type locator that can be used to find types, either by short or
+ * fully qualified name.
+ */
+ TypeLocator getTypeLocator();
+
+ /**
+ * Return a type converter that can convert (or coerce) a value from one type to another.
+ */
+ TypeConverter getTypeConverter();
+
+ /**
+ * Return a type comparator for comparing pairs of objects for equality.
+ */
+ TypeComparator getTypeComparator();
+
+ /**
+ * Return an operator overloader that may support mathematical operations
+ * between more than the standard set of types.
+ */
+ OperatorOverloader getOperatorOverloader();
+
+ /**
+ * Return a bean resolver that can look up beans by name.
+ */
+ BeanResolver getBeanResolver();
+
+ /**
+ * Set a named variable within this evaluation context to a specified value.
+ * @param name variable to set
+ * @param value value to be placed in the variable
+ */
+ void setVariable(String name, Object value);
+
+ /**
+ * Look up a named variable within this evaluation context.
+ * @param name variable to lookup
+ * @return the value of the variable
+ */
+ Object lookupVariable(String name);
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/EvaluationException.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/EvaluationException.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/EvaluationException.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * Represent an exception that occurs during expression evaluation.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+@SuppressWarnings("serial")
+public class EvaluationException extends ExpressionException {
+
+ /**
+ * Creates a new expression evaluation exception.
+ * @param position the position in the expression where the problem occurred
+ * @param message description of the problem that occurred
+ */
+ public EvaluationException(int position, String message) {
+ super(position, message);
+ }
+
+ /**
+ * Creates a new expression evaluation exception.
+ * @param expressionString the expression that could not be evaluated
+ * @param message description of the problem that occurred
+ */
+ public EvaluationException(String expressionString, String message) {
+ super(expressionString, message);
+ }
+
+ /**
+ * Creates a new expression evaluation exception.
+ * @param position the position in the expression where the problem occurred
+ * @param message description of the problem that occurred
+ * @param cause the underlying cause of this exception
+ */
+ public EvaluationException(int position, String message, Throwable cause) {
+ super(position, message, cause);
+ }
+
+ /**
+ * Creates a new expression evaluation exception.
+ * @param message description of the problem that occurred
+ */
+ public EvaluationException(String message) {
+ super(message);
+ }
+
+ public EvaluationException(String message, Throwable cause) {
+ super(message,cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/Expression.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/Expression.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/Expression.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,240 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+import org.springframework.core.convert.TypeDescriptor;
+
+/**
+ * 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
+ * @since 3.0
+ */
+public interface Expression {
+
+ /**
+ * Evaluate this expression in the default standard context.
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ Object getValue() throws EvaluationException;
+
+ /**
+ * Evaluate this expression against the specified root object
+ * @param rootObject the root object against which properties/etc will be resolved
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ Object getValue(Object rootObject) throws EvaluationException;
+
+ /**
+ * Evaluate the expression in the default context. If the result of the evaluation does not match (and
+ * cannot be converted to) the expected result type then an exception will be returned.
+ * @param desiredResultType the class the caller would like the result to be
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ T getValue(Class desiredResultType) throws EvaluationException;
+
+ /**
+ * Evaluate the expression in the default context against the specified root object. If the
+ * result of the evaluation does not match (and cannot be converted to) the expected result type
+ * then an exception will be returned.
+ * @param rootObject the root object against which properties/etc will be resolved
+ * @param desiredResultType the class the caller would like the result to be
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ T getValue(Object rootObject, Class desiredResultType) throws EvaluationException;
+
+ /**
+ * Evaluate this expression in the provided context and return the result of evaluation.
+ * @param context the context in which to evaluate the expression
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ Object getValue(EvaluationContext context) throws EvaluationException;
+
+ /**
+ * Evaluate this expression in the provided context and return the result of evaluation, but use
+ * the supplied root context as an override for any default root object specified in the context.
+ * @param context the context in which to evaluate the expression
+ * @param rootObject the root object against which properties/etc will be resolved
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException;
+
+ /**
+ * Evaluate the expression in a specified context which can resolve references to properties, methods, types, etc -
+ * the type of the evaluation result is expected to be of a particular class and an exception will be thrown if it
+ * is not and cannot be converted to that type.
+ * @param context the context in which to evaluate the expression
+ * @param desiredResultType the class the caller would like the result to be
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ T getValue(EvaluationContext context, Class desiredResultType) throws EvaluationException;
+
+ /**
+ * Evaluate the expression in a specified context which can resolve references to properties, methods, types, etc -
+ * the type of the evaluation result is expected to be of a particular class and an exception will be thrown if it
+ * is not and cannot be converted to that type. The supplied root object overrides any default specified on the
+ * supplied context.
+ * @param context the context in which to evaluate the expression
+ * @param rootObject the root object against which properties/etc will be resolved
+ * @param desiredResultType the class the caller would like the result to be
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) throws EvaluationException;
+
+ /**
+ * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)}
+ * method using the default context.
+ * @return the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ Class> getValueType() throws EvaluationException;
+
+ /**
+ * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)}
+ * method using the default context.
+ * @param rootObject the root object against which to evaluate the expression
+ * @return the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ Class> getValueType(Object rootObject) throws EvaluationException;
+
+ /**
+ * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)}
+ * method for the given context.
+ * @param context the context in which to evaluate the expression
+ * @return the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ Class> getValueType(EvaluationContext context) throws EvaluationException;
+
+ /**
+ * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)}
+ * method for the given context. The supplied root object overrides any specified in the context.
+ * @param context the context in which to evaluate the expression
+ * @param rootObject the root object against which to evaluate the expression
+ * @return the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ Class> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException;
+
+ /**
+ * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)}
+ * method using the default context.
+ * @return a type descriptor for the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ TypeDescriptor getValueTypeDescriptor() throws EvaluationException;
+
+ /**
+ * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)}
+ * method using the default context.
+ * @param rootObject the root object against which to evaluate the expression
+ * @return a type descriptor for the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException;
+
+ /**
+ * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)}
+ * method for the given context.
+ * @param context the context in which to evaluate the expression
+ * @return a type descriptor for the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException;
+
+ /**
+ * Returns the most general type that can be passed to the {@link #setValue(EvaluationContext, Object)} method for
+ * the given context. The supplied root object overrides any specified in the context.
+ * @param context the context in which to evaluate the expression
+ * @param rootObject the root object against which to evaluate the expression
+ * @return a type descriptor for the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException;
+
+ /**
+ * Determine if an expression can be written to, i.e. setValue() can be called.
+ * @param context the context in which the expression should be checked
+ * @return true if the expression is writable
+ * @throws EvaluationException if there is a problem determining if it is writable
+ */
+ boolean isWritable(EvaluationContext context) throws EvaluationException;
+
+ /**
+ * Determine if an expression can be written to, i.e. setValue() can be called.
+ * The supplied root object overrides any specified in the context.
+ * @param context the context in which the expression should be checked
+ * @param rootObject the root object against which to evaluate the expression
+ * @return true if the expression is writable
+ * @throws EvaluationException if there is a problem determining if it is writable
+ */
+ boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException;
+
+ /**
+ * Determine if an expression can be written to, i.e. setValue() can be called.
+ * @param rootObject the root object against which to evaluate the expression
+ * @return true if the expression is writable
+ * @throws EvaluationException if there is a problem determining if it is writable
+ */
+ boolean isWritable(Object rootObject) throws EvaluationException;
+
+ /**
+ * Set this expression in the provided context to the value provided.
+ *
+ * @param context the context in which to set the value of the expression
+ * @param value the new value
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ void setValue(EvaluationContext context, Object value) throws EvaluationException;
+
+ /**
+ * Set this expression in the provided context to the value provided.
+ * @param rootObject the root object against which to evaluate the expression
+ * @param value the new value
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ void setValue(Object rootObject, Object value) throws EvaluationException;
+
+ /**
+ * Set this expression in the provided context to the value provided.
+ * The supplied root object overrides any specified in the context.
+ * @param context the context in which to set the value of the expression
+ * @param rootObject the root object against which to evaluate the expression
+ * @param value the new value
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException;
+
+ /**
+ * Returns the original string used to create this expression, unmodified.
+ * @return the original expression string
+ */
+ String getExpressionString();
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/ExpressionException.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/ExpressionException.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/ExpressionException.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * Super class for exceptions that can occur whilst processing expressions
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+@SuppressWarnings("serial")
+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
+ * @param message a descriptive message
+ */
+ public ExpressionException(String expressionString, String message) {
+ super(message);
+ this.position = -1;
+ this.expressionString = expressionString;
+ }
+
+ /**
+ * Creates a new expression exception.
+ * @param expressionString the expression string
+ * @param position the position in the expression string where the problem occurred
+ * @param message a descriptive message
+ */
+ public ExpressionException(String expressionString, int position, String message) {
+ super(message);
+ this.position = position;
+ this.expressionString = expressionString;
+ }
+
+ /**
+ * Creates a new expression exception.
+ * @param position the position in the expression string where the problem occurred
+ * @param message a descriptive message
+ */
+ public ExpressionException(int position, String message) {
+ super(message);
+ this.position = position;
+ }
+
+ /**
+ * Creates a new expression exception.
+ * @param position the position in the expression string where the problem occurred
+ * @param message a descriptive message
+ * @param cause the underlying cause of this exception
+ */
+ public ExpressionException(int position, String message, Throwable cause) {
+ super(message,cause);
+ this.position = position;
+ }
+
+ /**
+ * Creates a new expression exception.
+ * @param message a descriptive message
+ */
+ public ExpressionException(String message) {
+ super(message);
+ }
+
+ public ExpressionException(String message, Throwable cause) {
+ super(message,cause);
+ }
+
+
+ /**
+ * Return the exception message. Since Spring 4.0 this method returns the same
+ * result as {@link #toDetailedString()}.
+ * @see java.lang.Throwable#getMessage()
+ */
+ @Override
+ public String getMessage() {
+ return toDetailedString();
+ }
+
+ /**
+ * Return the exception simple message without including the expression that caused
+ * the failure.
+ */
+ public String getSimpleMessage() {
+ return super.getMessage();
+ }
+
+ public String toDetailedString() {
+ StringBuilder output = new StringBuilder();
+ if (this.expressionString!=null) {
+ output.append("Expression '");
+ output.append(this.expressionString);
+ output.append("'");
+ if (this.position!=-1) {
+ output.append(" @ ");
+ output.append(this.position);
+ }
+ output.append(": ");
+ }
+ output.append(getSimpleMessage());
+ return output.toString();
+ }
+
+ public final String getExpressionString() {
+ return this.expressionString;
+ }
+
+ public final int getPosition() {
+ return this.position;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/ExpressionInvocationTargetException.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/ExpressionInvocationTargetException.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/ExpressionInvocationTargetException.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * 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
+ */
+@SuppressWarnings("serial")
+public class ExpressionInvocationTargetException extends EvaluationException {
+
+ public ExpressionInvocationTargetException(int position, String message, Throwable cause) {
+ super(position, message, cause);
+ }
+
+ public ExpressionInvocationTargetException(int position, String message) {
+ super(position, message);
+ }
+
+ public ExpressionInvocationTargetException(String expressionString, String message) {
+ super(expressionString, message);
+ }
+
+ public ExpressionInvocationTargetException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ExpressionInvocationTargetException(String message) {
+ super(message);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/ExpressionParser.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/ExpressionParser.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/ExpressionParser.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * Parses expression strings into compiled expressions that can be evaluated.
+ * Supports parsing templates as well as standard expression strings.
+ *
+ * @author Keith Donald
+ * @author Andy Clement
+ * @since 3.0
+ */
+public interface ExpressionParser {
+
+ /**
+ * Parse the expression string and return an Expression object you can use for repeated evaluation.
+ *
Some examples:
+ *
+ * 3 + 4
+ * name.firstName
+ *
+ * @param expressionString the raw expression string to parse
+ * @return an evaluator for the parsed expression
+ * @throws ParseException an exception occurred during parsing
+ */
+ Expression parseExpression(String expressionString) throws ParseException;
+
+ /**
+ * Parse the expression string and return an Expression object you can use for repeated evaluation.
+ *
Some examples:
+ *
+ * 3 + 4
+ * name.firstName
+ *
+ * @param expressionString the raw expression string to parse
+ * @param context a context for influencing this expression parsing routine (optional)
+ * @return an evaluator for the parsed expression
+ * @throws ParseException an exception occurred during parsing
+ */
+ Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/MethodExecutor.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/MethodExecutor.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/MethodExecutor.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * 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.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+public interface MethodExecutor {
+
+ /**
+ * 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
+ * @return the value returned from execution
+ * @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;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/MethodFilter.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/MethodFilter.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/MethodFilter.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+import 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.
+ *
+ * @author Andy Clement
+ * @since 3.0.1
+ */
+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
+ * 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
+ */
+ List filter(List methods);
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/MethodResolver.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/MethodResolver.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/MethodResolver.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+import 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.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+public interface MethodResolver {
+
+ /**
+ * Within the supplied context determine a suitable method on the supplied object that
+ * can handle the specified arguments. Return a {@link 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
+ */
+ MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
+ List argumentTypes) throws AccessException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/Operation.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/Operation.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/Operation.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * 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
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/OperatorOverloader.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/OperatorOverloader.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/OperatorOverloader.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * 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
+ */
+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.
+ * @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
+ * @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.
+ * @param operation the operation to be performed
+ * @param leftOperand the left operand
+ * @param rightOperand the right operand
+ * @return the result of performing the operation on the two operands
+ * @throws EvaluationException if there is a problem performing the operation
+ */
+ Object operate(Operation operation, Object leftOperand, Object rightOperand)
+ throws EvaluationException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/ParseException.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/ParseException.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/ParseException.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * Represent an exception that occurs during expression parsing.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+@SuppressWarnings("serial")
+public class ParseException extends ExpressionException {
+
+ /**
+ * Creates a new expression parsing exception.
+ * @param expressionString the expression string that could not be parsed
+ * @param position the position in the expression string where the problem occurred
+ * @param message description of the problem that occurred
+ */
+ public ParseException(String expressionString, int position, String message) {
+ super(expressionString, position, message);
+ }
+
+ /**
+ * Creates a new expression parsing exception.
+ * @param position the position in the expression string where the problem occurred
+ * @param message description of the problem that occurred
+ * @param cause the underlying cause of this exception
+ */
+ public ParseException(int position, String message, Throwable cause) {
+ super(position, message, cause);
+ }
+
+ /**
+ * Creates a new expression parsing exception.
+ * @param position the position in the expression string where the problem occurred
+ * @param message description of the problem that occurred
+ */
+ public ParseException(int position, String message) {
+ super(position, message);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/ParserContext.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/ParserContext.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/ParserContext.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * Input provided to an expression parser that can influence an expression
+ * parsing/compilation routine.
+ *
+ * @author Keith Donald
+ * @author Andy Clement
+ * @since 3.0
+ */
+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:
+ *
+ * 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: "${"
+ * @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: "}"
+ * @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 }.
+ * @see #isTemplate()
+ */
+ public static final ParserContext TEMPLATE_EXPRESSION = new ParserContext() {
+
+ @Override
+ public String getExpressionPrefix() {
+ return "#{";
+ }
+
+ @Override
+ public String getExpressionSuffix() {
+ return "}";
+ }
+
+ @Override
+ public boolean isTemplate() {
+ return true;
+ }
+
+ };
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/PropertyAccessor.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/PropertyAccessor.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/PropertyAccessor.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+
+/**
+ * A property accessor is able to read from (and possibly write to) an object's properties.
+ * This 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. However, if it returns {@code null} from {@link #getSpecificTargetClasses()},
+ * 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 {@link #getSpecificTargetClasses()} will be called first, before the general resolvers.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+public interface PropertyAccessor {
+
+ /**
+ * Return an array of classes for which this resolver should be called.
+ *
>Returning {@code 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 {@code 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.
+ * @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
+ */
+ boolean canRead(EvaluationContext context, Object target, String name) throws AccessException;
+
+ /**
+ * Called to read a property from a specified target object.
+ * Should only succeed if {@link #canRead} also returns {@code 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
+ * @return a TypedValue object wrapping the property value read and a type descriptor for it
+ * @throws AccessException if there is any problem accessing the property value
+ */
+ 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.
+ * @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
+ */
+ 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 {@link #canWrite} also returns {@code 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
+ * @param newValue the new value for the property
+ * @throws AccessException if there is any problem writing to the property value
+ */
+ void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/TypeComparator.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/TypeComparator.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/TypeComparator.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * 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 java.lang.Comparable}.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ * @see java.lang.Comparable
+ */
+public interface TypeComparator {
+
+ /**
+ * Return {@code true} if the comparator can compare these two objects.
+ * @param firstObject the first object
+ * @param secondObject the second object
+ * @return {@code true} if the comparator can compare these objects
+ */
+ boolean canCompare(Object firstObject, Object secondObject);
+
+ /**
+ * Compare two given 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 if they are not comparable in the first place)
+ */
+ int compare(Object firstObject, Object secondObject) throws EvaluationException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/TypeConverter.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/TypeConverter.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/TypeConverter.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+import org.springframework.core.convert.TypeDescriptor;
+
+/**
+ * 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
+ * @since 3.0
+ */
+public interface TypeConverter {
+
+ /**
+ * Return {@code 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 {@code true} if that conversion can be performed
+ */
+ boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
+
+ /**
+ * Convert (or coerce) a value from one type to another, for example from a
+ * {@code boolean} to a {@code String}.
+ *
The {@link TypeDescriptor} parameters enable support for typed collections:
+ * A caller may prefer a {@code List<Integer>}, for example, rather than
+ * simply any {@code 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
+ * @return the converted value
+ * @throws EvaluationException if conversion failed or is not possible to begin with
+ */
+ Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType);
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/TypeLocator.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/TypeLocator.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/TypeLocator.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+/**
+ * Implementers of this interface are expected to be able to locate types.
+ * They may use a custom {@link ClassLoader} and/or deal with common
+ * package prefixes (e.g. {@code java.lang}) however they wish.
+ *
+ *
See {@link org.springframework.expression.spel.support.StandardTypeLocator}
+ * for an example implementation.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+public interface TypeLocator {
+
+ /**
+ * Find a type by name. The name may or may not be fully qualified
+ * (e.g. {@code String} or {@code java.lang.String}).
+ * @param typeName the type to be located
+ * @return the {@code Class} object representing that type
+ * @throws EvaluationException if there is a problem finding the type
+ */
+ Class> findType(String typeName) throws EvaluationException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/TypedValue.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/TypedValue.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/TypedValue.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression;
+
+import org.springframework.core.convert.TypeDescriptor;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Encapsulates an object and a {@link TypeDescriptor} that describes it.
+ * The type descriptor can contain generic declarations that would not
+ * be accessible through a simple {@code getClass()} call on the object.
+ *
+ * @author Andy Clement
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class TypedValue {
+
+ public static final TypedValue NULL = new TypedValue(null);
+
+
+ private final Object value;
+
+ private TypeDescriptor typeDescriptor;
+
+
+ /**
+ * Create a {@link TypedValue} for a simple object. The {@link TypeDescriptor}
+ * is inferred from the object, so no generic declarations are preserved.
+ * @param value the object value
+ */
+ public TypedValue(Object value) {
+ this.value = value;
+ this.typeDescriptor = null; // initialized when/if requested
+ }
+
+ /**
+ * Create a {@link TypedValue} for a particular value with a particular
+ * {@link TypeDescriptor} which may contain additional generic declarations.
+ * @param value the object value
+ * @param typeDescriptor a type descriptor describing the type of the value
+ */
+ public TypedValue(Object value, TypeDescriptor typeDescriptor) {
+ this.value = value;
+ this.typeDescriptor = typeDescriptor;
+ }
+
+
+ public Object getValue() {
+ return this.value;
+ }
+
+ public TypeDescriptor getTypeDescriptor() {
+ if (this.typeDescriptor == null && this.value != null) {
+ this.typeDescriptor = TypeDescriptor.forObject(this.value);
+ }
+ return this.typeDescriptor;
+ }
+
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof TypedValue)) {
+ return false;
+ }
+ TypedValue otherTv = (TypedValue) other;
+ // Avoid TypeDescriptor initialization if not necessary
+ return (ObjectUtils.nullSafeEquals(this.value, otherTv.value) &&
+ ((this.typeDescriptor == null && otherTv.typeDescriptor == null) ||
+ ObjectUtils.nullSafeEquals(getTypeDescriptor(), otherTv.getTypeDescriptor())));
+ }
+
+ @Override
+ public int hashCode() {
+ return ObjectUtils.nullSafeHashCode(this.value);
+ }
+
+ @Override
+ public String toString() {
+ return "TypedValue: '" + this.value + "' of [" + getTypeDescriptor() + "]";
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/common/CompositeStringExpression.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/common/CompositeStringExpression.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/common/CompositeStringExpression.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.common;
+
+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:
+ *
+ *
+ * "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
+ */
+public class CompositeStringExpression implements Expression {
+
+ private final String expressionString;
+
+ /** The array of expressions that make up the composite expression */
+ private final Expression[] expressions;
+
+
+ public CompositeStringExpression(String expressionString, Expression[] expressions) {
+ this.expressionString = expressionString;
+ this.expressions = expressions;
+ }
+
+
+ @Override
+ public final String getExpressionString() {
+ return this.expressionString;
+ }
+
+ @Override
+ public String getValue() throws EvaluationException {
+ StringBuilder sb = new StringBuilder();
+ for (Expression expression : this.expressions) {
+ String value = expression.getValue(String.class);
+ if (value != null) {
+ sb.append(value);
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String getValue(Object rootObject) throws EvaluationException {
+ StringBuilder sb = new StringBuilder();
+ for (Expression expression : this.expressions) {
+ String value = expression.getValue(rootObject, String.class);
+ if (value != null) {
+ sb.append(value);
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String getValue(EvaluationContext context) throws EvaluationException {
+ StringBuilder sb = new StringBuilder();
+ for (Expression expression : this.expressions) {
+ String value = expression.getValue(context, String.class);
+ if (value != null) {
+ sb.append(value);
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String getValue(EvaluationContext context, Object rootObject) throws EvaluationException {
+ StringBuilder sb = new StringBuilder();
+ for (Expression expression : this.expressions) {
+ String value = expression.getValue(context, rootObject, String.class);
+ if (value != null) {
+ sb.append(value);
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public Class> getValueType(EvaluationContext context) {
+ return String.class;
+ }
+
+ @Override
+ public Class> getValueType() {
+ return String.class;
+ }
+
+ @Override
+ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) {
+ return TypeDescriptor.valueOf(String.class);
+ }
+
+ @Override
+ public TypeDescriptor getValueTypeDescriptor() {
+ return TypeDescriptor.valueOf(String.class);
+ }
+
+ @Override
+ public void setValue(EvaluationContext context, Object value) throws EvaluationException {
+ throw new EvaluationException(this.expressionString, "Cannot call setValue on a composite expression");
+ }
+
+ @Override
+ public T getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException {
+ Object value = getValue(context);
+ return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType);
+ }
+
+ @Override
+ public T getValue(Class expectedResultType) throws EvaluationException {
+ Object value = getValue();
+ return ExpressionUtils.convertTypedValue(null, new TypedValue(value), expectedResultType);
+ }
+
+ @Override
+ public boolean isWritable(EvaluationContext context) {
+ return false;
+ }
+
+ public Expression[] getExpressions() {
+ return this.expressions;
+ }
+
+
+ @Override
+ public T getValue(Object rootObject, Class desiredResultType) throws EvaluationException {
+ Object value = getValue(rootObject);
+ 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.convertTypedValue(context, new TypedValue(value), desiredResultType);
+ }
+
+ @Override
+ public Class> getValueType(Object rootObject) throws EvaluationException {
+ return String.class;
+ }
+
+ @Override
+ public Class> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return String.class;
+ }
+
+ @Override
+ public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException {
+ return TypeDescriptor.valueOf(String.class);
+ }
+
+ @Override
+ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return TypeDescriptor.valueOf(String.class);
+ }
+
+ @Override
+ public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return false;
+ }
+
+ @Override
+ public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException {
+ throw new EvaluationException(this.expressionString, "Cannot call setValue on a composite expression");
+ }
+
+ @Override
+ public boolean isWritable(Object rootObject) throws EvaluationException {
+ return false;
+ }
+
+ @Override
+ public void setValue(Object rootObject, Object value) throws EvaluationException {
+ throw new EvaluationException(this.expressionString, "Cannot call setValue on a composite expression");
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/common/ExpressionUtils.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/common/ExpressionUtils.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/common/ExpressionUtils.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.common;
+
+import org.springframework.core.convert.TypeDescriptor;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.TypeConverter;
+import org.springframework.expression.TypedValue;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Common utility functions that may be used by any Expression Language provider.
+ *
+ * @author Andy Clement
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+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.
+ * @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
+ * @deprecated use {@link #convertTypedValue(EvaluationContext, TypedValue, Class)}
+ */
+ @Deprecated
+ public static T convert(EvaluationContext context, Object value, Class targetType) throws EvaluationException {
+ 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.
+ * @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
+ */
+ @SuppressWarnings("unchecked")
+ public static T convertTypedValue(EvaluationContext context, TypedValue typedValue, Class targetType) {
+ Object value = typedValue.getValue();
+ if (targetType == null) {
+ return (T) value;
+ }
+ if (context != null) {
+ return (T) context.getTypeConverter().convertValue(
+ value, typedValue.getTypeDescriptor(), TypeDescriptor.valueOf(targetType));
+ }
+ if (ClassUtils.isAssignableValue(targetType, value)) {
+ return (T) value;
+ }
+ throw new EvaluationException("Cannot convert value '" + value + "' to type '" + targetType.getName() + "'");
+ }
+
+ /**
+ * Attempt to convert a typed value to an int using the supplied type converter.
+ */
+ public static int toInt(TypeConverter typeConverter, TypedValue typedValue) {
+ return (Integer) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
+ TypeDescriptor.valueOf(Integer.class));
+ }
+
+ /**
+ * Attempt to convert a typed value to a boolean using the supplied type converter.
+ */
+ public static boolean toBoolean(TypeConverter typeConverter, TypedValue typedValue) {
+ return (Boolean) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
+ TypeDescriptor.valueOf(Boolean.class));
+ }
+
+ /**
+ * Attempt to convert a typed value to a double using the supplied type converter.
+ */
+ public static double toDouble(TypeConverter typeConverter, TypedValue typedValue) {
+ return (Double) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
+ TypeDescriptor.valueOf(Double.class));
+ }
+
+ /**
+ * Attempt to convert a typed value to a long using the supplied type converter.
+ */
+ public static long toLong(TypeConverter typeConverter, TypedValue typedValue) {
+ return (Long) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
+ TypeDescriptor.valueOf(Long.class));
+ }
+
+ /**
+ * Attempt to convert a typed value to a char using the supplied type converter.
+ */
+ public static char toChar(TypeConverter typeConverter, TypedValue typedValue) {
+ return (Character) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
+ TypeDescriptor.valueOf(Character.class));
+ }
+
+ /**
+ * Attempt to convert a typed value to a short using the supplied type converter.
+ */
+ public static short toShort(TypeConverter typeConverter, TypedValue typedValue) {
+ return (Short) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
+ TypeDescriptor.valueOf(Short.class));
+ }
+
+ /**
+ * Attempt to convert a typed value to a float using the supplied type converter.
+ */
+ public static float toFloat(TypeConverter typeConverter, TypedValue typedValue) {
+ return (Float) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
+ TypeDescriptor.valueOf(Float.class));
+ }
+
+ /**
+ * Attempt to convert a typed value to a byte using the supplied type converter.
+ */
+ public static byte toByte(TypeConverter typeConverter, TypedValue typedValue) {
+ return (Byte) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
+ TypeDescriptor.valueOf(Byte.class));
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/common/LiteralExpression.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/common/LiteralExpression.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/common/LiteralExpression.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.common;
+
+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.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+public class LiteralExpression implements Expression {
+
+ /** Fixed literal value of this expression */
+ private final String literalValue;
+
+
+ public LiteralExpression(String literalValue) {
+ this.literalValue = literalValue;
+ }
+
+
+ @Override
+ public final String getExpressionString() {
+ return this.literalValue;
+ }
+
+ @Override
+ public String getValue() {
+ return this.literalValue;
+ }
+
+ @Override
+ public String getValue(EvaluationContext context) {
+ return this.literalValue;
+ }
+
+ @Override
+ public String getValue(Object rootObject) {
+ return this.literalValue;
+ }
+
+ @Override
+ public Class> getValueType(EvaluationContext context) {
+ return String.class;
+ }
+
+ @Override
+ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) {
+ return TypeDescriptor.valueOf(String.class);
+ }
+
+ @Override
+ public TypeDescriptor getValueTypeDescriptor() {
+ return TypeDescriptor.valueOf(String.class);
+ }
+
+ @Override
+ public void setValue(EvaluationContext context, Object value) throws EvaluationException {
+ 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.convertTypedValue(context, new TypedValue(value), expectedResultType);
+ }
+
+ @Override
+ public T getValue(Class expectedResultType) throws EvaluationException {
+ Object value = getValue();
+ return ExpressionUtils.convertTypedValue(null, new TypedValue(value), expectedResultType);
+ }
+
+ @Override
+ public boolean isWritable(EvaluationContext context) {
+ return false;
+ }
+
+ @Override
+ public Class> getValueType() {
+ return String.class;
+ }
+
+ @Override
+ public T getValue(Object rootObject, Class desiredResultType) throws EvaluationException {
+ Object value = getValue(rootObject);
+ return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType);
+ }
+
+ @Override
+ public String getValue(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return this.literalValue;
+ }
+
+ @Override
+ public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) throws EvaluationException {
+ Object value = getValue(context, rootObject);
+ return ExpressionUtils.convertTypedValue(context, new TypedValue(value), desiredResultType);
+ }
+
+ @Override
+ public Class> getValueType(Object rootObject) throws EvaluationException {
+ return String.class;
+ }
+
+ @Override
+ public Class> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return String.class;
+ }
+
+ @Override
+ public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException {
+ return TypeDescriptor.valueOf(String.class);
+ }
+
+ @Override
+ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return TypeDescriptor.valueOf(String.class);
+ }
+
+ @Override
+ public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return false;
+ }
+
+ @Override
+ public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException {
+ throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression");
+ }
+
+ @Override
+ public boolean isWritable(Object rootObject) throws EvaluationException {
+ return false;
+ }
+
+ @Override
+ public void setValue(Object rootObject, Object value) throws EvaluationException {
+ throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression");
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/common/TemplateAwareExpressionParser.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/common/TemplateAwareExpressionParser.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/common/TemplateAwareExpressionParser.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.common;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+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.
+ *
+ * @author Keith Donald
+ * @author Juergen Hoeller
+ * @author Andy Clement
+ * @since 3.0
+ */
+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 {
+ if (context == null) {
+ context = NON_TEMPLATE_PARSER_CONTEXT;
+ }
+
+ if (context.isTemplate()) {
+ return parseTemplate(expressionString, context);
+ }
+ else {
+ return doParseExpression(expressionString, context);
+ }
+ }
+
+ 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 {
+ 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 '.
+ * @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 {
+ 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);
+ if (prefixIndex >= startIdx) {
+ // an inner expression was found - this is a composite
+ if (prefixIndex > startIdx) {
+ expressions.add(createLiteralExpression(context,
+ expressionString.substring(startIdx, prefixIndex)));
+ }
+ int afterPrefixIndex = prefixIndex + prefix.length();
+ 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));
+ }
+
+ if (suffixIndex == afterPrefixIndex) {
+ throw new ParseException(expressionString, prefixIndex,
+ "No expression defined within delimiter '" + prefix + suffix
+ + "' at character " + prefixIndex);
+ }
+
+ 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)));
+ startIdx = expressionString.length();
+ }
+ }
+ return expressions.toArray(new Expression[expressions.size()]);
+ }
+
+ private Expression createLiteralExpression(ParserContext context, String text) {
+ return new LiteralExpression(text);
+ }
+
+ /**
+ * 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) {
+ int suffixPosition = 0;
+ for (int i = 0; i < suffix.length() && pos < expressionString.length(); i++) {
+ if (expressionString.charAt(pos++) != suffix.charAt(suffixPosition++)) {
+ return false;
+ }
+ }
+ if (suffixPosition != suffix.length()) {
+ // the expressionString ran out before the suffix could entirely be found
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Copes with nesting, for example '${...${...}}' where the correct end for the first
+ * ${ is the final }.
+ * @param prefix the prefix
+ * @param suffix the suffix
+ * @param expressionString the expression string
+ * @param afterPrefixIndex the most recently found prefix location for which the
+ * matching end suffix is being sought
+ * @return the position of the correct matching nextSuffix or -1 if none can be found
+ */
+ private int skipToCorrectEndSuffix(String prefix, String suffix,
+ String expressionString, int afterPrefixIndex) throws ParseException {
+ // Chew on the expression text - relying on the rules:
+ // brackets must be in pairs: () [] {}
+ // string literals are "..." or '...' and these may contain unmatched brackets
+ int pos = afterPrefixIndex;
+ int maxlen = expressionString.length();
+ int nextSuffix = expressionString.indexOf(suffix, afterPrefixIndex);
+ if (nextSuffix == -1) {
+ return -1; // the suffix is missing
+ }
+ Stack stack = new Stack();
+ while (pos < maxlen) {
+ if (isSuffixHere(expressionString, pos, suffix) && stack.isEmpty()) {
+ break;
+ }
+ char ch = expressionString.charAt(pos);
+ switch (ch) {
+ case '{':
+ case '[':
+ case '(':
+ stack.push(new Bracket(ch, pos));
+ break;
+ case '}':
+ case ']':
+ case ')':
+ if (stack.isEmpty()) {
+ throw new ParseException(expressionString, pos, "Found closing '"
+ + ch + "' at position " + pos + " without an opening '"
+ + Bracket.theOpenBracketFor(ch) + "'");
+ }
+ Bracket p = stack.pop();
+ if (!p.compatibleWithCloseBracket(ch)) {
+ throw new ParseException(expressionString, pos, "Found closing '"
+ + ch + "' at position " + pos
+ + " but most recent opening is '" + p.bracket
+ + "' at position " + p.pos);
+ }
+ break;
+ case '\'':
+ case '"':
+ // jump to the end of the literal
+ int endLiteral = expressionString.indexOf(ch, pos + 1);
+ if (endLiteral == -1) {
+ throw new ParseException(expressionString, pos,
+ "Found non terminating string literal starting at position "
+ + pos);
+ }
+ pos = endLiteral;
+ break;
+ }
+ pos++;
+ }
+ if (!stack.isEmpty()) {
+ Bracket p = stack.pop();
+ throw new ParseException(expressionString, p.pos, "Missing closing '"
+ + Bracket.theCloseBracketFor(p.bracket) + "' for '" + p.bracket
+ + "' at position " + p.pos);
+ }
+ if (!isSuffixHere(expressionString, pos, suffix)) {
+ return -1;
+ }
+ return pos;
+ }
+
+
+ /**
+ * This captures a type of bracket and the position in which it occurs in the
+ * expression. The positional information is used if an error has to be reported
+ * because the related end bracket cannot be found. Bracket is used to describe:
+ * square brackets [] round brackets () and curly brackets {}
+ */
+ private static class Bracket {
+
+ char bracket;
+
+ int pos;
+
+ Bracket(char bracket, int pos) {
+ this.bracket = bracket;
+ this.pos = pos;
+ }
+
+ boolean compatibleWithCloseBracket(char closeBracket) {
+ if (this.bracket == '{') {
+ return closeBracket == '}';
+ }
+ else if (this.bracket == '[') {
+ return closeBracket == ']';
+ }
+ return closeBracket == ')';
+ }
+
+ static char theOpenBracketFor(char closeBracket) {
+ if (closeBracket == '}') {
+ return '{';
+ }
+ else if (closeBracket == ']') {
+ return '[';
+ }
+ return '(';
+ }
+
+ static char theCloseBracketFor(char openBracket) {
+ if (openBracket == '{') {
+ return '}';
+ }
+ else if (openBracket == '[') {
+ return ']';
+ }
+ return ')';
+ }
+ }
+
+ /**
+ * Actually parse the expression string and return an Expression object.
+ * @param expressionString the raw expression string to parse
+ * @param context a context for influencing this expression parsing routine (optional)
+ * @return an evaluator for the parsed expression
+ * @throws ParseException an exception occurred during parsing
+ */
+ protected abstract Expression doParseExpression(String expressionString,
+ ParserContext context) throws ParseException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/common/TemplateParserContext.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/common/TemplateParserContext.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/common/TemplateParserContext.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.common;
+
+import org.springframework.expression.ParserContext;
+
+/**
+ * Configurable {@link ParserContext} implementation for template parsing. Expects the
+ * expression prefix and suffix as constructor arguments.
+ *
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class TemplateParserContext implements ParserContext {
+
+ private final String expressionPrefix;
+
+ private final String expressionSuffix;
+
+
+ /**
+ * Create a new TemplateParserContext with the default "#{" prefix and "}" suffix.
+ */
+ public TemplateParserContext() {
+ this("#{", "}");
+ }
+
+ /**
+ * Create a new TemplateParserContext for the given prefix and suffix.
+ * @param expressionPrefix the expression prefix to use
+ * @param expressionSuffix the expression suffix to use
+ */
+ public TemplateParserContext(String expressionPrefix, String expressionSuffix) {
+ this.expressionPrefix = expressionPrefix;
+ this.expressionSuffix = expressionSuffix;
+ }
+
+
+ @Override
+ public final boolean isTemplate() {
+ return true;
+ }
+
+ @Override
+ public final String getExpressionPrefix() {
+ return this.expressionPrefix;
+ }
+
+ @Override
+ public final String getExpressionSuffix() {
+ return this.expressionSuffix;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ExpressionState.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ExpressionState.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ExpressionState.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.springframework.core.convert.TypeDescriptor;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.Operation;
+import org.springframework.expression.OperatorOverloader;
+import org.springframework.expression.PropertyAccessor;
+import org.springframework.expression.TypeComparator;
+import org.springframework.expression.TypeConverter;
+import org.springframework.expression.TypedValue;
+import org.springframework.util.Assert;
+
+/**
+ * An ExpressionState is for maintaining per-expression-evaluation state, any changes to
+ * it are not seen by other expressions but it gives a place to hold local variables and
+ * for component expressions in a compound expression to communicate state. This is in
+ * contrast to the EvaluationContext, which is shared amongst expression evaluations, and
+ * any changes to it will be seen by other expressions or any code that chooses to ask
+ * questions of the context.
+ *
+ *
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
+ */
+public class ExpressionState {
+
+ private final EvaluationContext relatedContext;
+
+ private final TypedValue rootObject;
+
+ private final SpelParserConfiguration configuration;
+
+ private Stack variableScopes;
+
+ private Stack contextObjects;
+
+
+ public ExpressionState(EvaluationContext context) {
+ this(context, context.getRootObject(), new SpelParserConfiguration(false, false));
+ }
+
+ public ExpressionState(EvaluationContext context, SpelParserConfiguration configuration) {
+ this(context, context.getRootObject(), configuration);
+ }
+
+ public ExpressionState(EvaluationContext context, TypedValue rootObject) {
+ this(context, rootObject, new SpelParserConfiguration(false, false));
+ }
+
+ public ExpressionState(EvaluationContext context, TypedValue rootObject, SpelParserConfiguration configuration) {
+ Assert.notNull(context, "EvaluationContext must not be null");
+ Assert.notNull(configuration, "SpelParserConfiguration must not be null");
+ this.relatedContext = context;
+ this.rootObject = rootObject;
+ this.configuration = configuration;
+ }
+
+
+ private void ensureVariableScopesInitialized() {
+ if (this.variableScopes == null) {
+ this.variableScopes = new Stack();
+ // top level empty variable scope
+ this.variableScopes.add(new VariableScope());
+ }
+ }
+
+ /**
+ * The active context object is what unqualified references to properties/etc are resolved against.
+ */
+ public TypedValue getActiveContextObject() {
+ if (this.contextObjects == null || this.contextObjects.isEmpty()) {
+ return this.rootObject;
+ }
+ return this.contextObjects.peek();
+ }
+
+ public void pushActiveContextObject(TypedValue obj) {
+ if (this.contextObjects == null) {
+ this.contextObjects = new Stack();
+ }
+ this.contextObjects.push(obj);
+ }
+
+ public void popActiveContextObject() {
+ if (this.contextObjects == null) {
+ this.contextObjects = new Stack();
+ }
+ this.contextObjects.pop();
+ }
+
+ public TypedValue getRootContextObject() {
+ return this.rootObject;
+ }
+
+ public void setVariable(String name, Object value) {
+ this.relatedContext.setVariable(name, value);
+ }
+
+ public TypedValue lookupVariable(String name) {
+ Object value = this.relatedContext.lookupVariable(name);
+ if (value == null) {
+ return TypedValue.NULL;
+ }
+ else {
+ return new TypedValue(value);
+ }
+ }
+
+ public TypeComparator getTypeComparator() {
+ return this.relatedContext.getTypeComparator();
+ }
+
+ public Class> findType(String type) throws EvaluationException {
+ return this.relatedContext.getTypeLocator().findType(type);
+ }
+
+ public Object convertValue(Object value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
+ return this.relatedContext.getTypeConverter().convertValue(value,
+ TypeDescriptor.forObject(value), targetTypeDescriptor);
+ }
+
+ public TypeConverter getTypeConverter() {
+ return this.relatedContext.getTypeConverter();
+ }
+
+ public Object convertValue(TypedValue value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
+ Object val = value.getValue();
+ return this.relatedContext.getTypeConverter().convertValue(val, TypeDescriptor.forObject(val), targetTypeDescriptor);
+ }
+
+ /*
+ * A new scope is entered when a function is invoked.
+ */
+ public void enterScope(Map argMap) {
+ ensureVariableScopesInitialized();
+ this.variableScopes.push(new VariableScope(argMap));
+ }
+
+ public void enterScope(String name, Object value) {
+ ensureVariableScopesInitialized();
+ this.variableScopes.push(new VariableScope(name, value));
+ }
+
+ public void exitScope() {
+ ensureVariableScopesInitialized();
+ this.variableScopes.pop();
+ }
+
+ public void setLocalVariable(String name, Object value) {
+ ensureVariableScopesInitialized();
+ this.variableScopes.peek().setVariable(name, value);
+ }
+
+ public Object lookupLocalVariable(String name) {
+ ensureVariableScopesInitialized();
+ int scopeNumber = this.variableScopes.size() - 1;
+ for (int i = scopeNumber; i >= 0; i--) {
+ if (this.variableScopes.get(i).definesVariable(name)) {
+ return this.variableScopes.get(i).lookupVariable(name);
+ }
+ }
+ return null;
+ }
+
+ public TypedValue operate(Operation op, Object left, Object right) throws EvaluationException {
+ OperatorOverloader overloader = this.relatedContext.getOperatorOverloader();
+ if (overloader.overridesOperation(op, left, right)) {
+ Object returnValue = overloader.operate(op, left, right);
+ return new TypedValue(returnValue);
+ }
+ else {
+ String leftType = (left == null ? "null" : left.getClass().getName());
+ String rightType = (right == null? "null" : right.getClass().getName());
+ throw new SpelEvaluationException(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES, op, leftType, rightType);
+ }
+ }
+
+ public List getPropertyAccessors() {
+ return this.relatedContext.getPropertyAccessors();
+ }
+
+ public EvaluationContext getEvaluationContext() {
+ return this.relatedContext;
+ }
+
+ public SpelParserConfiguration getConfiguration() {
+ 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 the function is executing. When the function returns,
+ * the scope is exited.
+ */
+ private static class VariableScope {
+
+ private final Map vars = new HashMap();
+
+ public VariableScope() {
+ }
+
+ public VariableScope(Map arguments) {
+ if (arguments != null) {
+ this.vars.putAll(arguments);
+ }
+ }
+
+ public VariableScope(String name, Object value) {
+ this.vars.put(name,value);
+ }
+
+ public Object lookupVariable(String name) {
+ return this.vars.get(name);
+ }
+
+ public void setVariable(String name, Object value) {
+ this.vars.put(name,value);
+ }
+
+ public boolean definesVariable(String name) {
+ return this.vars.containsKey(name);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/InternalParseException.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/InternalParseException.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/InternalParseException.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel;
+
+import org.springframework.expression.spel.SpelParseException;
+
+/**
+ * Wraps a real parse exception. This exception flows to the top parse method and then
+ * the wrapped exception is thrown as the real problem.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+@SuppressWarnings("serial")
+public class InternalParseException extends RuntimeException {
+
+ public InternalParseException(SpelParseException cause) {
+ super(cause);
+ }
+
+ @Override
+ public SpelParseException getCause() {
+ return (SpelParseException) super.getCause();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/SpelEvaluationException.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/SpelEvaluationException.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/SpelEvaluationException.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.expression.spel;
+
+import org.springframework.expression.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.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+@SuppressWarnings("serial")
+public class SpelEvaluationException extends EvaluationException {
+
+ 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?
+ this.message = message;
+ this.inserts = inserts;
+ }
+
+ public SpelEvaluationException(int position, SpelMessage message, Object... inserts) {
+ super(position, message.formatMessage(position, inserts));
+ this.message = message;
+ this.inserts = inserts;
+ }
+
+ public SpelEvaluationException(int position, Throwable cause,
+ SpelMessage message, Object... inserts) {
+ super(position,message.formatMessage(position,inserts),cause);
+ this.message = message;
+ this.inserts = inserts;
+ }
+
+ public SpelEvaluationException(Throwable cause, SpelMessage message, Object... inserts) {
+ super(message.formatMessage(0,inserts),cause);
+ this.message = message;
+ this.inserts = inserts;
+ }
+
+
+ /**
+ * @return a formatted message with inserts applied
+ */
+ @Override
+ public String getMessage() {
+ if (this.message != null) {
+ return this.message.formatMessage(this.position, this.inserts);
+ }
+ else {
+ return super.getMessage();
+ }
+ }
+
+ /**
+ * @return the message code
+ */
+ public SpelMessage getMessageCode() {
+ return this.message;
+ }
+
+ /**
+ * Set the position in the related expression which gave rise to this exception.
+ *
+ * @param position the position in the expression that gave rise to the exception
+ */
+ public void setPosition(int position) {
+ this.position = position;
+ }
+
+ /**
+ * @return the message inserts
+ */
+ public Object[] getInserts() {
+ return this.inserts;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/SpelMessage.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/SpelMessage.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/SpelMessage.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel;
+
+import 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
+ *
+ *
+ * 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.
+ *
+ * @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,
+ "Property or field ''{0}'' cannot be found on null"),
+
+ PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1008,
+ "Property or field ''{0}'' cannot be found on object of type ''{1}'' - maybe not public?"),
+
+ PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1009,
+ "Property or field ''{0}'' cannot be set on null"),
+
+ PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010,
+ "Property or field ''{0}'' cannot be set on object of type ''{1}'' - maybe not public?"),
+
+ 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} 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}''"),
+
+ INCORRECT_ELEMENT_TYPE_FOR_ARRAY(Kind.ERROR, 1061,
+ "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");
+
+
+ private final Kind kind;
+
+ private final int code;
+
+ private final String message;
+
+
+ private SpelMessage(Kind kind, int code, String message) {
+ this.kind = kind;
+ this.code = code;
+ this.message = message;
+ }
+
+
+ /**
+ * Produce a complete message including the prefix, the position (if known)
+ * and with the inserts applied to the message.
+ * @param pos the position (ignored and not included in the message if less than 0)
+ * @param inserts the inserts to put into the formatted message
+ * @return a formatted message
+ */
+ public String formatMessage(int pos, Object... inserts) {
+ StringBuilder formattedMessage = new StringBuilder();
+ 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(this.message, inserts));
+ return formattedMessage.toString();
+ }
+
+
+ public static enum Kind { INFO, WARNING, ERROR }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/SpelNode.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/SpelNode.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/SpelNode.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel;
+
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.TypedValue;
+
+/**
+ * Represents a node in the Ast for a parsed expression.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+public interface SpelNode {
+
+ /**
+ * 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.
+ * @param expressionState the current expression state (includes the context)
+ * @return the type value of this node evaluated against the specified state
+ */
+ TypedValue getTypedValue(ExpressionState expressionState) throws EvaluationException;
+
+ /**
+ * Determine if this expression node will support a setValue() call.
+ *
+ * @param expressionState the current expression state (includes the context)
+ * @return true if the expression node will allow setValue()
+ * @throws EvaluationException if something went wrong trying to determine if the node supports writing
+ */
+ 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.
+ * @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
+ */
+ void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException;
+
+ /**
+ * @return the string form of this AST node
+ */
+ String toStringAST();
+
+ /**
+ * @return the number of children under this node
+ */
+ int getChildCount();
+
+ /**
+ * Helper method that returns a SpelNode rather than an Antlr Tree node.
+ * @return the child node cast to a SpelNode
+ */
+ SpelNode getChild(int index);
+
+ /**
+ * 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
+ */
+ Class> getObjectClass(Object obj);
+
+ /**
+ * @return the start position of this Ast node in the expression string
+ */
+ int getStartPosition();
+
+ /**
+ * @return the end position of this Ast node in the expression string
+ */
+ int getEndPosition();
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/SpelParseException.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/SpelParseException.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/SpelParseException.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.expression.spel;
+
+import org.springframework.expression.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.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+@SuppressWarnings("serial")
+public class SpelParseException extends ParseException {
+
+ private final SpelMessage message;
+
+ private final Object[] inserts;
+
+
+ public SpelParseException(String expressionString, int position, SpelMessage message, Object... inserts) {
+ super(expressionString, position, message.formatMessage(position,inserts));
+ this.position = position;
+ this.message = message;
+ this.inserts = inserts;
+ }
+
+ public SpelParseException(int position, SpelMessage message, Object... inserts) {
+ super(position, message.formatMessage(position,inserts));
+ this.position = position;
+ this.message = message;
+ this.inserts = inserts;
+ }
+
+ public SpelParseException(int position, Throwable cause, SpelMessage message, Object... inserts) {
+ super(position, message.formatMessage(position,inserts), cause);
+ this.position = position;
+ this.message = message;
+ this.inserts = inserts;
+ }
+
+
+ /**
+ * @return a formatted message with inserts applied
+ */
+ @Override
+ public String getMessage() {
+ return (this.message != null ? this.message.formatMessage(this.position, this.inserts)
+ : super.getMessage());
+ }
+
+ /**
+ * @return the message code
+ */
+ public SpelMessage getMessageCode() {
+ return this.message;
+ }
+
+ /**
+ * @return the message inserts
+ */
+ public Object[] getInserts() {
+ return this.inserts;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/SpelParserConfiguration.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/SpelParserConfiguration.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/SpelParserConfiguration.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel;
+
+/**
+ * Configuration object for the SpEL expression parser.
+ *
+ * @author Juergen Hoeller
+ * @author Phillip Webb
+ * @since 3.0
+ * @see org.springframework.expression.spel.standard.SpelExpressionParser#SpelExpressionParser(SpelParserConfiguration)
+ */
+public class SpelParserConfiguration {
+
+ private final boolean autoGrowNullReferences;
+
+ private final boolean autoGrowCollections;
+
+ private final int maximumAutoGrowSize;
+
+
+ /**
+ * Create a new {@link SpelParserConfiguration} instance.
+ * @param autoGrowNullReferences if null references should automatically grow
+ * @param autoGrowCollections if collections should automatically grow
+ * @see #SpelParserConfiguration(boolean, boolean, int)
+ */
+ public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections) {
+ this(autoGrowNullReferences, autoGrowCollections, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Create a new {@link SpelParserConfiguration} instance.
+ * @param autoGrowNullReferences if null references should automatically grow
+ * @param autoGrowCollections if collections should automatically grow
+ * @param maximumAutoGrowSize the maximum size that the collection can auto grow
+ */
+ public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize) {
+ this.autoGrowNullReferences = autoGrowNullReferences;
+ this.autoGrowCollections = autoGrowCollections;
+ this.maximumAutoGrowSize = maximumAutoGrowSize;
+ }
+
+
+ /**
+ * @return {@code true} if {@code null} references should be automatically grown
+ */
+ public boolean isAutoGrowNullReferences() {
+ return this.autoGrowNullReferences;
+ }
+
+ /**
+ * @return {@code true} if collections should be automatically grown
+ */
+ public boolean isAutoGrowCollections() {
+ return this.autoGrowCollections;
+ }
+
+ /**
+ * @return the maximum size that a collection can auto grow
+ */
+ public int getMaximumAutoGrowSize() {
+ return this.maximumAutoGrowSize;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/Assign.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/Assign.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/Assign.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import org.springframework.expression.EvaluationException;
+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.
+ *
+ *
Example: 'someNumberProperty=42'
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+public class Assign extends SpelNodeImpl {
+
+
+ public Assign(int pos,SpelNodeImpl... operands) {
+ super(pos,operands);
+ }
+
+
+ @Override
+ public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
+ 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();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/AstUtils.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/AstUtils.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/AstUtils.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.expression.PropertyAccessor;
+
+/**
+ * Utilities methods for use in the Ast classes.
+ *
+ * @author Andy Clement
+ * @since 3.0.2
+ */
+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.
+ * @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
+ */
+ public static List getPropertyAccessorsToTry(Class> targetType, List propertyAccessors) {
+ List specificAccessors = new ArrayList();
+ List generalAccessors = new ArrayList();
+ for (PropertyAccessor resolver : propertyAccessors) {
+ Class>[] targets = resolver.getSpecificTargetClasses();
+ if (targets == null) { // generic resolver that says it can be used for any type
+ generalAccessors.add(resolver);
+ }
+ else {
+ if (targetType != null) {
+ int pos = 0;
+ for (Class> clazz : targets) {
+ if (clazz == targetType) { // put exact matches on the front to be tried first?
+ specificAccessors.add(pos++, resolver);
+ }
+ else if (clazz.isAssignableFrom(targetType)) { // put supertype matches at the end of the
+ // specificAccessor list
+ generalAccessors.add(resolver);
+ }
+ }
+ }
+ }
+ }
+ List resolvers = new ArrayList();
+ resolvers.addAll(specificAccessors);
+ resolvers.addAll(generalAccessors);
+ return resolvers;
+ }
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/BeanReference.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/BeanReference.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/BeanReference.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import org.springframework.expression.AccessException;
+import org.springframework.expression.BeanResolver;
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.TypedValue;
+import org.springframework.expression.spel.ExpressionState;
+import org.springframework.expression.spel.SpelEvaluationException;
+import org.springframework.expression.spel.SpelMessage;
+
+/**
+ * Represents a bean reference to a type, for example "@foo" or "@'foo.bar'"
+ *
+ * @author Andy Clement
+ */
+public class BeanReference extends SpelNodeImpl {
+
+ 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, this.beanname);
+ }
+
+ try {
+ TypedValue bean = new TypedValue(beanResolver.resolve(
+ state.getEvaluationContext(), this.beanname));
+ return bean;
+ }
+ catch (AccessException ae) {
+ throw new SpelEvaluationException( getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_BEAN_RESOLUTION,
+ this.beanname, ae.getMessage());
+ }
+ }
+
+ @Override
+ public String toStringAST() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("@");
+ if (this.beanname.indexOf('.') == -1) {
+ sb.append(this.beanname);
+ }
+ else {
+ sb.append("'").append(this.beanname).append("'");
+ }
+ return sb.toString();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/BooleanLiteral.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/BooleanLiteral.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/BooleanLiteral.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.expression.spel.ast;
+
+import org.springframework.expression.spel.support.BooleanTypedValue;
+
+/**
+ * Represents the literal values TRUE and FALSE.
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+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;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/CompoundExpression.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/CompoundExpression.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/CompoundExpression.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.TypedValue;
+import org.springframework.expression.spel.ExpressionState;
+import org.springframework.expression.spel.SpelEvaluationException;
+
+/**
+ * Represents a DOT separated expression sequence, such as 'property1.property2.methodOne()'
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+public class CompoundExpression extends SpelNodeImpl {
+
+ public CompoundExpression(int pos,SpelNodeImpl... expressionComponents) {
+ super(pos, expressionComponents);
+ if (expressionComponents.length < 2) {
+ throw new IllegalStateException("Do not build compound expression less than one entry: " +
+ expressionComponents.length);
+ }
+ }
+
+
+ @Override
+ protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
+ if (getChildCount() == 1) {
+ return this.children[0].getValueRef(state);
+ }
+ SpelNodeImpl nextNode = this.children[0];
+ try {
+ TypedValue result = nextNode.getValueInternal(state);
+ int cc = getChildCount();
+ for (int i = 1; i < cc - 1; i++) {
+ try {
+ state.pushActiveContextObject(result);
+ nextNode = this.children[i];
+ result = nextNode.getValueInternal(state);
+ }
+ finally {
+ state.popActiveContextObject();
+ }
+ }
+ try {
+ state.pushActiveContextObject(result);
+ nextNode = this.children[cc-1];
+ return nextNode.getValueRef(state);
+ }
+ finally {
+ state.popActiveContextObject();
+ }
+ }
+ catch (SpelEvaluationException ee) {
+ // Correct the position for the error before re-throwing
+ ee.setPosition(nextNode.getStartPosition());
+ throw ee;
+ }
+ }
+
+ /**
+ * Evaluates a compound expression. This involves evaluating each piece in turn and the
+ * return value from each piece is the active context object for the subsequent piece.
+ * @param state the state in which the expression is being evaluated
+ * @return the final value from the last piece of the compound expression
+ */
+ @Override
+ public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
+ return getValueRef(state).getValue();
+ }
+
+ @Override
+ public void setValue(ExpressionState state, Object value) throws EvaluationException {
+ getValueRef(state).setValue(value);
+ }
+
+ @Override
+ public boolean isWritable(ExpressionState state) throws EvaluationException {
+ return getValueRef(state).isWritable();
+ }
+
+ @Override
+ public String toStringAST() {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < getChildCount(); i++) {
+ if (i > 0) {
+ sb.append(".");
+ }
+ sb.append(getChild(i).toStringAST());
+ }
+ return sb.toString();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/ConstructorReference.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/ConstructorReference.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/ConstructorReference.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,407 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.core.convert.TypeDescriptor;
+import org.springframework.expression.AccessException;
+import org.springframework.expression.ConstructorExecutor;
+import org.springframework.expression.ConstructorResolver;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.TypeConverter;
+import org.springframework.expression.TypedValue;
+import org.springframework.expression.common.ExpressionUtils;
+import org.springframework.expression.spel.ExpressionState;
+import org.springframework.expression.spel.SpelEvaluationException;
+import org.springframework.expression.spel.SpelMessage;
+import org.springframework.expression.spel.SpelNode;
+
+/**
+ * Represents the invocation of a constructor. Either a constructor on a regular type or
+ * construction of an array. When an array is constructed, an initializer can be specified.
+ *
+ *
+ * Examples:
+ * new String('hello world')
+ * new int[]{1,2,3,4}
+ * new int[3] new int[3]{1,2,3}
+ *
+ * @author Andy Clement
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class ConstructorReference extends SpelNodeImpl {
+
+ private boolean isArrayConstructor = false;
+
+ private SpelNodeImpl[] dimensions;
+
+ // TODO is this caching safe - passing the expression around will mean this executor is also being passed around
+ /**
+ * The cached executor that may be reused on subsequent evaluations.
+ */
+ private volatile ConstructorExecutor cachedExecutor;
+
+
+ /**
+ * Create a constructor reference. The first argument is the type, the rest are the parameters to the constructor
+ * call
+ */
+ public ConstructorReference(int pos, SpelNodeImpl... arguments) {
+ super(pos, arguments);
+ this.isArrayConstructor = false;
+ }
+
+ /**
+ * Create a constructor reference. The first argument is the type, the rest are the parameters to the constructor
+ * call
+ */
+ public ConstructorReference(int pos, SpelNodeImpl[] dimensions, SpelNodeImpl... arguments) {
+ super(pos, arguments);
+ this.isArrayConstructor = true;
+ this.dimensions = dimensions;
+ }
+
+
+ /**
+ * Implements getValue() - delegating to the code for building an array or a simple type.
+ */
+ @Override
+ public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
+ if (this.isArrayConstructor) {
+ return createArray(state);
+ }
+ else {
+ return createNewInstance(state);
+ }
+ }
+
+ /**
+ * Create a new ordinary object and return it.
+ * @param state the expression state within which this expression is being evaluated
+ * @return the new object
+ * @throws EvaluationException if there is a problem creating the object
+ */
+ private TypedValue createNewInstance(ExpressionState state) throws EvaluationException {
+ Object[] arguments = new Object[getChildCount() - 1];
+ List argumentTypes = new ArrayList(getChildCount() - 1);
+ for (int i = 0; i < arguments.length; i++) {
+ TypedValue childValue = this.children[i + 1].getValueInternal(state);
+ Object value = childValue.getValue();
+ arguments[i] = value;
+ argumentTypes.add(TypeDescriptor.forObject(value));
+ }
+
+ ConstructorExecutor executorToUse = this.cachedExecutor;
+ if (executorToUse != null) {
+ try {
+ return executorToUse.execute(state.getEvaluationContext(), arguments);
+ }
+ catch (AccessException ae) {
+ // Two reasons this can occur:
+ // 1. the method invoked actually threw a real exception
+ // 2. the method invoked was not passed the arguments it expected and has become 'stale'
+
+ // In the first case we should not retry, in the second case we should see if there is a
+ // better suited method.
+
+ // To determine which situation it is, the AccessException will contain a cause.
+ // If the cause is an InvocationTargetException, a user exception was thrown inside the constructor.
+ // Otherwise the constructor could not be invoked.
+ if (ae.getCause() instanceof InvocationTargetException) {
+ // User exception was the root cause - exit now
+ Throwable rootCause = ae.getCause().getCause();
+ if (rootCause instanceof RuntimeException) {
+ throw (RuntimeException) rootCause;
+ }
+ else {
+ String typename = (String) this.children[0].getValueInternal(state).getValue();
+ throw new SpelEvaluationException(getStartPosition(), rootCause,
+ SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM, typename, FormatHelper
+ .formatMethodForMessage("", argumentTypes));
+ }
+ }
+
+ // at this point we know it wasn't a user problem so worth a retry if a better candidate can be found
+ this.cachedExecutor = null;
+ }
+ }
+
+ // either there was no accessor or it no longer exists
+ String typename = (String) this.children[0].getValueInternal(state).getValue();
+ executorToUse = findExecutorForConstructor(typename, argumentTypes, state);
+ try {
+ this.cachedExecutor = executorToUse;
+ return executorToUse.execute(state.getEvaluationContext(), arguments);
+ }
+ catch (AccessException ae) {
+ throw new SpelEvaluationException(getStartPosition(), ae,
+ SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM, typename,
+ FormatHelper.formatMethodForMessage("", argumentTypes));
+ }
+ }
+
+ /**
+ * Go through the list of registered constructor resolvers and see if any can find a constructor that takes the
+ * specified set of arguments.
+ * @param typename the type trying to be constructed
+ * @param argumentTypes the types of the arguments supplied that the constructor must take
+ * @param state the current state of the expression
+ * @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 {
+
+ EvaluationContext eContext = state.getEvaluationContext();
+ List cResolvers = eContext.getConstructorResolvers();
+ if (cResolvers != null) {
+ for (ConstructorResolver ctorResolver : cResolvers) {
+ try {
+ ConstructorExecutor cEx = ctorResolver.resolve(state.getEvaluationContext(), typename,
+ argumentTypes);
+ if (cEx != null) {
+ return cEx;
+ }
+ }
+ catch (AccessException ex) {
+ throw new SpelEvaluationException(getStartPosition(), ex,
+ SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM, typename,
+ FormatHelper.formatMethodForMessage("", argumentTypes));
+ }
+ }
+ }
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.CONSTRUCTOR_NOT_FOUND, typename, FormatHelper
+ .formatMethodForMessage("", argumentTypes));
+ }
+
+ @Override
+ public String toStringAST() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("new ");
+
+ int index = 0;
+ sb.append(getChild(index++).toStringAST());
+ sb.append("(");
+ for (int i = index; i < getChildCount(); i++) {
+ if (i > index) {
+ sb.append(",");
+ }
+ sb.append(getChild(i).toStringAST());
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ /**
+ * Create an array and return it.
+ * @param state the expression state within which this expression is being evaluated
+ * @return the new array
+ * @throws EvaluationException if there is a problem creating the array
+ */
+ private TypedValue createArray(ExpressionState state) throws EvaluationException {
+ // First child gives us the array type which will either be a primitive or reference type
+ 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()));
+ }
+ String type = (String) intendedArrayType;
+ Class> componentType;
+ TypeCode arrayTypeCode = TypeCode.forName(type);
+ if (arrayTypeCode == TypeCode.OBJECT) {
+ componentType = state.findType(type);
+ }
+ else {
+ componentType = arrayTypeCode.getType();
+ }
+ Object newArray;
+ if (!hasInitializer()) {
+ // Confirm all dimensions were specified (for example [3][][5] is missing the 2nd dimension)
+ for (SpelNodeImpl dimension : this.dimensions) {
+ if (dimension == null) {
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.MISSING_ARRAY_DIMENSION);
+ }
+ }
+ TypeConverter typeConverter = state.getEvaluationContext().getTypeConverter();
+
+ // Shortcut for 1 dimensional
+ if (this.dimensions.length == 1) {
+ TypedValue o = this.dimensions[0].getTypedValue(state);
+ int arraySize = ExpressionUtils.toInt(typeConverter, o);
+ newArray = Array.newInstance(componentType, arraySize);
+ }
+ else {
+ // Multi-dimensional - hold onto your hat!
+ int[] dims = new int[this.dimensions.length];
+ for (int d = 0; d < this.dimensions.length; d++) {
+ TypedValue o = this.dimensions[d].getTypedValue(state);
+ dims[d] = ExpressionUtils.toInt(typeConverter, o);
+ }
+ newArray = Array.newInstance(componentType, dims);
+ }
+ }
+ else {
+ // There is an initializer
+ if (this.dimensions.length > 1) {
+ // There is an initializer but this is a multi-dimensional array (e.g. new int[][]{{1,2},{3,4}}) - this
+ // is not currently supported
+ throw new SpelEvaluationException(getStartPosition(),
+ SpelMessage.MULTIDIM_ARRAY_INITIALIZER_NOT_SUPPORTED);
+ }
+ TypeConverter typeConverter = state.getEvaluationContext().getTypeConverter();
+ InlineList initializer = (InlineList) getChild(1);
+ // If a dimension was specified, check it matches the initializer length
+ if (this.dimensions[0] != null) {
+ TypedValue dValue = this.dimensions[0].getTypedValue(state);
+ int i = ExpressionUtils.toInt(typeConverter, dValue);
+ if (i != initializer.getChildCount()) {
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.INITIALIZER_LENGTH_INCORRECT);
+ }
+ }
+ // Build the array and populate it
+ int arraySize = initializer.getChildCount();
+ newArray = Array.newInstance(componentType, arraySize);
+ if (arrayTypeCode == TypeCode.OBJECT) {
+ populateReferenceTypeArray(state, newArray, typeConverter, initializer, componentType);
+ }
+ else if (arrayTypeCode == TypeCode.INT) {
+ populateIntArray(state, newArray, typeConverter, initializer);
+ }
+ else if (arrayTypeCode == TypeCode.BOOLEAN) {
+ populateBooleanArray(state, newArray, typeConverter, initializer);
+ }
+ else if (arrayTypeCode == TypeCode.CHAR) {
+ populateCharArray(state, newArray, typeConverter, initializer);
+ }
+ else if (arrayTypeCode == TypeCode.LONG) {
+ populateLongArray(state, newArray, typeConverter, initializer);
+ }
+ else if (arrayTypeCode == TypeCode.SHORT) {
+ populateShortArray(state, newArray, typeConverter, initializer);
+ }
+ else if (arrayTypeCode == TypeCode.DOUBLE) {
+ populateDoubleArray(state, newArray, typeConverter, initializer);
+ }
+ else if (arrayTypeCode == TypeCode.FLOAT) {
+ populateFloatArray(state, newArray, typeConverter, initializer);
+ }
+ else if (arrayTypeCode == TypeCode.BYTE) {
+ populateByteArray(state, newArray, typeConverter, initializer);
+ }
+ else {
+ throw new IllegalStateException(arrayTypeCode.name());
+ }
+ }
+ return new TypedValue(newArray);
+ }
+
+ private void populateReferenceTypeArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
+ InlineList initializer, Class> componentType) {
+ TypeDescriptor toTypeDescriptor = TypeDescriptor.valueOf(componentType);
+ Object[] newObjectArray = (Object[]) newArray;
+ for (int i = 0; i < newObjectArray.length; i++) {
+ SpelNode elementNode = initializer.getChild(i);
+ Object arrayEntry = elementNode.getValue(state);
+ newObjectArray[i] = typeConverter.convertValue(arrayEntry, TypeDescriptor.forObject(arrayEntry), toTypeDescriptor);
+ }
+ }
+
+ private void populateByteArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
+ InlineList initializer) {
+ byte[] newByteArray = (byte[]) newArray;
+ for (int i = 0; i < newByteArray.length; i++) {
+ TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
+ newByteArray[i] = ExpressionUtils.toByte(typeConverter, typedValue);
+ }
+ }
+
+ private void populateFloatArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
+ InlineList initializer) {
+ float[] newFloatArray = (float[]) newArray;
+ for (int i = 0; i < newFloatArray.length; i++) {
+ TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
+ newFloatArray[i] = ExpressionUtils.toFloat(typeConverter, typedValue);
+ }
+ }
+
+ private void populateDoubleArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
+ InlineList initializer) {
+ double[] newDoubleArray = (double[]) newArray;
+ for (int i = 0; i < newDoubleArray.length; i++) {
+ TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
+ newDoubleArray[i] = ExpressionUtils.toDouble(typeConverter, typedValue);
+ }
+ }
+
+ private void populateShortArray(ExpressionState state, Object newArray,
+ TypeConverter typeConverter, InlineList initializer) {
+ short[] newShortArray = (short[]) newArray;
+ for (int i = 0; i < newShortArray.length; i++) {
+ TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
+ newShortArray[i] = ExpressionUtils.toShort(typeConverter, typedValue);
+ }
+ }
+
+ private void populateLongArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
+ InlineList initializer) {
+ long[] newLongArray = (long[]) newArray;
+ for (int i = 0; i < newLongArray.length; i++) {
+ TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
+ newLongArray[i] = ExpressionUtils.toLong(typeConverter, typedValue);
+ }
+ }
+
+ private void populateCharArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
+ InlineList initializer) {
+ char[] newCharArray = (char[]) newArray;
+ for (int i = 0; i < newCharArray.length; i++) {
+ TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
+ newCharArray[i] = ExpressionUtils.toChar(typeConverter, typedValue);
+ }
+ }
+
+ private void populateBooleanArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
+ InlineList initializer) {
+ boolean[] newBooleanArray = (boolean[]) newArray;
+ for (int i = 0; i < newBooleanArray.length; i++) {
+ TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
+ newBooleanArray[i] = ExpressionUtils.toBoolean(typeConverter, typedValue);
+ }
+ }
+
+ private void populateIntArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
+ InlineList initializer) {
+ int[] newIntArray = (int[]) newArray;
+ for (int i = 0; i < newIntArray.length; i++) {
+ TypedValue typedValue = initializer.getChild(i).getTypedValue(state);
+ newIntArray[i] = ExpressionUtils.toInt(typeConverter, typedValue);
+ }
+ }
+
+ private boolean hasInitializer() {
+ return getChildCount() > 1;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/Elvis.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/Elvis.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/Elvis.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import org.springframework.expression.EvaluationException;
+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".
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+public class Elvis extends SpelNodeImpl {
+
+ public Elvis(int pos, SpelNodeImpl... args) {
+ super(pos,args);
+ }
+
+
+ /**
+ * 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
+ */
+ @Override
+ public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
+ TypedValue value = this.children[0].getValueInternal(state);
+ if ((value.getValue() != null) && !((value.getValue() instanceof String) &&
+ ((String) value.getValue()).length() == 0)) {
+ return value;
+ }
+ else {
+ return this.children[1].getValueInternal(state);
+ }
+ }
+
+ @Override
+ public String toStringAST() {
+ return new StringBuilder().append(getChild(0).toStringAST()).append(" ?: ").append(
+ getChild(1).toStringAST()).toString();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/FloatLiteral.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/FloatLiteral.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/FloatLiteral.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import org.springframework.expression.TypedValue;
+
+/**
+ * Expression language AST node that represents a float literal.
+ *
+ * @author Satyapal Reddy
+ * @since 3.2
+ */
+public class FloatLiteral extends Literal {
+
+ private final TypedValue value;
+
+ FloatLiteral(String payload, int pos, float value) {
+ super(payload, pos);
+ this.value = new TypedValue(value);
+ }
+
+
+ @Override
+ public TypedValue getLiteralValue() {
+ return this.value;
+ }
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/FormatHelper.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/FormatHelper.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/FormatHelper.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import java.util.List;
+
+import org.springframework.core.convert.TypeDescriptor;
+
+/**
+ * Utility methods (formatters, etc) used during parsing and evaluation.
+ *
+ * @author Andy Clement
+ */
+public class FormatHelper {
+
+ /**
+ * Produce a nice string for a given method name with specified arguments.
+ * @param name the name of the method
+ * @param argumentTypes the types of the arguments to the method
+ * @return nicely formatted string, eg. foo(String,int)
+ */
+ public static String formatMethodForMessage(String name, List argumentTypes) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(name);
+ sb.append("(");
+ for (int i = 0; i < argumentTypes.size(); i++) {
+ if (i > 0) {
+ sb.append(",");
+ }
+ TypeDescriptor typeDescriptor = argumentTypes.get(i);
+ if (typeDescriptor != null) {
+ sb.append(formatClassNameForMessage(typeDescriptor.getType()));
+ }
+ else {
+ sb.append(formatClassNameForMessage(null));
+ }
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ /**
+ * Produce a nice string for a given class object.
+ * For example, a string array will have the formatted name "java.lang.String[]".
+ * @param clazz The class whose name is to be formatted
+ * @return a formatted string suitable for message inclusion
+ */
+ public static String formatClassNameForMessage(Class> clazz) {
+ if (clazz == null) {
+ return "null";
+ }
+ StringBuilder fmtd = new StringBuilder();
+ if (clazz.isArray()) {
+ int dims = 1;
+ Class> baseClass = clazz.getComponentType();
+ while (baseClass.isArray()) {
+ baseClass = baseClass.getComponentType();
+ dims++;
+ }
+ fmtd.append(baseClass.getName());
+ for (int i = 0; i < dims; i++) {
+ fmtd.append("[]");
+ }
+ }
+ else {
+ fmtd.append(clazz.getName());
+ }
+ return fmtd.toString();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/FunctionReference.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/FunctionReference.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/FunctionReference.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.springframework.core.MethodParameter;
+import org.springframework.core.convert.TypeDescriptor;
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.TypeConverter;
+import org.springframework.expression.TypedValue;
+import org.springframework.expression.spel.ExpressionState;
+import org.springframework.expression.spel.SpelEvaluationException;
+import org.springframework.expression.spel.SpelMessage;
+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.
+ *
+ *
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
+ */
+public class FunctionReference extends SpelNodeImpl {
+
+ private final String name;
+
+
+ public FunctionReference(String functionName, int pos, SpelNodeImpl... arguments) {
+ super(pos,arguments);
+ this.name = functionName;
+ }
+
+
+ @Override
+ public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
+ TypedValue o = state.lookupVariable(this.name);
+ if (o == null) {
+ 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, this.name, o.getClass());
+ }
+ try {
+ return executeFunctionJLRMethod(state, (Method) o.getValue());
+ }
+ catch (SpelEvaluationException se) {
+ se.setPosition(getStartPosition());
+ throw se;
+ }
+ }
+
+ /**
+ * Execute a function represented as a java.lang.reflect.Method.
+ *
+ * @param state the expression evaluation state
+ * @param the java method to invoke
+ * @return the return value of the invoked Java method
+ * @throws EvaluationException if there is any problem invoking the method
+ */
+ private TypedValue executeFunctionJLRMethod(ExpressionState state, Method method) throws EvaluationException {
+ Object[] functionArgs = getArguments(state);
+
+ if (!method.isVarArgs() && method.getParameterTypes().length != functionArgs.length) {
+ throw new SpelEvaluationException(SpelMessage.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION,
+ functionArgs.length, method.getParameterTypes().length);
+ }
+ // 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(), this.name);
+ }
+
+ // Convert arguments if necessary and remap them for varargs if required
+ if (functionArgs != null) {
+ TypeConverter converter = state.getEvaluationContext().getTypeConverter();
+ ReflectionHelper.convertAllArguments(converter, functionArgs, method);
+ }
+ if (method.isVarArgs()) {
+ functionArgs = ReflectionHelper.setupArgumentsForVarargsInvocation(
+ method.getParameterTypes(), functionArgs);
+ }
+
+ try {
+ ReflectionUtils.makeAccessible(method);
+ Object result = method.invoke(method.getClass(), functionArgs);
+ return new TypedValue(result, new TypeDescriptor(new MethodParameter(method,-1)).narrow(result));
+ }
+ catch (Exception ex) {
+ throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.EXCEPTION_DURING_FUNCTION_CALL,
+ this.name, ex.getMessage());
+ }
+ }
+
+ @Override
+ public String toStringAST() {
+ StringBuilder sb = new StringBuilder("#").append(this.name);
+ sb.append("(");
+ for (int i = 0; i < getChildCount(); i++) {
+ if (i > 0) {
+ sb.append(",");
+ }
+ sb.append(getChild(i).toStringAST());
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ // to 'assign' to a function don't use the () suffix and so it is just a variable reference
+
+ /**
+ * Compute the arguments to the function, they are the children of this expression node.
+ * @return an array of argument values for the function call
+ */
+ private Object[] getArguments(ExpressionState state) throws EvaluationException {
+ // Compute arguments to the function
+ Object[] arguments = new Object[getChildCount()];
+ for (int i = 0; i < arguments.length; i++) {
+ arguments[i] = this.children[i].getValueInternal(state).getValue();
+ }
+ return arguments;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/Identifier.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/Identifier.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/Identifier.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import org.springframework.expression.TypedValue;
+import org.springframework.expression.spel.ExpressionState;
+
+/**
+ * @author Andy Clement
+ * @since 3.0
+ */
+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();
+ }
+
+ @Override
+ public TypedValue getValueInternal(ExpressionState state) {
+ return this.id;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/Indexer.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/Indexer.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/Indexer.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,590 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.core.convert.TypeDescriptor;
+import org.springframework.expression.AccessException;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.PropertyAccessor;
+import org.springframework.expression.TypeConverter;
+import org.springframework.expression.TypedValue;
+import org.springframework.expression.spel.ExpressionState;
+import org.springframework.expression.spel.SpelEvaluationException;
+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.
+ *
+ * @author Andy Clement
+ * @author Phillip Webb
+ * @since 3.0
+ */
+// TODO support multidimensional arrays
+// TODO support correct syntax for multidimensional [][][] and not [,,,]
+public class Indexer extends SpelNodeImpl {
+
+ // These fields are used when the indexer is being used as a property read accessor.
+ // If the name and target type match these cached values then the cachedReadAccessor
+ // is used to read the property. If they do not match, the correct accessor is
+ // discovered and then cached for later use.
+
+ private String cachedReadName;
+
+ private Class> cachedReadTargetType;
+
+ private PropertyAccessor cachedReadAccessor;
+
+ // These fields are used when the indexer is being used as a property write accessor.
+ // If the name and target type match these cached values then the cachedWriteAccessor
+ // is used to write the property. If they do not match, the correct accessor is
+ // discovered and then cached for later use.
+
+ private String cachedWriteName;
+
+ private Class> cachedWriteTargetType;
+
+ private PropertyAccessor cachedWriteAccessor;
+
+
+ public Indexer(int pos, SpelNodeImpl expr) {
+ super(pos, expr);
+ }
+
+
+ @Override
+ public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
+ return getValueRef(state).getValue();
+ }
+
+ @Override
+ public void setValue(ExpressionState state, Object newValue) throws EvaluationException {
+ getValueRef(state).setValue(newValue);
+ }
+
+ @Override
+ public boolean isWritable(ExpressionState expressionState) throws SpelEvaluationException {
+ return true;
+ }
+
+
+ @Override
+ protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
+ TypedValue context = state.getActiveContextObject();
+ Object targetObject = context.getValue();
+ TypeDescriptor targetObjectTypeDescriptor = context.getTypeDescriptor();
+ TypedValue indexValue = null;
+ Object index = null;
+
+ // This first part of the if clause prevents a 'double dereference' of
+ // the property (SPR-5847)
+ if (targetObject instanceof Map && (this.children[0] instanceof PropertyOrFieldReference)) {
+ PropertyOrFieldReference reference = (PropertyOrFieldReference) this.children[0];
+ index = reference.getName();
+ indexValue = new TypedValue(index);
+ }
+ else {
+ // In case the map key is unqualified, we want it evaluated against
+ // the root object so temporarily push that on whilst evaluating the key
+ try {
+ state.pushActiveContextObject(state.getRootContextObject());
+ indexValue = this.children[0].getValueInternal(state);
+ index = indexValue.getValue();
+ }
+ finally {
+ state.popActiveContextObject();
+ }
+ }
+
+ // Indexing into a Map
+ if (targetObject instanceof Map) {
+ Object key = index;
+ if (targetObjectTypeDescriptor.getMapKeyTypeDescriptor() != null) {
+ key = state.convertValue(key, targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
+ }
+ return new MapIndexingValueRef(state.getTypeConverter(), (Map, ?>) targetObject, key,
+ targetObjectTypeDescriptor);
+ }
+
+ if (targetObject == null) {
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
+ }
+
+ // if the object is something that looks indexable by an integer,
+ // attempt to treat the index value as a number
+ if (targetObject.getClass().isArray() || targetObject instanceof Collection || targetObject instanceof String) {
+ int idx = (Integer) state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
+ if (targetObject.getClass().isArray()) {
+ return new ArrayIndexingValueRef(state.getTypeConverter(), targetObject, idx, targetObjectTypeDescriptor);
+ }
+ else if (targetObject instanceof Collection) {
+ return new CollectionIndexingValueRef((Collection>) targetObject, idx, targetObjectTypeDescriptor,
+ state.getTypeConverter(), state.getConfiguration().isAutoGrowCollections(),
+ state.getConfiguration().getMaximumAutoGrowSize());
+ }
+ else if (targetObject instanceof String) {
+ return new StringIndexingLValue((String) targetObject, idx, targetObjectTypeDescriptor);
+ }
+ }
+
+ // Try and treat the index value as a property of the context object
+ // TODO could call the conversion service to convert the value to a String
+ if (indexValue.getTypeDescriptor().getType() == String.class) {
+ return new PropertyIndexingValueRef(targetObject, (String) indexValue.getValue(),
+ state.getEvaluationContext(), targetObjectTypeDescriptor);
+ }
+
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
+ targetObjectTypeDescriptor.toString());
+ }
+
+ @Override
+ public String toStringAST() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for (int i = 0; i < getChildCount(); i++) {
+ if (i > 0) {
+ sb.append(",");
+ }
+ sb.append(getChild(i).toStringAST());
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ private void setArrayElement(TypeConverter converter, Object ctx, int idx, Object newValue,
+ Class> arrayComponentType) throws EvaluationException {
+
+ if (arrayComponentType == Integer.TYPE) {
+ int[] array = (int[]) ctx;
+ checkAccess(array.length, idx);
+ array[idx] = (Integer) converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ TypeDescriptor.valueOf(Integer.class));
+ }
+ else if (arrayComponentType == Boolean.TYPE) {
+ boolean[] array = (boolean[]) ctx;
+ checkAccess(array.length, idx);
+ array[idx] = (Boolean) converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ TypeDescriptor.valueOf(Boolean.class));
+ }
+ else if (arrayComponentType == Character.TYPE) {
+ char[] array = (char[]) ctx;
+ checkAccess(array.length, idx);
+ array[idx] = (Character) converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ TypeDescriptor.valueOf(Character.class));
+ }
+ else if (arrayComponentType == Long.TYPE) {
+ long[] array = (long[]) ctx;
+ checkAccess(array.length, idx);
+ array[idx] = (Long) converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ TypeDescriptor.valueOf(Long.class));
+ }
+ else if (arrayComponentType == Short.TYPE) {
+ short[] array = (short[]) ctx;
+ checkAccess(array.length, idx);
+ array[idx] = (Short) converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ TypeDescriptor.valueOf(Short.class));
+ }
+ else if (arrayComponentType == Double.TYPE) {
+ double[] array = (double[]) ctx;
+ checkAccess(array.length, idx);
+ array[idx] = (Double) converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ TypeDescriptor.valueOf(Double.class));
+ }
+ else if (arrayComponentType == Float.TYPE) {
+ float[] array = (float[]) ctx;
+ checkAccess(array.length, idx);
+ array[idx] = (Float) converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ TypeDescriptor.valueOf(Float.class));
+ }
+ else if (arrayComponentType == Byte.TYPE) {
+ byte[] array = (byte[]) ctx;
+ checkAccess(array.length, idx);
+ array[idx] = (Byte) converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ TypeDescriptor.valueOf(Byte.class));
+ }
+ else {
+ Object[] array = (Object[]) ctx;
+ checkAccess(array.length, idx);
+ array[idx] = converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ TypeDescriptor.valueOf(arrayComponentType));
+ }
+ }
+
+ private Object accessArrayElement(Object ctx, int idx) throws SpelEvaluationException {
+ Class> arrayComponentType = ctx.getClass().getComponentType();
+ if (arrayComponentType == Integer.TYPE) {
+ int[] array = (int[]) ctx;
+ checkAccess(array.length, idx);
+ return array[idx];
+ }
+ else if (arrayComponentType == Boolean.TYPE) {
+ boolean[] array = (boolean[]) ctx;
+ checkAccess(array.length, idx);
+ return array[idx];
+ }
+ else if (arrayComponentType == Character.TYPE) {
+ char[] array = (char[]) ctx;
+ checkAccess(array.length, idx);
+ return array[idx];
+ }
+ else if (arrayComponentType == Long.TYPE) {
+ long[] array = (long[]) ctx;
+ checkAccess(array.length, idx);
+ return array[idx];
+ }
+ else if (arrayComponentType == Short.TYPE) {
+ short[] array = (short[]) ctx;
+ checkAccess(array.length, idx);
+ return array[idx];
+ }
+ else if (arrayComponentType == Double.TYPE) {
+ double[] array = (double[]) ctx;
+ checkAccess(array.length, idx);
+ return array[idx];
+ }
+ else if (arrayComponentType == Float.TYPE) {
+ float[] array = (float[]) ctx;
+ checkAccess(array.length, idx);
+ return array[idx];
+ }
+ else if (arrayComponentType == Byte.TYPE) {
+ byte[] array = (byte[]) ctx;
+ checkAccess(array.length, idx);
+ return array[idx];
+ }
+ else {
+ Object[] array = (Object[]) ctx;
+ checkAccess(array.length, idx);
+ return array[idx];
+ }
+ }
+
+ private void checkAccess(int arrayLength, int index) throws SpelEvaluationException {
+ if (index > arrayLength) {
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.ARRAY_INDEX_OUT_OF_BOUNDS,
+ arrayLength, index);
+ }
+ }
+
+
+ private class ArrayIndexingValueRef implements ValueRef {
+
+ private final TypeConverter typeConverter;
+
+ private final Object array;
+
+ private final int index;
+
+ private final TypeDescriptor typeDescriptor;
+
+
+ ArrayIndexingValueRef(TypeConverter typeConverter, Object array, int index, TypeDescriptor typeDescriptor) {
+ this.typeConverter = typeConverter;
+ this.array = array;
+ this.index = index;
+ this.typeDescriptor = typeDescriptor;
+ }
+
+
+ @Override
+ public TypedValue getValue() {
+ 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.index, newValue,
+ this.typeDescriptor.getElementTypeDescriptor().getType());
+ }
+
+ @Override
+ public boolean isWritable() {
+ return true;
+ }
+ }
+
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private static class MapIndexingValueRef implements ValueRef {
+
+ private final TypeConverter typeConverter;
+
+ private final Map map;
+
+ private final Object key;
+
+ private final TypeDescriptor mapEntryTypeDescriptor;
+
+ public 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));
+ }
+
+ @Override
+ public void setValue(Object newValue) {
+ if (this.mapEntryTypeDescriptor.getMapValueTypeDescriptor() != null) {
+ newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ this.mapEntryTypeDescriptor.getMapValueTypeDescriptor());
+ }
+ this.map.put(this.key, newValue);
+ }
+
+ @Override
+ public boolean isWritable() {
+ return true;
+ }
+ }
+
+
+ private class PropertyIndexingValueRef implements ValueRef {
+
+ private final Object targetObject;
+
+ private final String name;
+
+ private final EvaluationContext evaluationContext;
+
+ private final TypeDescriptor targetObjectTypeDescriptor;
+
+ public PropertyIndexingValueRef(Object targetObject, String value, EvaluationContext evaluationContext,
+ TypeDescriptor targetObjectTypeDescriptor) {
+ this.targetObject = targetObject;
+ this.name = value;
+ this.evaluationContext = evaluationContext;
+ this.targetObjectTypeDescriptor = targetObjectTypeDescriptor;
+ }
+
+
+ @Override
+ public TypedValue getValue() {
+ Class> targetObjectRuntimeClass = getObjectClass(this.targetObject);
+ try {
+ 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 Indexer.this.cachedReadAccessor.read(this.evaluationContext, this.targetObject, this.name);
+ }
+ List accessorsToTry = AstUtils.getPropertyAccessorsToTry(
+ targetObjectRuntimeClass, this.evaluationContext.getPropertyAccessors());
+ if (accessorsToTry != null) {
+ for (PropertyAccessor accessor : accessorsToTry) {
+ if (accessor.canRead(this.evaluationContext, this.targetObject, this.name)) {
+ if (accessor instanceof ReflectivePropertyAccessor) {
+ accessor = ((ReflectivePropertyAccessor) accessor).createOptimalAccessor(
+ this.evaluationContext, 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.targetObjectTypeDescriptor.toString());
+ }
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
+ this.targetObjectTypeDescriptor.toString());
+ }
+
+ @Override
+ public void setValue(Object newValue) {
+ Class> contextObjectClass = getObjectClass(this.targetObject);
+ try {
+ 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
+ Indexer.this.cachedWriteAccessor.write(this.evaluationContext, this.targetObject, this.name, newValue);
+ return;
+ }
+ List accessorsToTry =
+ AstUtils.getPropertyAccessorsToTry(contextObjectClass, this.evaluationContext.getPropertyAccessors());
+ if (accessorsToTry != null) {
+ for (PropertyAccessor accessor : accessorsToTry) {
+ 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;
+ }
+ }
+ }
+ }
+ catch (AccessException ex) {
+ throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE,
+ this.name, ex.getMessage());
+ }
+ }
+
+ @Override
+ public boolean isWritable() {
+ return true;
+ }
+ }
+
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private class CollectionIndexingValueRef implements ValueRef {
+
+ private final Collection collection;
+
+ private final int index;
+
+ private final TypeDescriptor collectionEntryDescriptor;
+
+ private final TypeConverter typeConverter;
+
+ private final boolean growCollection;
+
+ private final int maximumSize;
+
+ public CollectionIndexingValueRef(Collection collection, int index, TypeDescriptor collectionEntryTypeDescriptor,
+ TypeConverter typeConverter, boolean growCollection, int maximumSize) {
+ this.collection = collection;
+ this.index = index;
+ this.collectionEntryDescriptor = collectionEntryTypeDescriptor;
+ this.typeConverter = typeConverter;
+ this.growCollection = growCollection;
+ this.maximumSize = maximumSize;
+ }
+
+
+ @Override
+ public TypedValue getValue() {
+ growCollectionIfNecessary();
+ if (this.collection instanceof List) {
+ Object o = ((List) this.collection).get(this.index);
+ return new TypedValue(o, this.collectionEntryDescriptor.elementTypeDescriptor(o));
+ }
+ int pos = 0;
+ for (Object o : this.collection) {
+ if (pos == this.index) {
+ return new TypedValue(o, this.collectionEntryDescriptor.elementTypeDescriptor(o));
+ }
+ pos++;
+ }
+ throw new IllegalStateException("Failed to find indexed element " + this.index + ": " + this.collection);
+ }
+
+ @Override
+ public void setValue(Object newValue) {
+ growCollectionIfNecessary();
+ if (this.collection instanceof List) {
+ List list = (List) this.collection;
+ if (this.collectionEntryDescriptor.getElementTypeDescriptor() != null) {
+ newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ this.collectionEntryDescriptor.getElementTypeDescriptor());
+ }
+ list.set(this.index, newValue);
+ }
+ else {
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
+ this.collectionEntryDescriptor.toString());
+ }
+ }
+
+ private void growCollectionIfNecessary() {
+ if (this.index >= this.collection.size()) {
+ if (!this.growCollection) {
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS,
+ this.collection.size(), this.index);
+ }
+ if(this.index >= this.maximumSize) {
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION);
+ }
+ if (this.collectionEntryDescriptor.getElementTypeDescriptor() == null) {
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
+ }
+ TypeDescriptor elementType = this.collectionEntryDescriptor.getElementTypeDescriptor();
+ try {
+ int newElements = this.index - this.collection.size();
+ while (newElements >= 0) {
+ (this.collection).add(elementType.getType().newInstance());
+ newElements--;
+ }
+ }
+ catch (Exception ex) {
+ throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION);
+ }
+ }
+ }
+
+ @Override
+ public boolean isWritable() {
+ return true;
+ }
+ }
+
+
+ private class StringIndexingLValue implements ValueRef {
+
+ private final String target;
+
+ private final int index;
+
+ private final TypeDescriptor typeDescriptor;
+
+ public StringIndexingLValue(String target, int index, TypeDescriptor typeDescriptor) {
+ this.target = target;
+ this.index = index;
+ 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(), this.index);
+ }
+ return new TypedValue(String.valueOf(this.target.charAt(this.index)));
+ }
+
+ @Override
+ public void setValue(Object newValue) {
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
+ this.typeDescriptor.toString());
+ }
+
+ @Override
+ public boolean isWritable() {
+ return true;
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/expression/spel/ast/InlineList.java
===================================================================
diff -u
--- 3rdParty_sources/spring/org/springframework/expression/spel/ast/InlineList.java (revision 0)
+++ 3rdParty_sources/spring/org/springframework/expression/spel/ast/InlineList.java (revision 59bce63ef2931ab2a2eb6fab2efc3d952291c674)
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.expression.spel.ast;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.TypedValue;
+import org.springframework.expression.spel.ExpressionState;
+import org.springframework.expression.spel.SpelNode;
+
+/**
+ * Represent a list in an expression, e.g. '{1,2,3}'
+ *
+ * @author Andy Clement
+ * @since 3.0.4
+ */
+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
+ * created.
+ */
+ private void checkIfConstant() {
+ boolean isConstant = true;
+ for (int c = 0, max = getChildCount(); c < max; c++) {
+ SpelNode child = getChild(c);
+ if (!(child instanceof Literal)) {
+ if (child instanceof InlineList) {
+ InlineList inlineList = (InlineList) child;
+ if (!inlineList.isConstant()) {
+ isConstant = false;
+ }
+ }
+ else {
+ isConstant = false;
+ }
+ }
+ }
+ if (isConstant) {
+ List