Convert CRLF (dos) to LF (unix)

Prior to this change, roughly 5% (~300 out of 6000+) of files under the
source tree had CRLF line endings as opposed to the majority which have
LF endings.

This change normalizes these files to LF for consistency going forward.

Command used:

$ git ls-files | xargs file | grep CRLF | cut -d":" -f1 | xargs dos2unix

Issue: SPR-5608
This commit is contained in:
Chris Beams
2011-12-21 14:40:03 +01:00
parent 096de373b4
commit ae72cf2f50
292 changed files with 30756 additions and 30756 deletions

View File

@@ -1,44 +1,44 @@
/*
* 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;
/**
* An AccessException is thrown by an accessor if it has an unexpected problem.
*
* @author Andy Clement
* @since 3.0
*/
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);
}
}
/*
* 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;
/**
* An AccessException is thrown by an accessor if it has an unexpected problem.
*
* @author Andy Clement
* @since 3.0
*/
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);
}
}

View File

@@ -1,38 +1,38 @@
/*
* Copyright 2002-2010 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</code> 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;
}
/*
* Copyright 2002-2010 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</code> 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;
}

View File

@@ -1,45 +1,45 @@
/*
* 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;
// 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;
}
/*
* 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;
// 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;
}

View File

@@ -1,44 +1,44 @@
/*
* Copyright 2002-2010 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</code> 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<TypeDescriptor> argumentTypes)
throws AccessException;
}
/*
* Copyright 2002-2010 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</code> 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<TypeDescriptor> argumentTypes)
throws AccessException;
}

View File

@@ -1,49 +1,49 @@
/*
* Copyright 2002-2010 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
*/
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);
}
}
/*
* Copyright 2002-2010 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
*/
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);
}
}

View File

@@ -1,44 +1,44 @@
/*
* 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;
/**
* MethodExecutors are built by the resolvers and can be cached by the infrastructure to repeat an operation quickly
* without going back to the resolvers. For example, the particular method to run on an object may be discovered by the
* reflection method resolver - it will then build a MethodExecutor that executes that method and the MethodExecutor can
* be reused without needing to go back to the resolver to discover the method again.
*
* <p>They can become stale, and in that case should throw an AccessException - this will cause the infrastructure to go
* back to the resolvers to ask for a new one.
*
* @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;
}
/*
* 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;
/**
* MethodExecutors are built by the resolvers and can be cached by the infrastructure to repeat an operation quickly
* without going back to the resolvers. For example, the particular method to run on an object may be discovered by the
* reflection method resolver - it will then build a MethodExecutor that executes that method and the MethodExecutor can
* be reused without needing to go back to the resolver to discover the method again.
*
* <p>They can become stale, and in that case should throw an AccessException - this will cause the infrastructure to go
* back to the resolvers to ask for a new one.
*
* @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;
}

View File

@@ -1,46 +1,46 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression;
import 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<Method> filter(List<Method> methods);
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression;
import 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<Method> filter(List<Method> methods);
}

View File

@@ -1,44 +1,44 @@
/*
* Copyright 2002-2010 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 MethodExecutor that can be used to invoke that method
* (or <code>null</code> 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<TypeDescriptor> argumentTypes) throws AccessException;
}
/*
* Copyright 2002-2010 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 MethodExecutor that can be used to invoke that method
* (or <code>null</code> 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<TypeDescriptor> argumentTypes) throws AccessException;
}

View File

@@ -1,29 +1,29 @@
/*
* 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;
/**
* 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
}
/*
* 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;
/**
* 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
}

View File

@@ -1,81 +1,81 @@
/*
* 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;
/**
* A property accessor is able to read (and possibly write) to object properties. The interface places no restrictions
* and so implementors are free to access properties directly as fields or through getters or in any other way they see
* as appropriate. A resolver can optionally specify an array of target classes for which it should be called - but if
* it returns null from getSpecificTargetClasses() then it will be called for all property references and given a chance
* to determine if it can read or write them. Property resolvers are considered to be ordered and each will be called in
* turn. The only rule that affects the call order is that any naming the target class directly in
* getSpecifiedTargetClasses() will be called first, before the general resolvers.
*
* @author Andy Clement
* @since 3.0
*/
public interface PropertyAccessor {
/**
* Return an array of classes for which this resolver should be called. Returning null indicates this is a general
* resolver that can be called in an attempt to resolve a property on any type.
* @return an array of classes that this resolver is suitable for (or null if a general resolver)
*/
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
* @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 canWrite() also returns true.
* @param context the evaluation context in which the access is being attempted
* @param target the target object upon which the property is being accessed
* @param name the name of the property being accessed
* @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;
}
/*
* 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;
/**
* A property accessor is able to read (and possibly write) to object properties. The interface places no restrictions
* and so implementors are free to access properties directly as fields or through getters or in any other way they see
* as appropriate. A resolver can optionally specify an array of target classes for which it should be called - but if
* it returns null from getSpecificTargetClasses() then it will be called for all property references and given a chance
* to determine if it can read or write them. Property resolvers are considered to be ordered and each will be called in
* turn. The only rule that affects the call order is that any naming the target class directly in
* getSpecifiedTargetClasses() will be called first, before the general resolvers.
*
* @author Andy Clement
* @since 3.0
*/
public interface PropertyAccessor {
/**
* Return an array of classes for which this resolver should be called. Returning null indicates this is a general
* resolver that can be called in an attempt to resolve a property on any type.
* @return an array of classes that this resolver is suitable for (or null if a general resolver)
*/
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
* @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 canWrite() also returns true.
* @param context the evaluation context in which the access is being attempted
* @param target the target object upon which the property is being accessed
* @param name the name of the property being accessed
* @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;
}

View File

@@ -1,53 +1,53 @@
/*
* Copyright 2002-2011 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 true if the type converter can convert the specified type to the desired target type.
* @param sourceType a type descriptor that describes the source type
* @param targetType a type descriptor that describes the requested result type
* @return true if that conversion can be performed
*/
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
/**
* Convert (may coerce) a value from one type to another, for example from a boolean to a string.
* The typeDescriptor parameter enables support for typed collections - if the caller really wishes they
* can have a List&lt;Integer&gt; for example, rather than simply a List.
* @param value the value to be converted
* @param sourceType a type descriptor that supplies extra information about the source object
* @param targetType a type descriptor that supplies extra information about the requested result type
* @return the converted value
* @throws EvaluationException if conversion is not possible
*/
Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType);
}
/*
* Copyright 2002-2011 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 true if the type converter can convert the specified type to the desired target type.
* @param sourceType a type descriptor that describes the source type
* @param targetType a type descriptor that describes the requested result type
* @return true if that conversion can be performed
*/
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
/**
* Convert (may coerce) a value from one type to another, for example from a boolean to a string.
* The typeDescriptor parameter enables support for typed collections - if the caller really wishes they
* can have a List&lt;Integer&gt; for example, rather than simply a List.
* @param value the value to be converted
* @param sourceType a type descriptor that supplies extra information about the source object
* @param targetType a type descriptor that supplies extra information about the requested result type
* @return the converted value
* @throws EvaluationException if conversion is not possible
*/
Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType);
}

View File

@@ -1,80 +1,80 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression;
import org.springframework.core.convert.TypeDescriptor;
/**
* Encapsulates an object and a type descriptor that describes it.
* The type descriptor can hold generic information that would not be
* accessible through a simple <code>getClass()</code> 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 TypedValue for a simple object. The type descriptor is inferred
* from the object, so no generic information is preserved.
* @param value the object value
*/
public TypedValue(Object value) {
this.value = value;
this.typeDescriptor = null; // initialized when/if requested
}
/**
* Create a TypedValue for a particular value with a particular type descriptor.
* @param value the object value
* @param typeDescriptor a type descriptor describing the type of the value
*/
public TypedValue(Object value, TypeDescriptor typeDescriptor) {
this.value = value;
this.typeDescriptor = typeDescriptor;
}
public Object getValue() {
return this.value;
}
public TypeDescriptor getTypeDescriptor() {
if (this.typeDescriptor == null) {
this.typeDescriptor = TypeDescriptor.forObject(this.value);
}
return this.typeDescriptor;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append("TypedValue: '").append(this.value).append("' of [").append(getTypeDescriptor() + "]");
return str.toString();
}
}
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression;
import org.springframework.core.convert.TypeDescriptor;
/**
* Encapsulates an object and a type descriptor that describes it.
* The type descriptor can hold generic information that would not be
* accessible through a simple <code>getClass()</code> 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 TypedValue for a simple object. The type descriptor is inferred
* from the object, so no generic information is preserved.
* @param value the object value
*/
public TypedValue(Object value) {
this.value = value;
this.typeDescriptor = null; // initialized when/if requested
}
/**
* Create a TypedValue for a particular value with a particular type descriptor.
* @param value the object value
* @param typeDescriptor a type descriptor describing the type of the value
*/
public TypedValue(Object value, TypeDescriptor typeDescriptor) {
this.value = value;
this.typeDescriptor = typeDescriptor;
}
public Object getValue() {
return this.value;
}
public TypeDescriptor getTypeDescriptor() {
if (this.typeDescriptor == null) {
this.typeDescriptor = TypeDescriptor.forObject(this.value);
}
return this.typeDescriptor;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append("TypedValue: '").append(this.value).append("' of [").append(getTypeDescriptor() + "]");
return str.toString();
}
}

View File

@@ -1,65 +1,65 @@
/*
* Copyright 2002-2010 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;
}
public final boolean isTemplate() {
return true;
}
public final String getExpressionPrefix() {
return this.expressionPrefix;
}
public final String getExpressionSuffix() {
return this.expressionSuffix;
}
}
/*
* Copyright 2002-2010 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;
}
public final boolean isTemplate() {
return true;
}
public final String getExpressionPrefix() {
return this.expressionPrefix;
}
public final String getExpressionSuffix() {
return this.expressionSuffix;
}
}

View File

@@ -1,242 +1,242 @@
/*
* Copyright 2002-2011 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.TypedValue;
/**
* An ExpressionState is for maintaining per-expression-evaluation state, any changes to it are not seen by other
* expressions but it gives a place to hold local variables and for component expressions in a compound expression to
* communicate state. This is in contrast to the EvaluationContext, which is shared amongst expression evaluations, and
* any changes to it will be seen by other expressions or any code that chooses to ask questions of the context.
*
* <p>It also acts as a place for to define common utility routines that the various Ast nodes might need.
*
* @author Andy Clement
* @since 3.0
*/
public class ExpressionState {
private final EvaluationContext relatedContext;
private Stack<VariableScope> variableScopes;
private Stack<TypedValue> contextObjects;
private final TypedValue rootObject;
private SpelParserConfiguration configuration;
public ExpressionState(EvaluationContext context) {
this.relatedContext = context;
this.rootObject = context.getRootObject();
}
public ExpressionState(EvaluationContext context, SpelParserConfiguration configuration) {
this.relatedContext = context;
this.configuration = configuration;
this.rootObject = context.getRootObject();
}
public ExpressionState(EvaluationContext context, TypedValue rootObject) {
this.relatedContext = context;
this.rootObject = rootObject;
}
public ExpressionState(EvaluationContext context, TypedValue rootObject, SpelParserConfiguration configuration) {
this.relatedContext = context;
this.configuration = configuration;
this.rootObject = rootObject;
}
private void ensureVariableScopesInitialized() {
if (this.variableScopes == null) {
this.variableScopes = new Stack<VariableScope>();
// 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<TypedValue>();
}
this.contextObjects.push(obj);
}
public void popActiveContextObject() {
if (this.contextObjects==null) {
this.contextObjects = new Stack<TypedValue>();
}
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 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<String, Object> 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<PropertyAccessor> 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<String, Object> vars = new HashMap<String, Object>();
public VariableScope() { }
public VariableScope(Map<String, Object> 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);
}
}
}
/*
* Copyright 2002-2011 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.TypedValue;
/**
* An ExpressionState is for maintaining per-expression-evaluation state, any changes to it are not seen by other
* expressions but it gives a place to hold local variables and for component expressions in a compound expression to
* communicate state. This is in contrast to the EvaluationContext, which is shared amongst expression evaluations, and
* any changes to it will be seen by other expressions or any code that chooses to ask questions of the context.
*
* <p>It also acts as a place for to define common utility routines that the various Ast nodes might need.
*
* @author Andy Clement
* @since 3.0
*/
public class ExpressionState {
private final EvaluationContext relatedContext;
private Stack<VariableScope> variableScopes;
private Stack<TypedValue> contextObjects;
private final TypedValue rootObject;
private SpelParserConfiguration configuration;
public ExpressionState(EvaluationContext context) {
this.relatedContext = context;
this.rootObject = context.getRootObject();
}
public ExpressionState(EvaluationContext context, SpelParserConfiguration configuration) {
this.relatedContext = context;
this.configuration = configuration;
this.rootObject = context.getRootObject();
}
public ExpressionState(EvaluationContext context, TypedValue rootObject) {
this.relatedContext = context;
this.rootObject = rootObject;
}
public ExpressionState(EvaluationContext context, TypedValue rootObject, SpelParserConfiguration configuration) {
this.relatedContext = context;
this.configuration = configuration;
this.rootObject = rootObject;
}
private void ensureVariableScopesInitialized() {
if (this.variableScopes == null) {
this.variableScopes = new Stack<VariableScope>();
// 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<TypedValue>();
}
this.contextObjects.push(obj);
}
public void popActiveContextObject() {
if (this.contextObjects==null) {
this.contextObjects = new Stack<TypedValue>();
}
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 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<String, Object> 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<PropertyAccessor> 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<String, Object> vars = new HashMap<String, Object>();
public VariableScope() { }
public VariableScope(Map<String, Object> 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);
}
}
}

View File

@@ -1,38 +1,38 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
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
*/
public class InternalParseException extends RuntimeException {
public InternalParseException(SpelParseException cause) {
super(cause);
}
public SpelParseException getCause() {
return (SpelParseException) super.getCause();
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
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
*/
public class InternalParseException extends RuntimeException {
public InternalParseException(SpelParseException cause) {
super(cause);
}
public SpelParseException getCause() {
return (SpelParseException) super.getCause();
}
}

View File

@@ -1,92 +1,92 @@
/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
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
*/
public class SpelEvaluationException extends EvaluationException {
private SpelMessage message;
private 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 (message != null)
return message.formatMessage(position, 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 inserts;
}
}
/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
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
*/
public class SpelEvaluationException extends EvaluationException {
private SpelMessage message;
private 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 (message != null)
return message.formatMessage(position, 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 inserts;
}
}

View File

@@ -1,156 +1,156 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
import java.text.MessageFormat;
/**
* Contains all the messages that can be produced by the Spring Expression Language. Each message has a kind (info,
* warn, error) and a code number. Tests can be written to expect particular code numbers rather than particular text,
* enabling the message text to more easily be modified and the tests to run successfully in different locales.
* <p>
* When a message is formatted, it will have this kind of form
*
* <pre>
* EL1004E: (pos 34): Type cannot be found 'String'
* </pre>
*
* </code> The prefix captures the code and the error kind, whilst the position is included if it is known.
*
* @author Andy Clement
* @since 3.0
*/
public enum SpelMessage {
TYPE_CONVERSION_ERROR(Kind.ERROR, 1001, "Type conversion problem, cannot convert from {0} to {1}"), //
CONSTRUCTOR_NOT_FOUND(Kind.ERROR, 1002, "Constructor call: No suitable constructor found on type {0} for arguments {1}"), //
CONSTRUCTOR_INVOCATION_PROBLEM(Kind.ERROR, 1003, "A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"), //
METHOD_NOT_FOUND(Kind.ERROR, 1004, "Method call: Method {0} cannot be found on {1} type"), //
TYPE_NOT_FOUND(Kind.ERROR, 1005, "Type cannot be found ''{0}''"), //
FUNCTION_NOT_DEFINED(Kind.ERROR, 1006, "The function ''{0}'' could not be found"), //
PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1007, "Field or property ''{0}'' cannot be found on null"), //
PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1008, "Field or property ''{0}'' cannot be found on object of type ''{1}''"), //
PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1009, "Field or property ''{0}'' cannot be set on null"), //
PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010, "Field or property ''{0}'' cannot be set on object of type ''{1}''"), //
METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1011, "Method call: Attempted to call method {0} on null context object"), //
CANNOT_INDEX_INTO_NULL_VALUE(Kind.ERROR, 1012, "Cannot index into a null value"),
NOT_COMPARABLE(Kind.ERROR, 1013, "Cannot compare instances of {0} and {1}"), //
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1014, "Incorrect number of arguments for function, {0} supplied but function takes {1}"), //
INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1015, "Cannot perform selection on input data of type ''{0}''"), //
RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1016, "Result of selection criteria is not boolean"), //
BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST(Kind.ERROR, 1017, "Right operand for the 'between' operator has to be a two-element list"), //
INVALID_PATTERN(Kind.ERROR, 1018, "Pattern is not valid ''{0}''"), //
PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1019, "Projection is not supported on the type ''{0}''"), //
ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1020, "The argument list of a lambda expression should never have getValue() called upon it"), //
EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1021, "A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"), //
FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1022, "The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"), //
EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1023, "A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"), //
ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1024, "The array has ''{0}'' elements, index ''{1}'' is invalid"), //
COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1025, "The collection has ''{0}'' elements, index ''{1}'' is invalid"), //
STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1026, "The string has ''{0}'' characters, index ''{1}'' is invalid"), //
INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1027, "Indexing into type ''{0}'' is not supported"), //
INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1028, "The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"), //
EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1029, "A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"), //
OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1030, "The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"), //
PROBLEM_LOCATING_METHOD(Kind.ERROR, 1031, "Problem locating method {0} cannot on type {1}"),
SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1032, "setValue(ExpressionState, Object) not supported for ''{0}''"), //
MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1033, "Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"), //
EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1034, "A problem occurred whilst attempting to set the property ''{0}'': {1}"), //
NOT_AN_INTEGER(Kind.ERROR, 1035, "The value ''{0}'' cannot be parsed as an int"), //
NOT_A_LONG(Kind.ERROR, 1036, "The value ''{0}'' cannot be parsed as a long"), //
INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1037, "First operand to matches operator must be a string. ''{0}'' is not"), //
INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1038, "Second operand to matches operator must be a string. ''{0}'' is not"), //
FUNCTION_MUST_BE_STATIC(Kind.ERROR, 1039, "Only static methods can be called via function references. The method ''{0}'' referred to by name ''{1}'' is not static."),//
NOT_A_REAL(Kind.ERROR, 1040, "The value ''{0}'' cannot be parsed as a double"), //
MORE_INPUT(Kind.ERROR,1041, "After parsing a valid expression, there is still more data in the expression: ''{0}''"),
RIGHT_OPERAND_PROBLEM(Kind.ERROR,1042, "Problem parsing right operand"),
NOT_EXPECTED_TOKEN(Kind.ERROR,1043,"Unexpected token. Expected ''{0}'' but was ''{1}''"),
OOD(Kind.ERROR,1044,"Unexpectedly ran out of input"), //
NON_TERMINATING_DOUBLE_QUOTED_STRING(Kind.ERROR,1045,"Cannot find terminating \" for string"),//
NON_TERMINATING_QUOTED_STRING(Kind.ERROR,1046,"Cannot find terminating ' for string"), //
MISSING_LEADING_ZERO_FOR_NUMBER(Kind.ERROR,1047,"A real number must be prefixed by zero, it cannot start with just ''.''"), //
REAL_CANNOT_BE_LONG(Kind.ERROR,1048,"Real number cannot be suffixed with a long (L or l) suffix"),//
UNEXPECTED_DATA_AFTER_DOT(Kind.ERROR,1049,"Unexpected data after ''.'': ''{0}''"),//
MISSING_CONSTRUCTOR_ARGS(Kind.ERROR,1050,"The arguments '(...)' for the constructor call are missing"),//
RUN_OUT_OF_ARGUMENTS(Kind.ERROR,1051,"Unexpected ran out of arguments"),//
UNABLE_TO_GROW_COLLECTION(Kind.ERROR,1052,"Unable to grow collection"),//
UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE(Kind.ERROR,1053,"Unable to grow collection: unable to determine list element type"),//
UNABLE_TO_CREATE_LIST_FOR_INDEXING(Kind.ERROR,1054,"Unable to dynamically create a List to replace a null value"),//
UNABLE_TO_CREATE_MAP_FOR_INDEXING(Kind.ERROR,1055,"Unable to dynamically create a Map to replace a null value"),//
UNABLE_TO_DYNAMICALLY_CREATE_OBJECT(Kind.ERROR,1056,"Unable to dynamically create instance of ''{0}'' to replace a null value"),//
NO_BEAN_RESOLVER_REGISTERED(Kind.ERROR,1057,"No bean resolver registered in the context to resolve access to bean ''{0}''"),//
EXCEPTION_DURING_BEAN_RESOLUTION(Kind.ERROR, 1058, "A problem occurred when trying to resolve bean ''{0}'':''{1}''"), //
INVALID_BEAN_REFERENCE(Kind.ERROR,1059,"@ can only be followed by an identifier or a quoted name"),//
TYPE_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"), //
;
private Kind kind;
private int code;
private 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, if less than zero it is ignored and not included in the message
* @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(code);
switch (kind) {
// case WARNING:
// formattedMessage.append("W");
// break;
// case INFO:
// formattedMessage.append("I");
// break;
case ERROR:
formattedMessage.append("E");
break;
}
formattedMessage.append(":");
if (pos != -1) {
formattedMessage.append("(pos ").append(pos).append("): ");
}
formattedMessage.append(MessageFormat.format(message, inserts));
return formattedMessage.toString();
}
public static enum Kind {
INFO, WARNING, ERROR
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
import java.text.MessageFormat;
/**
* Contains all the messages that can be produced by the Spring Expression Language. Each message has a kind (info,
* warn, error) and a code number. Tests can be written to expect particular code numbers rather than particular text,
* enabling the message text to more easily be modified and the tests to run successfully in different locales.
* <p>
* When a message is formatted, it will have this kind of form
*
* <pre>
* EL1004E: (pos 34): Type cannot be found 'String'
* </pre>
*
* </code> The prefix captures the code and the error kind, whilst the position is included if it is known.
*
* @author Andy Clement
* @since 3.0
*/
public enum SpelMessage {
TYPE_CONVERSION_ERROR(Kind.ERROR, 1001, "Type conversion problem, cannot convert from {0} to {1}"), //
CONSTRUCTOR_NOT_FOUND(Kind.ERROR, 1002, "Constructor call: No suitable constructor found on type {0} for arguments {1}"), //
CONSTRUCTOR_INVOCATION_PROBLEM(Kind.ERROR, 1003, "A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"), //
METHOD_NOT_FOUND(Kind.ERROR, 1004, "Method call: Method {0} cannot be found on {1} type"), //
TYPE_NOT_FOUND(Kind.ERROR, 1005, "Type cannot be found ''{0}''"), //
FUNCTION_NOT_DEFINED(Kind.ERROR, 1006, "The function ''{0}'' could not be found"), //
PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1007, "Field or property ''{0}'' cannot be found on null"), //
PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1008, "Field or property ''{0}'' cannot be found on object of type ''{1}''"), //
PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1009, "Field or property ''{0}'' cannot be set on null"), //
PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010, "Field or property ''{0}'' cannot be set on object of type ''{1}''"), //
METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1011, "Method call: Attempted to call method {0} on null context object"), //
CANNOT_INDEX_INTO_NULL_VALUE(Kind.ERROR, 1012, "Cannot index into a null value"),
NOT_COMPARABLE(Kind.ERROR, 1013, "Cannot compare instances of {0} and {1}"), //
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1014, "Incorrect number of arguments for function, {0} supplied but function takes {1}"), //
INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1015, "Cannot perform selection on input data of type ''{0}''"), //
RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1016, "Result of selection criteria is not boolean"), //
BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST(Kind.ERROR, 1017, "Right operand for the 'between' operator has to be a two-element list"), //
INVALID_PATTERN(Kind.ERROR, 1018, "Pattern is not valid ''{0}''"), //
PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1019, "Projection is not supported on the type ''{0}''"), //
ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1020, "The argument list of a lambda expression should never have getValue() called upon it"), //
EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1021, "A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"), //
FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1022, "The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"), //
EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1023, "A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"), //
ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1024, "The array has ''{0}'' elements, index ''{1}'' is invalid"), //
COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1025, "The collection has ''{0}'' elements, index ''{1}'' is invalid"), //
STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1026, "The string has ''{0}'' characters, index ''{1}'' is invalid"), //
INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1027, "Indexing into type ''{0}'' is not supported"), //
INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1028, "The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"), //
EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1029, "A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"), //
OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1030, "The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"), //
PROBLEM_LOCATING_METHOD(Kind.ERROR, 1031, "Problem locating method {0} cannot on type {1}"),
SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1032, "setValue(ExpressionState, Object) not supported for ''{0}''"), //
MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1033, "Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"), //
EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1034, "A problem occurred whilst attempting to set the property ''{0}'': {1}"), //
NOT_AN_INTEGER(Kind.ERROR, 1035, "The value ''{0}'' cannot be parsed as an int"), //
NOT_A_LONG(Kind.ERROR, 1036, "The value ''{0}'' cannot be parsed as a long"), //
INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1037, "First operand to matches operator must be a string. ''{0}'' is not"), //
INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1038, "Second operand to matches operator must be a string. ''{0}'' is not"), //
FUNCTION_MUST_BE_STATIC(Kind.ERROR, 1039, "Only static methods can be called via function references. The method ''{0}'' referred to by name ''{1}'' is not static."),//
NOT_A_REAL(Kind.ERROR, 1040, "The value ''{0}'' cannot be parsed as a double"), //
MORE_INPUT(Kind.ERROR,1041, "After parsing a valid expression, there is still more data in the expression: ''{0}''"),
RIGHT_OPERAND_PROBLEM(Kind.ERROR,1042, "Problem parsing right operand"),
NOT_EXPECTED_TOKEN(Kind.ERROR,1043,"Unexpected token. Expected ''{0}'' but was ''{1}''"),
OOD(Kind.ERROR,1044,"Unexpectedly ran out of input"), //
NON_TERMINATING_DOUBLE_QUOTED_STRING(Kind.ERROR,1045,"Cannot find terminating \" for string"),//
NON_TERMINATING_QUOTED_STRING(Kind.ERROR,1046,"Cannot find terminating ' for string"), //
MISSING_LEADING_ZERO_FOR_NUMBER(Kind.ERROR,1047,"A real number must be prefixed by zero, it cannot start with just ''.''"), //
REAL_CANNOT_BE_LONG(Kind.ERROR,1048,"Real number cannot be suffixed with a long (L or l) suffix"),//
UNEXPECTED_DATA_AFTER_DOT(Kind.ERROR,1049,"Unexpected data after ''.'': ''{0}''"),//
MISSING_CONSTRUCTOR_ARGS(Kind.ERROR,1050,"The arguments '(...)' for the constructor call are missing"),//
RUN_OUT_OF_ARGUMENTS(Kind.ERROR,1051,"Unexpected ran out of arguments"),//
UNABLE_TO_GROW_COLLECTION(Kind.ERROR,1052,"Unable to grow collection"),//
UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE(Kind.ERROR,1053,"Unable to grow collection: unable to determine list element type"),//
UNABLE_TO_CREATE_LIST_FOR_INDEXING(Kind.ERROR,1054,"Unable to dynamically create a List to replace a null value"),//
UNABLE_TO_CREATE_MAP_FOR_INDEXING(Kind.ERROR,1055,"Unable to dynamically create a Map to replace a null value"),//
UNABLE_TO_DYNAMICALLY_CREATE_OBJECT(Kind.ERROR,1056,"Unable to dynamically create instance of ''{0}'' to replace a null value"),//
NO_BEAN_RESOLVER_REGISTERED(Kind.ERROR,1057,"No bean resolver registered in the context to resolve access to bean ''{0}''"),//
EXCEPTION_DURING_BEAN_RESOLUTION(Kind.ERROR, 1058, "A problem occurred when trying to resolve bean ''{0}'':''{1}''"), //
INVALID_BEAN_REFERENCE(Kind.ERROR,1059,"@ can only be followed by an identifier or a quoted name"),//
TYPE_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"), //
;
private Kind kind;
private int code;
private 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, if less than zero it is ignored and not included in the message
* @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(code);
switch (kind) {
// case WARNING:
// formattedMessage.append("W");
// break;
// case INFO:
// formattedMessage.append("I");
// break;
case ERROR:
formattedMessage.append("E");
break;
}
formattedMessage.append(":");
if (pos != -1) {
formattedMessage.append("(pos ").append(pos).append("): ");
}
formattedMessage.append(MessageFormat.format(message, inserts));
return formattedMessage.toString();
}
public static enum Kind {
INFO, WARNING, ERROR
}
}

View File

@@ -1,95 +1,95 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
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 o 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();
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
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 o 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();
}

View File

@@ -1,107 +1,107 @@
/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
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
*/
public class SpelParseException extends ParseException {
private SpelMessage message;
private Object[] inserts;
// public SpelParseException(String expressionString, int position, Throwable cause, SpelMessages message, Object... inserts) {
// super(expressionString, position, message.formatMessage(position,inserts), cause);
// this.message = message;
// this.inserts = inserts;
// }
public SpelParseException(String expressionString, int position, SpelMessage message, Object... inserts) {
super(expressionString, position, message.formatMessage(position,inserts));
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;
}
//
// public SpelException(Throwable cause, SpelMessages message, Object... inserts) {
// super(cause);
// this.message = message;
// this.inserts = inserts;
// }
//
// public SpelException(int position, SpelMessages message, Object... inserts) {
// super((Throwable)null);
// this.position = position;
// this.message = message;
// this.inserts = inserts;
// }
//
// public SpelException(SpelMessages message, Object... inserts) {
// super((Throwable)null);
// this.message = message;
// this.inserts = inserts;
// }
/**
* @return a formatted message with inserts applied
*/
@Override
public String getMessage() {
if (message != null)
return message.formatMessage(position, inserts);
else
return super.getMessage();
}
/**
* @return the message code
*/
public SpelMessage getMessageCode() {
return this.message;
}
/**
* @return the message inserts
*/
public Object[] getInserts() {
return inserts;
}
}
/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
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
*/
public class SpelParseException extends ParseException {
private SpelMessage message;
private Object[] inserts;
// public SpelParseException(String expressionString, int position, Throwable cause, SpelMessages message, Object... inserts) {
// super(expressionString, position, message.formatMessage(position,inserts), cause);
// this.message = message;
// this.inserts = inserts;
// }
public SpelParseException(String expressionString, int position, SpelMessage message, Object... inserts) {
super(expressionString, position, message.formatMessage(position,inserts));
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;
}
//
// public SpelException(Throwable cause, SpelMessages message, Object... inserts) {
// super(cause);
// this.message = message;
// this.inserts = inserts;
// }
//
// public SpelException(int position, SpelMessages message, Object... inserts) {
// super((Throwable)null);
// this.position = position;
// this.message = message;
// this.inserts = inserts;
// }
//
// public SpelException(SpelMessages message, Object... inserts) {
// super((Throwable)null);
// this.message = message;
// this.inserts = inserts;
// }
/**
* @return a formatted message with inserts applied
*/
@Override
public String getMessage() {
if (message != null)
return message.formatMessage(position, inserts);
else
return super.getMessage();
}
/**
* @return the message code
*/
public SpelMessage getMessageCode() {
return this.message;
}
/**
* @return the message inserts
*/
public Object[] getInserts() {
return inserts;
}
}

View File

@@ -1,47 +1,47 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
/**
* Configuration object for the SpEL expression parser.
*
* @author Juergen Hoeller
* @since 3.0
* @see org.springframework.expression.spel.standard.SpelExpressionParser#SpelExpressionParser(SpelParserConfiguration)
*/
public class SpelParserConfiguration {
private final boolean autoGrowNullReferences;
private final boolean autoGrowCollections;
public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections) {
this.autoGrowNullReferences = autoGrowNullReferences;
this.autoGrowCollections = autoGrowCollections;
}
public boolean isAutoGrowNullReferences() {
return this.autoGrowNullReferences;
}
public boolean isAutoGrowCollections() {
return this.autoGrowCollections;
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
/**
* Configuration object for the SpEL expression parser.
*
* @author Juergen Hoeller
* @since 3.0
* @see org.springframework.expression.spel.standard.SpelExpressionParser#SpelExpressionParser(SpelParserConfiguration)
*/
public class SpelParserConfiguration {
private final boolean autoGrowNullReferences;
private final boolean autoGrowCollections;
public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections) {
this.autoGrowNullReferences = autoGrowNullReferences;
this.autoGrowCollections = autoGrowCollections;
}
public boolean isAutoGrowNullReferences() {
return this.autoGrowNullReferences;
}
public boolean isAutoGrowCollections() {
return this.autoGrowCollections;
}
}

View File

@@ -1,72 +1,72 @@
/*
* Copyright 2010 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;
import org.springframework.expression.spel.ExpressionState;
/**
* 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<PropertyAccessor> getPropertyAccessorsToTry(Class<?> targetType, ExpressionState state) {
List<PropertyAccessor> specificAccessors = new ArrayList<PropertyAccessor>();
List<PropertyAccessor> generalAccessors = new ArrayList<PropertyAccessor>();
for (PropertyAccessor resolver : state.getPropertyAccessors()) {
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<PropertyAccessor> resolvers = new ArrayList<PropertyAccessor>();
resolvers.addAll(specificAccessors);
resolvers.addAll(generalAccessors);
return resolvers;
}
}
/*
* Copyright 2010 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;
import org.springframework.expression.spel.ExpressionState;
/**
* 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<PropertyAccessor> getPropertyAccessorsToTry(Class<?> targetType, ExpressionState state) {
List<PropertyAccessor> specificAccessors = new ArrayList<PropertyAccessor>();
List<PropertyAccessor> generalAccessors = new ArrayList<PropertyAccessor>();
for (PropertyAccessor resolver : state.getPropertyAccessors()) {
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<PropertyAccessor> resolvers = new ArrayList<PropertyAccessor>();
resolvers.addAll(specificAccessors);
resolvers.addAll(generalAccessors);
return resolvers;
}
}

View File

@@ -1,84 +1,84 @@
/*
* Copyright 2002-2011 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<TypeDescriptor> 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();
}
}
/*
* Copyright 2002-2011 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<TypeDescriptor> 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();
}
}

View File

@@ -1,120 +1,120 @@
/*
* Copyright 2002-2010 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<Object> constantList = new ArrayList<Object>();
int childcount = getChildCount();
for (int c = 0; c < childcount; c++) {
SpelNode child = getChild(c);
if ((child instanceof Literal)) {
constantList.add(((Literal) child).getLiteralValue().getValue());
} else if (child instanceof InlineList) {
constantList.add(((InlineList) child).getConstantValue());
}
}
this.constant = new TypedValue(Collections.unmodifiableList(constantList));
}
}
@Override
public TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException {
if (constant != null) {
return constant;
} else {
List<Object> returnValue = new ArrayList<Object>();
int childcount = getChildCount();
for (int c = 0; c < childcount; c++) {
returnValue.add(getChild(c).getValue(expressionState));
}
return new TypedValue(returnValue);
}
}
@Override
public String toStringAST() {
StringBuilder s = new StringBuilder();
// string ast matches input string, not the 'toString()' of the resultant collection, which would use []
s.append('{');
int count = getChildCount();
for (int c = 0; c < count; c++) {
if (c > 0) {
s.append(',');
}
s.append(getChild(c).toStringAST());
}
s.append('}');
return s.toString();
}
/**
* @return whether this list is a constant value
*/
public boolean isConstant() {
return constant != null;
}
@SuppressWarnings("unchecked")
private List<Object> getConstantValue() {
return (List<Object>) constant.getValue();
}
}
/*
* Copyright 2002-2010 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<Object> constantList = new ArrayList<Object>();
int childcount = getChildCount();
for (int c = 0; c < childcount; c++) {
SpelNode child = getChild(c);
if ((child instanceof Literal)) {
constantList.add(((Literal) child).getLiteralValue().getValue());
} else if (child instanceof InlineList) {
constantList.add(((InlineList) child).getConstantValue());
}
}
this.constant = new TypedValue(Collections.unmodifiableList(constantList));
}
}
@Override
public TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException {
if (constant != null) {
return constant;
} else {
List<Object> returnValue = new ArrayList<Object>();
int childcount = getChildCount();
for (int c = 0; c < childcount; c++) {
returnValue.add(getChild(c).getValue(expressionState));
}
return new TypedValue(returnValue);
}
}
@Override
public String toStringAST() {
StringBuilder s = new StringBuilder();
// string ast matches input string, not the 'toString()' of the resultant collection, which would use []
s.append('{');
int count = getChildCount();
for (int c = 0; c < count; c++) {
if (c > 0) {
s.append(',');
}
s.append(getChild(c).toStringAST());
}
s.append('}');
return s.toString();
}
/**
* @return whether this list is a constant value
*/
public boolean isConstant() {
return constant != null;
}
@SuppressWarnings("unchecked")
private List<Object> getConstantValue() {
return (List<Object>) constant.getValue();
}
}

View File

@@ -1,40 +1,40 @@
/*
* Copyright 2002-2010 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 an integer literal.
*
* @author Andy Clement
* @since 3.0
*/
public class IntLiteral extends Literal {
private final TypedValue value;
IntLiteral(String payload, int pos, int value) {
super(payload, pos);
this.value = new TypedValue(value);
}
@Override
public TypedValue getLiteralValue() {
return this.value;
}
}
/*
* Copyright 2002-2010 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 an integer literal.
*
* @author Andy Clement
* @since 3.0
*/
public class IntLiteral extends Literal {
private final TypedValue value;
IntLiteral(String payload, int pos, int value) {
super(payload, pos);
this.value = new TypedValue(value);
}
@Override
public TypedValue getLiteralValue() {
return this.value;
}
}

View File

@@ -1,61 +1,61 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.ast;
/**
* Captures primitive types and their corresponding class objects, plus one special entry that represents all reference
* (non-primitive) types.
*
* @author Andy Clement
*/
public enum TypeCode {
OBJECT(Object.class), BOOLEAN(Boolean.TYPE), BYTE(Byte.TYPE), CHAR(Character.TYPE), //
SHORT(Short.TYPE), INT(Integer.TYPE), LONG(Long.TYPE), FLOAT(Float.TYPE), DOUBLE(Double.TYPE);
private Class<?> type;
TypeCode(Class<?> type) {
this.type = type;
}
public Class<?> getType() {
return type;
}
public static TypeCode forName(String name) {
String searchingFor = name.toUpperCase();
TypeCode[] tcs = values();
for (int i = 1; i < tcs.length; i++) {
if (tcs[i].name().equals(searchingFor)) {
return tcs[i];
}
}
return TypeCode.OBJECT;
}
public static TypeCode forClass(Class<?> c) {
TypeCode[] allValues = TypeCode.values();
for (int i = 0; i < allValues.length; i++) {
TypeCode typeCode = allValues[i];
if (c == typeCode.getType()) {
return typeCode;
}
}
return OBJECT;
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.ast;
/**
* Captures primitive types and their corresponding class objects, plus one special entry that represents all reference
* (non-primitive) types.
*
* @author Andy Clement
*/
public enum TypeCode {
OBJECT(Object.class), BOOLEAN(Boolean.TYPE), BYTE(Byte.TYPE), CHAR(Character.TYPE), //
SHORT(Short.TYPE), INT(Integer.TYPE), LONG(Long.TYPE), FLOAT(Float.TYPE), DOUBLE(Double.TYPE);
private Class<?> type;
TypeCode(Class<?> type) {
this.type = type;
}
public Class<?> getType() {
return type;
}
public static TypeCode forName(String name) {
String searchingFor = name.toUpperCase();
TypeCode[] tcs = values();
for (int i = 1; i < tcs.length; i++) {
if (tcs[i].name().equals(searchingFor)) {
return tcs[i];
}
}
return TypeCode.OBJECT;
}
public static TypeCode forClass(Class<?> c) {
TypeCode[] allValues = TypeCode.values();
for (int i = 0; i < allValues.length; i++) {
TypeCode typeCode = allValues[i];
if (c == typeCode.getType()) {
return typeCode;
}
}
return OBJECT;
}
}

View File

@@ -1,268 +1,268 @@
grammar SpringExpressions;
options {
language = Java;
output=AST;
k=2;
}
tokens {
INTEGER_LITERAL;
EXPRESSION;
QUALIFIED_IDENTIFIER;
PROPERTY_OR_FIELD;
INDEXER;
CONSTRUCTOR;
HOLDER;
NAMED_ARGUMENT;
FUNCTIONREF;
TYPEREF;
VARIABLEREF;
METHOD;
ADD;
SUBTRACT;
NUMBER;
}
// applies only to the parser:
@header {package org.springframework.expression.spel.generated;}
// applies only to the lexer:
@lexer::header {package org.springframework.expression.spel.generated;}
@members {
// For collecting info whilst processing rules that can be used in messages
protected Stack<String> paraphrase = new Stack<String>();
}
@rulecatch {
catch(RecognitionException e) {
reportError(e);
throw e;
}
}
expr: expression EOF!;
expression :
logicalOrExpression
( (ASSIGN^ logicalOrExpression)
| (DEFAULT^ logicalOrExpression)
| (QMARK^ expression COLON! expression))?;
parenExpr : LPAREN! expression RPAREN!;
logicalOrExpression
: logicalAndExpression (OR^ logicalAndExpression)*;
logicalAndExpression
: relationalExpression (AND^ relationalExpression)*;
relationalExpression : sumExpression (relationalOperator^ sumExpression)?;
sumExpression
: productExpression ( (PLUS^ | MINUS^) productExpression)*;
productExpression
: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ;
powerExpr : unaryExpression (POWER^ unaryExpression)? ;
unaryExpression
: (PLUS^ | MINUS^ | BANG^) unaryExpression
| primaryExpression ;
primaryExpression
: startNode (node)? -> ^(EXPRESSION startNode (node)?);
startNode
:
parenExpr
| methodOrProperty
| functionOrVar
| indexer
| literal
| type
| constructor
| projection
| selection
| firstSelection
| lastSelection
;
node
: ((DOT dottedNode) | nonDottedNode)+;
nonDottedNode
: indexer;
dottedNode
:
((methodOrProperty
| functionOrVar
| projection
| selection
| firstSelection
| lastSelection
))
;
functionOrVar
: (POUND ID LPAREN) => function
| var
;
function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs);
var : POUND id=ID -> ^(VARIABLEREF[$id]);
methodOrProperty
: (ID LPAREN) => id=ID methodArgs -> ^(METHOD[$id] methodArgs)
| property
;
// may have to preserve these commas to make it easier to offer suggestions in the right place
// mod at 9th feb 19:13 - added the second 'COMMA?' to allow for code completion "foo(A,"
// TODO need to preserve commas and then check for badly formed call later (optimizing tree walk) to disallow "foo(a,b,c,)"
methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!;
// If we match ID then create a node called PROPERTY_OR_FIELD and copy the id info into it.
// this means the propertyOrField.text is what id.text would have been, rather than having to
// access id as a child of the new node.
property: id=ID -> ^(PROPERTY_OR_FIELD[$id]);
indexer: LBRACKET r1=argument (COMMA r2=argument)* RBRACKET -> ^(INDEXER $r1 ($r2)*);
// argument;
// TODO make expression conditional with ? if want completion for when the RCURLY is missing
projection: PROJECT^ expression RBRACKET!;
selection: SELECT^ expression RBRACKET!;
firstSelection: SELECT_FIRST^ expression RBRACKET!;
lastSelection: SELECT_LAST^ expression RBRACKET!;
// TODO cope with array types
type: TYPE qualifiedId RPAREN -> ^(TYPEREF qualifiedId);
//type: TYPE tn=qualifiedId (LBRACKET RBRACKET)? (COMMA qid=qualifiedId)? RPAREN
constructor
: ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs)
;
ctorArgs
: LPAREN! (namedArgument (COMMA! namedArgument)*)? RPAREN!;
argument : expression;
namedArgument
: (ID ASSIGN) => id=ID ASSIGN expression
-> ^(NAMED_ARGUMENT[$id] expression)
| argument ;
qualifiedId : ID (DOT ID)* -> ^(QUALIFIED_IDENTIFIER ID*);
contextName : ID (DIV ID)* -> ^(QUALIFIED_IDENTIFIER ID*);
literal
: INTEGER_LITERAL
| STRING_LITERAL
| DQ_STRING_LITERAL
| boolLiteral
| NULL_LITERAL
| HEXADECIMAL_INTEGER_LITERAL
| REAL_LITERAL
;
boolLiteral: TRUE | FALSE;
INTEGER_LITERAL
: (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?;
HEXADECIMAL_INTEGER_LITERAL : ('0x' | '0X') (HEX_DIGIT)+ (INTEGER_TYPE_SUFFIX)?;
relationalOperator
: EQUAL
| NOT_EQUAL
| LESS_THAN
| LESS_THAN_OR_EQUAL
| GREATER_THAN
| GREATER_THAN_OR_EQUAL
| INSTANCEOF
| BETWEEN
| MATCHES
;
ASSIGN: '=';
EQUAL: '==';
NOT_EQUAL: '!=';
LESS_THAN: '<';
LESS_THAN_OR_EQUAL: '<=';
GREATER_THAN: '>';
GREATER_THAN_OR_EQUAL: '>=';
INSTANCEOF: 'instanceof';
BETWEEN:'between';
MATCHES:'matches';
NULL_LITERAL: 'null';
SEMI: ';';
DOT: '.';
COMMA: ',';
LPAREN: '(';
RPAREN: ')';
LCURLY: '{';
RCURLY: '}';
LBRACKET: '[';
RBRACKET: ']';
PIPE: '|';
AND: 'and';
OR: 'or';
FALSE: 'false';
TRUE: 'true';
PLUS: '+';
MINUS: '-';
DIV: '/';
STAR: '*';
MOD: '%';
POWER: '^';
BANG: '!';
POUND: '#';
QMARK: '?';
DEFAULT: '??';
PROJECT: '![';
SELECT: '?[';
SELECT_FIRST: '^[';
SELECT_LAST: '$[';
TYPE: 'T(';
STRING_LITERAL: '\''! (APOS|~'\'')* '\''!;
DQ_STRING_LITERAL: '"'! (~'"')* '"'!;
ID: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|DOT_ESCAPED)*;
DOT_ESCAPED: '\\.';
WS: ( ' ' | '\t' | '\n' |'\r')+ { $channel=HIDDEN; } ;
DOLLAR: '$';
AT: '@';
UPTO: '..';
COLON: ':';
REAL_LITERAL :
('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) |
((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX));
fragment APOS : '\''! '\'';
fragment DECIMAL_DIGIT : '0'..'9' ;
fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' );
fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f';
fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ;
fragment SIGN : '+' | '-' ;
fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd';
grammar SpringExpressions;
options {
language = Java;
output=AST;
k=2;
}
tokens {
INTEGER_LITERAL;
EXPRESSION;
QUALIFIED_IDENTIFIER;
PROPERTY_OR_FIELD;
INDEXER;
CONSTRUCTOR;
HOLDER;
NAMED_ARGUMENT;
FUNCTIONREF;
TYPEREF;
VARIABLEREF;
METHOD;
ADD;
SUBTRACT;
NUMBER;
}
// applies only to the parser:
@header {package org.springframework.expression.spel.generated;}
// applies only to the lexer:
@lexer::header {package org.springframework.expression.spel.generated;}
@members {
// For collecting info whilst processing rules that can be used in messages
protected Stack<String> paraphrase = new Stack<String>();
}
@rulecatch {
catch(RecognitionException e) {
reportError(e);
throw e;
}
}
expr: expression EOF!;
expression :
logicalOrExpression
( (ASSIGN^ logicalOrExpression)
| (DEFAULT^ logicalOrExpression)
| (QMARK^ expression COLON! expression))?;
parenExpr : LPAREN! expression RPAREN!;
logicalOrExpression
: logicalAndExpression (OR^ logicalAndExpression)*;
logicalAndExpression
: relationalExpression (AND^ relationalExpression)*;
relationalExpression : sumExpression (relationalOperator^ sumExpression)?;
sumExpression
: productExpression ( (PLUS^ | MINUS^) productExpression)*;
productExpression
: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ;
powerExpr : unaryExpression (POWER^ unaryExpression)? ;
unaryExpression
: (PLUS^ | MINUS^ | BANG^) unaryExpression
| primaryExpression ;
primaryExpression
: startNode (node)? -> ^(EXPRESSION startNode (node)?);
startNode
:
parenExpr
| methodOrProperty
| functionOrVar
| indexer
| literal
| type
| constructor
| projection
| selection
| firstSelection
| lastSelection
;
node
: ((DOT dottedNode) | nonDottedNode)+;
nonDottedNode
: indexer;
dottedNode
:
((methodOrProperty
| functionOrVar
| projection
| selection
| firstSelection
| lastSelection
))
;
functionOrVar
: (POUND ID LPAREN) => function
| var
;
function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs);
var : POUND id=ID -> ^(VARIABLEREF[$id]);
methodOrProperty
: (ID LPAREN) => id=ID methodArgs -> ^(METHOD[$id] methodArgs)
| property
;
// may have to preserve these commas to make it easier to offer suggestions in the right place
// mod at 9th feb 19:13 - added the second 'COMMA?' to allow for code completion "foo(A,"
// TODO need to preserve commas and then check for badly formed call later (optimizing tree walk) to disallow "foo(a,b,c,)"
methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!;
// If we match ID then create a node called PROPERTY_OR_FIELD and copy the id info into it.
// this means the propertyOrField.text is what id.text would have been, rather than having to
// access id as a child of the new node.
property: id=ID -> ^(PROPERTY_OR_FIELD[$id]);
indexer: LBRACKET r1=argument (COMMA r2=argument)* RBRACKET -> ^(INDEXER $r1 ($r2)*);
// argument;
// TODO make expression conditional with ? if want completion for when the RCURLY is missing
projection: PROJECT^ expression RBRACKET!;
selection: SELECT^ expression RBRACKET!;
firstSelection: SELECT_FIRST^ expression RBRACKET!;
lastSelection: SELECT_LAST^ expression RBRACKET!;
// TODO cope with array types
type: TYPE qualifiedId RPAREN -> ^(TYPEREF qualifiedId);
//type: TYPE tn=qualifiedId (LBRACKET RBRACKET)? (COMMA qid=qualifiedId)? RPAREN
constructor
: ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs)
;
ctorArgs
: LPAREN! (namedArgument (COMMA! namedArgument)*)? RPAREN!;
argument : expression;
namedArgument
: (ID ASSIGN) => id=ID ASSIGN expression
-> ^(NAMED_ARGUMENT[$id] expression)
| argument ;
qualifiedId : ID (DOT ID)* -> ^(QUALIFIED_IDENTIFIER ID*);
contextName : ID (DIV ID)* -> ^(QUALIFIED_IDENTIFIER ID*);
literal
: INTEGER_LITERAL
| STRING_LITERAL
| DQ_STRING_LITERAL
| boolLiteral
| NULL_LITERAL
| HEXADECIMAL_INTEGER_LITERAL
| REAL_LITERAL
;
boolLiteral: TRUE | FALSE;
INTEGER_LITERAL
: (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?;
HEXADECIMAL_INTEGER_LITERAL : ('0x' | '0X') (HEX_DIGIT)+ (INTEGER_TYPE_SUFFIX)?;
relationalOperator
: EQUAL
| NOT_EQUAL
| LESS_THAN
| LESS_THAN_OR_EQUAL
| GREATER_THAN
| GREATER_THAN_OR_EQUAL
| INSTANCEOF
| BETWEEN
| MATCHES
;
ASSIGN: '=';
EQUAL: '==';
NOT_EQUAL: '!=';
LESS_THAN: '<';
LESS_THAN_OR_EQUAL: '<=';
GREATER_THAN: '>';
GREATER_THAN_OR_EQUAL: '>=';
INSTANCEOF: 'instanceof';
BETWEEN:'between';
MATCHES:'matches';
NULL_LITERAL: 'null';
SEMI: ';';
DOT: '.';
COMMA: ',';
LPAREN: '(';
RPAREN: ')';
LCURLY: '{';
RCURLY: '}';
LBRACKET: '[';
RBRACKET: ']';
PIPE: '|';
AND: 'and';
OR: 'or';
FALSE: 'false';
TRUE: 'true';
PLUS: '+';
MINUS: '-';
DIV: '/';
STAR: '*';
MOD: '%';
POWER: '^';
BANG: '!';
POUND: '#';
QMARK: '?';
DEFAULT: '??';
PROJECT: '![';
SELECT: '?[';
SELECT_FIRST: '^[';
SELECT_LAST: '$[';
TYPE: 'T(';
STRING_LITERAL: '\''! (APOS|~'\'')* '\''!;
DQ_STRING_LITERAL: '"'! (~'"')* '"'!;
ID: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|DOT_ESCAPED)*;
DOT_ESCAPED: '\\.';
WS: ( ' ' | '\t' | '\n' |'\r')+ { $channel=HIDDEN; } ;
DOLLAR: '$';
AT: '@';
UPTO: '..';
COLON: ':';
REAL_LITERAL :
('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) |
((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX));
fragment APOS : '\''! '\'';
fragment DECIMAL_DIGIT : '0'..'9' ;
fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' );
fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f';
fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ;
fragment SIGN : '+' | '-' ;
fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd';

View File

@@ -1,63 +1,63 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.standard;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateAwareExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.util.Assert;
/**
* SpEL parser. Instances are reusable and thread-safe.
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
public class SpelExpressionParser extends TemplateAwareExpressionParser {
private final SpelParserConfiguration configuration;
/**
* Create a parser with standard configuration.
*/
public SpelExpressionParser() {
this.configuration = new SpelParserConfiguration(false, false);
}
/**
* Create a parser with some configured behavior.
* @param configuration custom configuration options
*/
public SpelExpressionParser(SpelParserConfiguration configuration) {
Assert.notNull(configuration, "SpelParserConfiguration must not be null");
this.configuration = configuration;
}
@Override
protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context);
}
public SpelExpression parseRaw(String expressionString) throws ParseException {
return doParseExpression(expressionString, null);
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.standard;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateAwareExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.util.Assert;
/**
* SpEL parser. Instances are reusable and thread-safe.
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
public class SpelExpressionParser extends TemplateAwareExpressionParser {
private final SpelParserConfiguration configuration;
/**
* Create a parser with standard configuration.
*/
public SpelExpressionParser() {
this.configuration = new SpelParserConfiguration(false, false);
}
/**
* Create a parser with some configured behavior.
* @param configuration custom configuration options
*/
public SpelExpressionParser(SpelParserConfiguration configuration) {
Assert.notNull(configuration, "SpelParserConfiguration must not be null");
this.configuration = configuration;
}
@Override
protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context);
}
public SpelExpression parseRaw(String expressionString) throws ParseException {
return doParseExpression(expressionString, null);
}
}

View File

@@ -1,87 +1,87 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.standard;
/**
* Holder for a kind of token, the associated data and its position in the input data stream (start/end).
*
* @author Andy Clement
* @since 3.0
*/
class Token {
TokenKind kind;
String data;
int startpos; // index of first character
int endpos; // index of char after the last character
/**
* Constructor for use when there is no particular data for the token (eg. TRUE or '+')
* @param startpos the exact start
* @param endpos the index to the last character
*/
Token(TokenKind tokenKind, int startpos, int endpos) {
this.kind = tokenKind;
this.startpos = startpos;
this.endpos = endpos;
}
Token(TokenKind tokenKind, char[] tokenData, int pos, int endpos) {
this(tokenKind,pos,endpos);
this.data = new String(tokenData);
}
public TokenKind getKind() {
return kind;
}
public String toString() {
StringBuilder s = new StringBuilder();
s.append("[").append(kind.toString());
if (kind.hasPayload()) {
s.append(":").append(data);
}
s.append("]");
s.append("(").append(startpos).append(",").append(endpos).append(")");
return s.toString();
}
public boolean isIdentifier() {
return kind==TokenKind.IDENTIFIER;
}
public boolean isNumericRelationalOperator() {
return kind==TokenKind.GT || kind==TokenKind.GE || kind==TokenKind.LT || kind==TokenKind.LE || kind==TokenKind.EQ || kind==TokenKind.NE;
}
public String stringValue() {
return data;
}
public Token asInstanceOfToken() {
return new Token(TokenKind.INSTANCEOF,startpos,endpos);
}
public Token asMatchesToken() {
return new Token(TokenKind.MATCHES,startpos,endpos);
}
public Token asBetweenToken() {
return new Token(TokenKind.BETWEEN,startpos,endpos);
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.standard;
/**
* Holder for a kind of token, the associated data and its position in the input data stream (start/end).
*
* @author Andy Clement
* @since 3.0
*/
class Token {
TokenKind kind;
String data;
int startpos; // index of first character
int endpos; // index of char after the last character
/**
* Constructor for use when there is no particular data for the token (eg. TRUE or '+')
* @param startpos the exact start
* @param endpos the index to the last character
*/
Token(TokenKind tokenKind, int startpos, int endpos) {
this.kind = tokenKind;
this.startpos = startpos;
this.endpos = endpos;
}
Token(TokenKind tokenKind, char[] tokenData, int pos, int endpos) {
this(tokenKind,pos,endpos);
this.data = new String(tokenData);
}
public TokenKind getKind() {
return kind;
}
public String toString() {
StringBuilder s = new StringBuilder();
s.append("[").append(kind.toString());
if (kind.hasPayload()) {
s.append(":").append(data);
}
s.append("]");
s.append("(").append(startpos).append(",").append(endpos).append(")");
return s.toString();
}
public boolean isIdentifier() {
return kind==TokenKind.IDENTIFIER;
}
public boolean isNumericRelationalOperator() {
return kind==TokenKind.GT || kind==TokenKind.GE || kind==TokenKind.LT || kind==TokenKind.LE || kind==TokenKind.EQ || kind==TokenKind.NE;
}
public String stringValue() {
return data;
}
public Token asInstanceOfToken() {
return new Token(TokenKind.INSTANCEOF,startpos,endpos);
}
public Token asMatchesToken() {
return new Token(TokenKind.MATCHES,startpos,endpos);
}
public Token asBetweenToken() {
return new Token(TokenKind.BETWEEN,startpos,endpos);
}
}

View File

@@ -1,58 +1,58 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.standard;
/**
* @author Andy Clement
* @since 3.0
*/
enum TokenKind {
// ordered by priority - operands first
LITERAL_INT, LITERAL_LONG, LITERAL_HEXINT, LITERAL_HEXLONG, LITERAL_STRING, LITERAL_REAL, LITERAL_REAL_FLOAT,
LPAREN("("), RPAREN(")"), COMMA(","), IDENTIFIER,
COLON(":"),HASH("#"),RSQUARE("]"), LSQUARE("["),
LCURLY("{"),RCURLY("}"),
DOT("."), PLUS("+"), STAR("*"), MINUS("-"), SELECT_FIRST("^["), SELECT_LAST("$["), QMARK("?"), PROJECT("!["),
DIV("/"), GE(">="), GT(">"), LE("<="), LT("<"), EQ("=="), NE("!="),
MOD("%"), NOT("!"), ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"),
SELECT("?["), POWER("^"),
ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@")
;
char[] tokenChars;
private boolean hasPayload; // is there more to this token than simply the kind
private TokenKind(String tokenString) {
tokenChars = tokenString.toCharArray();
hasPayload = tokenChars.length==0;
}
private TokenKind() {
this("");
}
public String toString() {
return this.name()+(tokenChars.length!=0?"("+new String(tokenChars)+")":"");
}
public boolean hasPayload() {
return hasPayload;
}
public int getLength() {
return tokenChars.length;
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.standard;
/**
* @author Andy Clement
* @since 3.0
*/
enum TokenKind {
// ordered by priority - operands first
LITERAL_INT, LITERAL_LONG, LITERAL_HEXINT, LITERAL_HEXLONG, LITERAL_STRING, LITERAL_REAL, LITERAL_REAL_FLOAT,
LPAREN("("), RPAREN(")"), COMMA(","), IDENTIFIER,
COLON(":"),HASH("#"),RSQUARE("]"), LSQUARE("["),
LCURLY("{"),RCURLY("}"),
DOT("."), PLUS("+"), STAR("*"), MINUS("-"), SELECT_FIRST("^["), SELECT_LAST("$["), QMARK("?"), PROJECT("!["),
DIV("/"), GE(">="), GT(">"), LE("<="), LT("<"), EQ("=="), NE("!="),
MOD("%"), NOT("!"), ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"),
SELECT("?["), POWER("^"),
ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@")
;
char[] tokenChars;
private boolean hasPayload; // is there more to this token than simply the kind
private TokenKind(String tokenString) {
tokenChars = tokenString.toCharArray();
hasPayload = tokenChars.length==0;
}
private TokenKind() {
this("");
}
public String toString() {
return this.name()+(tokenChars.length!=0?"("+new String(tokenChars)+")":"");
}
public boolean hasPayload() {
return hasPayload;
}
public int getLength() {
return tokenChars.length;
}
}

View File

@@ -1,46 +1,46 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import org.springframework.expression.TypedValue;
/**
* @author Andy Clement
* @since 3.0
*/
public class BooleanTypedValue extends TypedValue {
public static final BooleanTypedValue TRUE = new BooleanTypedValue(true);
public static final BooleanTypedValue FALSE = new BooleanTypedValue(false);
private BooleanTypedValue(boolean b) {
super(b);
}
public static BooleanTypedValue forValue(boolean b) {
if (b) {
return TRUE;
}
else {
return FALSE;
}
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import org.springframework.expression.TypedValue;
/**
* @author Andy Clement
* @since 3.0
*/
public class BooleanTypedValue extends TypedValue {
public static final BooleanTypedValue TRUE = new BooleanTypedValue(true);
public static final BooleanTypedValue FALSE = new BooleanTypedValue(false);
private BooleanTypedValue(boolean b) {
super(b);
}
public static BooleanTypedValue forValue(boolean b) {
if (b) {
return TRUE;
}
else {
return FALSE;
}
}
}

View File

@@ -1,74 +1,74 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.lang.reflect.Constructor;
import org.springframework.expression.AccessException;
import org.springframework.expression.ConstructorExecutor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.TypedValue;
import org.springframework.util.ReflectionUtils;
/**
* A simple ConstructorExecutor implementation that runs a constructor using reflective invocation.
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
class ReflectiveConstructorExecutor implements ConstructorExecutor {
private final Constructor<?> ctor;
private final Integer varargsPosition;
// When the constructor was found, we will have determined if arguments need to be converted for it
// to be invoked. Conversion won't be cheap so let's only do it if necessary.
private final int[] argsRequiringConversion;
public ReflectiveConstructorExecutor(Constructor<?> ctor, int[] argsRequiringConversion) {
this.ctor = ctor;
if (ctor.isVarArgs()) {
Class[] paramTypes = ctor.getParameterTypes();
this.varargsPosition = paramTypes.length - 1;
}
else {
this.varargsPosition = null;
}
this.argsRequiringConversion = argsRequiringConversion;
}
public TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException {
try {
if (arguments != null) {
ReflectionHelper.convertArguments(context.getTypeConverter(), arguments,
this.ctor, this.argsRequiringConversion, this.varargsPosition);
}
if (this.ctor.isVarArgs()) {
arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.ctor.getParameterTypes(), arguments);
}
ReflectionUtils.makeAccessible(this.ctor);
return new TypedValue(this.ctor.newInstance(arguments));
}
catch (Exception ex) {
throw new AccessException("Problem invoking constructor: " + this.ctor, ex);
}
}
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.lang.reflect.Constructor;
import org.springframework.expression.AccessException;
import org.springframework.expression.ConstructorExecutor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.TypedValue;
import org.springframework.util.ReflectionUtils;
/**
* A simple ConstructorExecutor implementation that runs a constructor using reflective invocation.
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
class ReflectiveConstructorExecutor implements ConstructorExecutor {
private final Constructor<?> ctor;
private final Integer varargsPosition;
// When the constructor was found, we will have determined if arguments need to be converted for it
// to be invoked. Conversion won't be cheap so let's only do it if necessary.
private final int[] argsRequiringConversion;
public ReflectiveConstructorExecutor(Constructor<?> ctor, int[] argsRequiringConversion) {
this.ctor = ctor;
if (ctor.isVarArgs()) {
Class[] paramTypes = ctor.getParameterTypes();
this.varargsPosition = paramTypes.length - 1;
}
else {
this.varargsPosition = null;
}
this.argsRequiringConversion = argsRequiringConversion;
}
public TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException {
try {
if (arguments != null) {
ReflectionHelper.convertArguments(context.getTypeConverter(), arguments,
this.ctor, this.argsRequiringConversion, this.varargsPosition);
}
if (this.ctor.isVarArgs()) {
arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.ctor.getParameterTypes(), arguments);
}
ReflectionUtils.makeAccessible(this.ctor);
return new TypedValue(this.ctor.newInstance(arguments));
}
catch (Exception ex) {
throw new AccessException("Problem invoking constructor: " + this.ctor, ex);
}
}
}

View File

@@ -1,120 +1,120 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.springframework.core.MethodParameter;
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;
/**
* A constructor resolver that uses reflection to locate the constructor that should be invoked
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
public class ReflectiveConstructorResolver implements ConstructorResolver {
/**
* Locate a constructor on the type. There are three kinds of match that might occur:
* <ol>
* <li>An exact match where the types of the arguments match the types of the constructor
* <li>An in-exact match where the types we are looking for are subtypes of those defined on the constructor
* <li>A match where we are able to convert the arguments into those expected by the constructor, according to the
* registered type converter.
* </ol>
*/
public ConstructorExecutor resolve(EvaluationContext context, String typename, List<TypeDescriptor> argumentTypes)
throws AccessException {
try {
TypeConverter typeConverter = context.getTypeConverter();
Class<?> type = context.getTypeLocator().findType(typename);
Constructor[] ctors = type.getConstructors();
Arrays.sort(ctors, new Comparator<Constructor>() {
public int compare(Constructor c1, Constructor c2) {
int c1pl = c1.getParameterTypes().length;
int c2pl = c2.getParameterTypes().length;
return (new Integer(c1pl)).compareTo(c2pl);
}
});
Constructor closeMatch = null;
int[] argsToConvert = null;
Constructor matchRequiringConversion = null;
for (Constructor ctor : ctors) {
Class[] paramTypes = ctor.getParameterTypes();
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
for (int i = 0; i < paramTypes.length; i++) {
paramDescriptors.add(new TypeDescriptor(new MethodParameter(ctor, i)));
}
ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
if (ctor.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) {
// *sigh* complicated
// Basically.. we have to have all parameters match up until the varargs one, then the rest of what is
// being provided should be
// the same type whilst the final argument to the method must be an array of that (oh, how easy...not) -
// or the final parameter
// we are supplied does match exactly (it is an array already).
matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
}
else if (paramTypes.length == argumentTypes.size()) {
// worth a closer look
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
}
if (matchInfo != null) {
if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) {
return new ReflectiveConstructorExecutor(ctor, null);
}
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) {
closeMatch = ctor;
}
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.REQUIRES_CONVERSION) {
argsToConvert = matchInfo.argsRequiringConversion;
matchRequiringConversion = ctor;
}
}
}
if (closeMatch != null) {
return new ReflectiveConstructorExecutor(closeMatch, null);
}
else if (matchRequiringConversion != null) {
return new ReflectiveConstructorExecutor(matchRequiringConversion, argsToConvert);
}
else {
return null;
}
}
catch (EvaluationException ex) {
throw new AccessException("Failed to resolve constructor", ex);
}
}
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.springframework.core.MethodParameter;
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;
/**
* A constructor resolver that uses reflection to locate the constructor that should be invoked
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
public class ReflectiveConstructorResolver implements ConstructorResolver {
/**
* Locate a constructor on the type. There are three kinds of match that might occur:
* <ol>
* <li>An exact match where the types of the arguments match the types of the constructor
* <li>An in-exact match where the types we are looking for are subtypes of those defined on the constructor
* <li>A match where we are able to convert the arguments into those expected by the constructor, according to the
* registered type converter.
* </ol>
*/
public ConstructorExecutor resolve(EvaluationContext context, String typename, List<TypeDescriptor> argumentTypes)
throws AccessException {
try {
TypeConverter typeConverter = context.getTypeConverter();
Class<?> type = context.getTypeLocator().findType(typename);
Constructor[] ctors = type.getConstructors();
Arrays.sort(ctors, new Comparator<Constructor>() {
public int compare(Constructor c1, Constructor c2) {
int c1pl = c1.getParameterTypes().length;
int c2pl = c2.getParameterTypes().length;
return (new Integer(c1pl)).compareTo(c2pl);
}
});
Constructor closeMatch = null;
int[] argsToConvert = null;
Constructor matchRequiringConversion = null;
for (Constructor ctor : ctors) {
Class[] paramTypes = ctor.getParameterTypes();
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
for (int i = 0; i < paramTypes.length; i++) {
paramDescriptors.add(new TypeDescriptor(new MethodParameter(ctor, i)));
}
ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
if (ctor.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) {
// *sigh* complicated
// Basically.. we have to have all parameters match up until the varargs one, then the rest of what is
// being provided should be
// the same type whilst the final argument to the method must be an array of that (oh, how easy...not) -
// or the final parameter
// we are supplied does match exactly (it is an array already).
matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
}
else if (paramTypes.length == argumentTypes.size()) {
// worth a closer look
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
}
if (matchInfo != null) {
if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) {
return new ReflectiveConstructorExecutor(ctor, null);
}
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) {
closeMatch = ctor;
}
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.REQUIRES_CONVERSION) {
argsToConvert = matchInfo.argsRequiringConversion;
matchRequiringConversion = ctor;
}
}
}
if (closeMatch != null) {
return new ReflectiveConstructorExecutor(closeMatch, null);
}
else if (matchRequiringConversion != null) {
return new ReflectiveConstructorExecutor(matchRequiringConversion, argsToConvert);
}
else {
return null;
}
}
catch (EvaluationException ex) {
throw new AccessException("Failed to resolve constructor", ex);
}
}
}

View File

@@ -1,77 +1,77 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.lang.reflect.Method;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.MethodExecutor;
import org.springframework.expression.TypedValue;
import org.springframework.util.ReflectionUtils;
/**
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
class ReflectiveMethodExecutor implements MethodExecutor {
private final Method method;
private final Integer varargsPosition;
// When the method was found, we will have determined if arguments need to be converted for it
// to be invoked. Conversion won't be cheap so let's only do it if necessary.
private final int[] argsRequiringConversion;
public ReflectiveMethodExecutor(Method theMethod, int[] argumentsRequiringConversion) {
this.method = theMethod;
if (theMethod.isVarArgs()) {
Class[] paramTypes = theMethod.getParameterTypes();
this.varargsPosition = paramTypes.length - 1;
}
else {
this.varargsPosition = null;
}
this.argsRequiringConversion = argumentsRequiringConversion;
}
public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException {
try {
if (arguments != null) {
ReflectionHelper.convertArguments(
context.getTypeConverter(), arguments, this.method,
this.argsRequiringConversion, this.varargsPosition);
}
if (this.method.isVarArgs()) {
arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.method.getParameterTypes(), arguments);
}
ReflectionUtils.makeAccessible(this.method);
Object value = this.method.invoke(target, arguments);
return new TypedValue(value, new TypeDescriptor(new MethodParameter(this.method, -1)).narrow(value));
}
catch (Exception ex) {
throw new AccessException("Problem invoking method: " + this.method, ex);
}
}
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.lang.reflect.Method;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.MethodExecutor;
import org.springframework.expression.TypedValue;
import org.springframework.util.ReflectionUtils;
/**
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
class ReflectiveMethodExecutor implements MethodExecutor {
private final Method method;
private final Integer varargsPosition;
// When the method was found, we will have determined if arguments need to be converted for it
// to be invoked. Conversion won't be cheap so let's only do it if necessary.
private final int[] argsRequiringConversion;
public ReflectiveMethodExecutor(Method theMethod, int[] argumentsRequiringConversion) {
this.method = theMethod;
if (theMethod.isVarArgs()) {
Class[] paramTypes = theMethod.getParameterTypes();
this.varargsPosition = paramTypes.length - 1;
}
else {
this.varargsPosition = null;
}
this.argsRequiringConversion = argumentsRequiringConversion;
}
public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException {
try {
if (arguments != null) {
ReflectionHelper.convertArguments(
context.getTypeConverter(), arguments, this.method,
this.argsRequiringConversion, this.varargsPosition);
}
if (this.method.isVarArgs()) {
arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.method.getParameterTypes(), arguments);
}
ReflectionUtils.makeAccessible(this.method);
Object value = this.method.invoke(target, arguments);
return new TypedValue(value, new TypeDescriptor(new MethodParameter(this.method, -1)).narrow(value));
}
catch (Exception ex) {
throw new AccessException("Problem invoking method: " + this.method, ex);
}
}
}

View File

@@ -1,197 +1,197 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.MethodExecutor;
import org.springframework.expression.MethodFilter;
import org.springframework.expression.MethodResolver;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.CollectionUtils;
/**
* A method resolver that uses reflection to locate the method that should be invoked.
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
public class ReflectiveMethodResolver implements MethodResolver {
private static Method[] NO_METHODS = new Method[0];
private Map<Class<?>, MethodFilter> filters = null;
// Using distance will ensure a more accurate match is discovered,
// more closely following the Java rules.
private boolean useDistance = false;
public ReflectiveMethodResolver() {
}
/**
* This constructors allows the ReflectiveMethodResolver to be configured such that it will
* use a distance computation to check which is the better of two close matches (when there
* are multiple matches). Using the distance computation is intended to ensure matches
* are more closely representative of what a Java compiler would do when taking into
* account boxing/unboxing and whether the method candidates are declared to handle a
* supertype of the type (of the argument) being passed in.
* @param useDistance true if distance computation should be used when calculating matches
*/
public ReflectiveMethodResolver(boolean useDistance) {
this.useDistance = useDistance;
}
/**
* Locate a method on a type. There are three kinds of match that might occur:
* <ol>
* <li>An exact match where the types of the arguments match the types of the constructor
* <li>An in-exact match where the types we are looking for are subtypes of those defined on the constructor
* <li>A match where we are able to convert the arguments into those expected by the constructor,
* according to the registered type converter.
* </ol>
*/
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
List<TypeDescriptor> argumentTypes) throws AccessException {
try {
TypeConverter typeConverter = context.getTypeConverter();
Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass());
Method[] methods = type.getMethods();
// If a filter is registered for this type, call it
MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
if (filter != null) {
List<Method> methodsForFiltering = new ArrayList<Method>();
for (Method method: methods) {
methodsForFiltering.add(method);
}
List<Method> methodsFiltered = filter.filter(methodsForFiltering);
if (CollectionUtils.isEmpty(methodsFiltered)) {
methods = NO_METHODS;
}
else {
methods = methodsFiltered.toArray(new Method[methodsFiltered.size()]);
}
}
Arrays.sort(methods, new Comparator<Method>() {
public int compare(Method m1, Method m2) {
int m1pl = m1.getParameterTypes().length;
int m2pl = m2.getParameterTypes().length;
return (new Integer(m1pl)).compareTo(m2pl);
}
});
Method closeMatch = null;
int closeMatchDistance = Integer.MAX_VALUE;
int[] argsToConvert = null;
Method matchRequiringConversion = null;
boolean multipleOptions = false;
for (Method method : methods) {
if (method.isBridge()) {
continue;
}
if (method.getName().equals(name)) {
Class[] paramTypes = method.getParameterTypes();
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
for (int i = 0; i < paramTypes.length; i++) {
paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i)));
}
ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
if (method.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) {
// *sigh* complicated
matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
}
else if (paramTypes.length == argumentTypes.size()) {
// name and parameter number match, check the arguments
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
}
if (matchInfo != null) {
if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) {
return new ReflectiveMethodExecutor(method, null);
}
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) {
if (!useDistance) {
closeMatch = method;
} else {
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
if (matchDistance<closeMatchDistance) {
// this is a better match
closeMatchDistance = matchDistance;
closeMatch = method;
}
}
}
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.REQUIRES_CONVERSION) {
if (matchRequiringConversion != null) {
multipleOptions = true;
}
argsToConvert = matchInfo.argsRequiringConversion;
matchRequiringConversion = method;
}
}
}
}
if (closeMatch != null) {
return new ReflectiveMethodExecutor(closeMatch, null);
}
else if (matchRequiringConversion != null) {
if (multipleOptions) {
throw new SpelEvaluationException(SpelMessage.MULTIPLE_POSSIBLE_METHODS, name);
}
return new ReflectiveMethodExecutor(matchRequiringConversion, argsToConvert);
}
else {
return null;
}
}
catch (EvaluationException ex) {
throw new AccessException("Failed to resolve method", ex);
}
}
public void registerMethodFilter(Class<?> type, MethodFilter filter) {
if (this.filters == null) {
this.filters = new HashMap<Class<?>, MethodFilter>();
}
if (filter == null) {
this.filters.remove(type);
}
else {
this.filters.put(type,filter);
}
}
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.MethodExecutor;
import org.springframework.expression.MethodFilter;
import org.springframework.expression.MethodResolver;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.CollectionUtils;
/**
* A method resolver that uses reflection to locate the method that should be invoked.
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
public class ReflectiveMethodResolver implements MethodResolver {
private static Method[] NO_METHODS = new Method[0];
private Map<Class<?>, MethodFilter> filters = null;
// Using distance will ensure a more accurate match is discovered,
// more closely following the Java rules.
private boolean useDistance = false;
public ReflectiveMethodResolver() {
}
/**
* This constructors allows the ReflectiveMethodResolver to be configured such that it will
* use a distance computation to check which is the better of two close matches (when there
* are multiple matches). Using the distance computation is intended to ensure matches
* are more closely representative of what a Java compiler would do when taking into
* account boxing/unboxing and whether the method candidates are declared to handle a
* supertype of the type (of the argument) being passed in.
* @param useDistance true if distance computation should be used when calculating matches
*/
public ReflectiveMethodResolver(boolean useDistance) {
this.useDistance = useDistance;
}
/**
* Locate a method on a type. There are three kinds of match that might occur:
* <ol>
* <li>An exact match where the types of the arguments match the types of the constructor
* <li>An in-exact match where the types we are looking for are subtypes of those defined on the constructor
* <li>A match where we are able to convert the arguments into those expected by the constructor,
* according to the registered type converter.
* </ol>
*/
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
List<TypeDescriptor> argumentTypes) throws AccessException {
try {
TypeConverter typeConverter = context.getTypeConverter();
Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass());
Method[] methods = type.getMethods();
// If a filter is registered for this type, call it
MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
if (filter != null) {
List<Method> methodsForFiltering = new ArrayList<Method>();
for (Method method: methods) {
methodsForFiltering.add(method);
}
List<Method> methodsFiltered = filter.filter(methodsForFiltering);
if (CollectionUtils.isEmpty(methodsFiltered)) {
methods = NO_METHODS;
}
else {
methods = methodsFiltered.toArray(new Method[methodsFiltered.size()]);
}
}
Arrays.sort(methods, new Comparator<Method>() {
public int compare(Method m1, Method m2) {
int m1pl = m1.getParameterTypes().length;
int m2pl = m2.getParameterTypes().length;
return (new Integer(m1pl)).compareTo(m2pl);
}
});
Method closeMatch = null;
int closeMatchDistance = Integer.MAX_VALUE;
int[] argsToConvert = null;
Method matchRequiringConversion = null;
boolean multipleOptions = false;
for (Method method : methods) {
if (method.isBridge()) {
continue;
}
if (method.getName().equals(name)) {
Class[] paramTypes = method.getParameterTypes();
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
for (int i = 0; i < paramTypes.length; i++) {
paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i)));
}
ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
if (method.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) {
// *sigh* complicated
matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
}
else if (paramTypes.length == argumentTypes.size()) {
// name and parameter number match, check the arguments
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
}
if (matchInfo != null) {
if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) {
return new ReflectiveMethodExecutor(method, null);
}
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) {
if (!useDistance) {
closeMatch = method;
} else {
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
if (matchDistance<closeMatchDistance) {
// this is a better match
closeMatchDistance = matchDistance;
closeMatch = method;
}
}
}
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.REQUIRES_CONVERSION) {
if (matchRequiringConversion != null) {
multipleOptions = true;
}
argsToConvert = matchInfo.argsRequiringConversion;
matchRequiringConversion = method;
}
}
}
}
if (closeMatch != null) {
return new ReflectiveMethodExecutor(closeMatch, null);
}
else if (matchRequiringConversion != null) {
if (multipleOptions) {
throw new SpelEvaluationException(SpelMessage.MULTIPLE_POSSIBLE_METHODS, name);
}
return new ReflectiveMethodExecutor(matchRequiringConversion, argsToConvert);
}
else {
return null;
}
}
catch (EvaluationException ex) {
throw new AccessException("Failed to resolve method", ex);
}
}
public void registerMethodFilter(Class<?> type, MethodFilter filter) {
if (this.filters == null) {
this.filters = new HashMap<Class<?>, MethodFilter>();
}
if (filter == null) {
this.filters.remove(type);
}
else {
this.filters.put(type,filter);
}
}
}

View File

@@ -1,38 +1,38 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation;
import org.springframework.expression.OperatorOverloader;
/**
* @author Juergen Hoeller
* @since 3.0
*/
public class StandardOperatorOverloader implements OperatorOverloader {
public boolean overridesOperation(Operation operation, Object leftOperand, Object rightOperand)
throws EvaluationException {
return false;
}
public Object operate(Operation operation, Object leftOperand, Object rightOperand) throws EvaluationException {
throw new EvaluationException("No operation overloaded by default");
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation;
import org.springframework.expression.OperatorOverloader;
/**
* @author Juergen Hoeller
* @since 3.0
*/
public class StandardOperatorOverloader implements OperatorOverloader {
public boolean overridesOperation(Operation operation, Object leftOperand, Object rightOperand)
throws EvaluationException {
return false;
}
public Object operate(Operation operation, Object leftOperand, Object rightOperand) throws EvaluationException {
throw new EvaluationException("No operation overloaded by default");
}
}

View File

@@ -1,76 +1,76 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.Assert;
/**
* Default implementation of the {@link TypeConverter} interface,
* delegating to a core Spring {@link ConversionService}.
*
* @author Juergen Hoeller
* @author Andy Clement
* @since 3.0
* @see org.springframework.core.convert.ConversionService
*/
public class StandardTypeConverter implements TypeConverter {
private static ConversionService defaultConversionService;
private final ConversionService conversionService;
public StandardTypeConverter() {
synchronized (this) {
if (defaultConversionService == null) {
defaultConversionService = new DefaultConversionService();
}
}
this.conversionService = defaultConversionService;
}
public StandardTypeConverter(ConversionService conversionService) {
Assert.notNull(conversionService, "ConversionService must not be null");
this.conversionService = conversionService;
}
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType, targetType);
}
public Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType) {
try {
return this.conversionService.convert(value, sourceType, targetType);
}
catch (ConverterNotFoundException cenfe) {
throw new SpelEvaluationException(cenfe, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString());
}
catch (ConversionException ce) {
throw new SpelEvaluationException(ce, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString());
}
}
}
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.Assert;
/**
* Default implementation of the {@link TypeConverter} interface,
* delegating to a core Spring {@link ConversionService}.
*
* @author Juergen Hoeller
* @author Andy Clement
* @since 3.0
* @see org.springframework.core.convert.ConversionService
*/
public class StandardTypeConverter implements TypeConverter {
private static ConversionService defaultConversionService;
private final ConversionService conversionService;
public StandardTypeConverter() {
synchronized (this) {
if (defaultConversionService == null) {
defaultConversionService = new DefaultConversionService();
}
}
this.conversionService = defaultConversionService;
}
public StandardTypeConverter(ConversionService conversionService) {
Assert.notNull(conversionService, "ConversionService must not be null");
this.conversionService = conversionService;
}
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType, targetType);
}
public Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType) {
try {
return this.conversionService.convert(value, sourceType, targetType);
}
catch (ConverterNotFoundException cenfe) {
throw new SpelEvaluationException(cenfe, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString());
}
catch (ConversionException ce) {
throw new SpelEvaluationException(ce, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString());
}
}
}

View File

@@ -1,58 +1,58 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
import java.io.PrintStream;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpression;
/**
* Utilities for working with Spring Expressions.
*
* @author Andy Clement
*/
public class SpelUtilities {
/**
* Output an indented representation of the expression syntax tree to the specified output stream.
* @param printStream the output stream to print into
* @param expression the expression to be displayed
*/
public static void printAbstractSyntaxTree(PrintStream printStream, Expression expression) {
printStream.println("===> Expression '" + expression.getExpressionString() + "' - AST start");
printAST(printStream, ((SpelExpression) expression).getAST(), "");
printStream.println("===> Expression '" + expression.getExpressionString() + "' - AST end");
}
/*
* Helper method for printing the AST with indentation
*/
private static void printAST(PrintStream out, SpelNode t, String indent) {
if (t != null) {
StringBuilder sb = new StringBuilder();
sb.append(indent).append(t.getClass().getSimpleName());
sb.append(" value:").append(t.toStringAST());
sb.append(t.getChildCount() < 2 ? "" : " #children:" + t.getChildCount());
out.println(sb.toString());
for (int i = 0; i < t.getChildCount(); i++) {
printAST(out, t.getChild(i), indent + " ");
}
}
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
import java.io.PrintStream;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpression;
/**
* Utilities for working with Spring Expressions.
*
* @author Andy Clement
*/
public class SpelUtilities {
/**
* Output an indented representation of the expression syntax tree to the specified output stream.
* @param printStream the output stream to print into
* @param expression the expression to be displayed
*/
public static void printAbstractSyntaxTree(PrintStream printStream, Expression expression) {
printStream.println("===> Expression '" + expression.getExpressionString() + "' - AST start");
printAST(printStream, ((SpelExpression) expression).getAST(), "");
printStream.println("===> Expression '" + expression.getExpressionString() + "' - AST end");
}
/*
* Helper method for printing the AST with indentation
*/
private static void printAST(PrintStream out, SpelNode t, String indent) {
if (t != null) {
StringBuilder sb = new StringBuilder();
sb.append(indent).append(t.getClass().getSimpleName());
sb.append(" value:").append(t.toStringAST());
sb.append(t.getChildCount() < 2 ? "" : " #children:" + t.getChildCount());
out.println(sb.toString());
for (int i = 0; i < t.getChildCount(); i++) {
printAST(out, t.getChild(i), indent + " ");
}
}
}
}

View File

@@ -1,44 +1,44 @@
/*
* Copyright 2002-2011 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.Arrays;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor;
import static org.junit.Assert.*;
/**
* @author Andy Wilkinson
*/
public class FormatHelperTests {
@Test
public void formatMethodWithSingleArgumentForMessage() {
String message = FormatHelper.formatMethodForMessage("foo", Arrays.asList(TypeDescriptor.forObject("a string")));
assertEquals("foo(java.lang.String)", message);
}
@Test
public void formatMethodWithMultipleArgumentsForMessage() {
String message = FormatHelper.formatMethodForMessage("foo", Arrays.asList(TypeDescriptor.forObject("a string"), TypeDescriptor.forObject(Integer.valueOf(5))));
assertEquals("foo(java.lang.String,java.lang.Integer)", message);
}
}
/*
* Copyright 2002-2011 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.Arrays;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor;
import static org.junit.Assert.*;
/**
* @author Andy Wilkinson
*/
public class FormatHelperTests {
@Test
public void formatMethodWithSingleArgumentForMessage() {
String message = FormatHelper.formatMethodForMessage("foo", Arrays.asList(TypeDescriptor.forObject("a string")));
assertEquals("foo(java.lang.String)", message);
}
@Test
public void formatMethodWithMultipleArgumentsForMessage() {
String message = FormatHelper.formatMethodForMessage("foo", Arrays.asList(TypeDescriptor.forObject("a string"), TypeDescriptor.forObject(Integer.valueOf(5))));
assertEquals("foo(java.lang.String,java.lang.Integer)", message);
}
}

View File

@@ -1,106 +1,106 @@
/*
* Copyright 2002-2010 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.standard;
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import org.junit.Test;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
/**
* @author Mark Fisher
*/
public class PropertiesConversionSpelTests {
private static final SpelExpressionParser parser = new SpelExpressionParser();
@Test
public void props() {
Properties props = new Properties();
props.setProperty("x", "1");
props.setProperty("y", "2");
props.setProperty("z", "3");
Expression expression = parser.parseExpression("foo(#props)");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("props", props);
String result = expression.getValue(context, new TestBean(), String.class);
assertEquals("123", result);
}
@Test
public void mapWithAllStringValues() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x", "1");
map.put("y", "2");
map.put("z", "3");
Expression expression = parser.parseExpression("foo(#props)");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("props", map);
String result = expression.getValue(context, new TestBean(), String.class);
assertEquals("123", result);
}
@Test
public void mapWithNonStringValue() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x", "1");
map.put("y", 2);
map.put("z", "3");
map.put("a", new UUID(1, 1));
Expression expression = parser.parseExpression("foo(#props)");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("props", map);
String result = expression.getValue(context, new TestBean(), String.class);
assertEquals("1null3", result);
}
@Test
public void customMapWithNonStringValue() {
CustomMap map = new CustomMap();
map.put("x", "1");
map.put("y", 2);
map.put("z", "3");
Expression expression = parser.parseExpression("foo(#props)");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("props", map);
String result = expression.getValue(context, new TestBean(), String.class);
assertEquals("1null3", result);
}
private static class TestBean {
@SuppressWarnings("unused")
public String foo(Properties props) {
return props.getProperty("x") + props.getProperty("y") + props.getProperty("z");
}
}
@SuppressWarnings("serial")
private static class CustomMap extends HashMap<String, Object> {
}
}
/*
* Copyright 2002-2010 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.standard;
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import org.junit.Test;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
/**
* @author Mark Fisher
*/
public class PropertiesConversionSpelTests {
private static final SpelExpressionParser parser = new SpelExpressionParser();
@Test
public void props() {
Properties props = new Properties();
props.setProperty("x", "1");
props.setProperty("y", "2");
props.setProperty("z", "3");
Expression expression = parser.parseExpression("foo(#props)");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("props", props);
String result = expression.getValue(context, new TestBean(), String.class);
assertEquals("123", result);
}
@Test
public void mapWithAllStringValues() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x", "1");
map.put("y", "2");
map.put("z", "3");
Expression expression = parser.parseExpression("foo(#props)");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("props", map);
String result = expression.getValue(context, new TestBean(), String.class);
assertEquals("123", result);
}
@Test
public void mapWithNonStringValue() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x", "1");
map.put("y", 2);
map.put("z", "3");
map.put("a", new UUID(1, 1));
Expression expression = parser.parseExpression("foo(#props)");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("props", map);
String result = expression.getValue(context, new TestBean(), String.class);
assertEquals("1null3", result);
}
@Test
public void customMapWithNonStringValue() {
CustomMap map = new CustomMap();
map.put("x", "1");
map.put("y", 2);
map.put("z", "3");
Expression expression = parser.parseExpression("foo(#props)");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("props", map);
String result = expression.getValue(context, new TestBean(), String.class);
assertEquals("1null3", result);
}
private static class TestBean {
@SuppressWarnings("unused")
public String foo(Properties props) {
return props.getProperty("x") + props.getProperty("y") + props.getProperty("z");
}
}
@SuppressWarnings("serial")
private static class CustomMap extends HashMap<String, Object> {
}
}

View File

@@ -1,370 +1,370 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.standard;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.ExpressionException;
import org.springframework.expression.ParseException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.SpelNode;
import org.springframework.expression.spel.SpelParseException;
import org.springframework.expression.spel.ast.OpAnd;
import org.springframework.expression.spel.ast.OpOr;
import org.springframework.expression.spel.support.StandardEvaluationContext;
/**
* @author Andy Clement
*/
public class SpelParserTests {
@Test
public void theMostBasic() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2");
Assert.assertNotNull(expr);
Assert.assertNotNull(expr.getAST());
Assert.assertEquals(2,expr.getValue());
Assert.assertEquals(Integer.class,expr.getValueType());
Assert.assertEquals(2,expr.getAST().getValue(null));
}
@Test
public void valueType() throws Exception {
SpelExpressionParser parser = new SpelExpressionParser();
EvaluationContext ctx = new StandardEvaluationContext();
Class c = parser.parseRaw("2").getValueType();
Assert.assertEquals(Integer.class,c);
c = parser.parseRaw("12").getValueType(ctx);
Assert.assertEquals(Integer.class,c);
c = parser.parseRaw("null").getValueType();
Assert.assertNull(c);
c = parser.parseRaw("null").getValueType(ctx);
Assert.assertNull(c);
Object o = parser.parseRaw("null").getValue(ctx,Integer.class);
Assert.assertNull(o);
}
@Test
public void whitespace() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2 + 3");
Assert.assertEquals(5,expr.getValue());
expr = parser.parseRaw("2 + 3");
Assert.assertEquals(5,expr.getValue());
expr = parser.parseRaw("2\n+ 3");
Assert.assertEquals(5,expr.getValue());
expr = parser.parseRaw("2\r\n+\t3");
Assert.assertEquals(5,expr.getValue());
}
@Test
public void arithmeticPlus1() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2+2");
Assert.assertNotNull(expr);
Assert.assertNotNull(expr.getAST());
Assert.assertEquals(4,expr.getValue());
}
@Test
public void arithmeticPlus2() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("37+41");
Assert.assertEquals(78,expr.getValue());
}
@Test
public void arithmeticMultiply1() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2*3");
Assert.assertNotNull(expr);
Assert.assertNotNull(expr.getAST());
// printAst(expr.getAST(),0);
Assert.assertEquals(6,expr.getValue());
}
@Test
public void arithmeticPrecedence1() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2*3+5");
Assert.assertEquals(11,expr.getValue());
}
@Test
public void generalExpressions() throws Exception {
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.MISSING_CONSTRUCTOR_ARGS,spe.getMessageCode());
Assert.assertEquals(10,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(3,");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode());
Assert.assertEquals(10,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(3");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode());
Assert.assertEquals(10,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode());
Assert.assertEquals(10,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("\"abc");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING,spe.getMessageCode());
Assert.assertEquals(0,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("'abc");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.NON_TERMINATING_QUOTED_STRING,spe.getMessageCode());
Assert.assertEquals(0,spe.getPosition());
}
}
@Test
public void arithmeticPrecedence2() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2+3*5");
Assert.assertEquals(17,expr.getValue());
}
@Test
public void arithmeticPrecedence3() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("3+10/2");
Assert.assertEquals(8,expr.getValue());
}
@Test
public void arithmeticPrecedence4() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("10/2+3");
Assert.assertEquals(8,expr.getValue());
}
@Test
public void arithmeticPrecedence5() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("(4+10)/2");
Assert.assertEquals(7,expr.getValue());
}
@Test
public void arithmeticPrecedence6() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("(3+2)*2");
Assert.assertEquals(10,expr.getValue());
}
@Test
public void booleanOperators() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("true");
Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false");
Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false and false");
Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true and (true or false)");
Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true and true or false");
Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!true");
Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!(false or true)");
Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class));
}
@Test
public void testStringLiterals() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'");
Assert.assertEquals("howdy",expr.getValue());
expr = new SpelExpressionParser().parseRaw("'hello '' world'");
Assert.assertEquals("hello ' world",expr.getValue());
}
@Test
public void testStringLiterals2() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'.substring(0,2)");
Assert.assertEquals("ho",expr.getValue());
}
@Test
public void testPositionalInformation() throws EvaluationException, ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("true and true or false");
SpelNode rootAst = expr.getAST();
OpOr operatorOr = (OpOr)rootAst;
OpAnd operatorAnd = (OpAnd)operatorOr.getLeftOperand();
SpelNode rightOrOperand = operatorOr.getRightOperand();
// check position for final 'false'
Assert.assertEquals(17, rightOrOperand.getStartPosition());
Assert.assertEquals(22, rightOrOperand.getEndPosition());
// check position for first 'true'
Assert.assertEquals(0, operatorAnd.getLeftOperand().getStartPosition());
Assert.assertEquals(4, operatorAnd.getLeftOperand().getEndPosition());
// check position for second 'true'
Assert.assertEquals(9, operatorAnd.getRightOperand().getStartPosition());
Assert.assertEquals(13, operatorAnd.getRightOperand().getEndPosition());
// check position for OperatorAnd
Assert.assertEquals(5, operatorAnd.getStartPosition());
Assert.assertEquals(8, operatorAnd.getEndPosition());
// check position for OperatorOr
Assert.assertEquals(14, operatorOr.getStartPosition());
Assert.assertEquals(16, operatorOr.getEndPosition());
}
@Test
public void testTokenKind() {
TokenKind tk = TokenKind.NOT;
Assert.assertFalse(tk.hasPayload());
Assert.assertEquals("NOT(!)",tk.toString());
tk = TokenKind.MINUS;
Assert.assertFalse(tk.hasPayload());
Assert.assertEquals("MINUS(-)",tk.toString());
tk = TokenKind.LITERAL_STRING;
Assert.assertEquals("LITERAL_STRING",tk.toString());
Assert.assertTrue(tk.hasPayload());
}
@Test
public void testToken() {
Token token = new Token(TokenKind.NOT,0,3);
Assert.assertEquals(TokenKind.NOT,token.kind);
Assert.assertEquals(0,token.startpos);
Assert.assertEquals(3,token.endpos);
Assert.assertEquals("[NOT(!)](0,3)",token.toString());
token = new Token(TokenKind.LITERAL_STRING,"abc".toCharArray(),0,3);
Assert.assertEquals(TokenKind.LITERAL_STRING,token.kind);
Assert.assertEquals(0,token.startpos);
Assert.assertEquals(3,token.endpos);
Assert.assertEquals("[LITERAL_STRING:abc](0,3)",token.toString());
}
@Test
public void testExceptions() {
ExpressionException exprEx = new ExpressionException("test");
Assert.assertEquals("test", exprEx.getMessage());
Assert.assertEquals("test", exprEx.toDetailedString());
exprEx = new ExpressionException("wibble","test");
Assert.assertEquals("test", exprEx.getMessage());
Assert.assertEquals("Expression 'wibble': test", exprEx.toDetailedString());
exprEx = new ExpressionException("wibble",3, "test");
Assert.assertEquals("test", exprEx.getMessage());
Assert.assertEquals("Expression 'wibble' @ 3: test", exprEx.toDetailedString());
}
@Test
public void testNumerics() {
checkNumber("2",2,Integer.class);
checkNumber("22",22,Integer.class);
checkNumber("+22",22,Integer.class);
checkNumber("-22",-22,Integer.class);
checkNumber("2L",2L,Long.class);
checkNumber("22l",22L,Long.class);
checkNumber("0x1",1,Integer.class);
checkNumber("0x1L",1L,Long.class);
checkNumber("0xa",10,Integer.class);
checkNumber("0xAL",10L,Long.class);
checkNumberError("0x",SpelMessage.NOT_AN_INTEGER);
checkNumberError("0xL",SpelMessage.NOT_A_LONG);
checkNumberError(".324",SpelMessage.UNEXPECTED_DATA_AFTER_DOT);
checkNumberError("3.4L",SpelMessage.REAL_CANNOT_BE_LONG);
// Number is parsed as a float, but immediately promoted to a double
checkNumber("3.5f",3.5d,Double.class);
checkNumber("1.2e3", 1.2e3d, Double.class);
checkNumber("1.2e+3", 1.2e3d, Double.class);
checkNumber("1.2e-3", 1.2e-3d, Double.class);
checkNumber("1.2e3", 1.2e3d, Double.class);
checkNumber("1.e+3", 1.e3d, Double.class);
checkNumber("1e+3", 1e3d, Double.class);
}
private void checkNumber(String expression, Object value, Class<?> type) {
try {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw(expression);
Object o = expr.getValue();
Assert.assertEquals(value,o);
Assert.assertEquals(type,o.getClass());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
private void checkNumberError(String expression, SpelMessage expectedMessage) {
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw(expression);
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(expectedMessage,spe.getMessageCode());
}
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.standard;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.ExpressionException;
import org.springframework.expression.ParseException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.SpelNode;
import org.springframework.expression.spel.SpelParseException;
import org.springframework.expression.spel.ast.OpAnd;
import org.springframework.expression.spel.ast.OpOr;
import org.springframework.expression.spel.support.StandardEvaluationContext;
/**
* @author Andy Clement
*/
public class SpelParserTests {
@Test
public void theMostBasic() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2");
Assert.assertNotNull(expr);
Assert.assertNotNull(expr.getAST());
Assert.assertEquals(2,expr.getValue());
Assert.assertEquals(Integer.class,expr.getValueType());
Assert.assertEquals(2,expr.getAST().getValue(null));
}
@Test
public void valueType() throws Exception {
SpelExpressionParser parser = new SpelExpressionParser();
EvaluationContext ctx = new StandardEvaluationContext();
Class c = parser.parseRaw("2").getValueType();
Assert.assertEquals(Integer.class,c);
c = parser.parseRaw("12").getValueType(ctx);
Assert.assertEquals(Integer.class,c);
c = parser.parseRaw("null").getValueType();
Assert.assertNull(c);
c = parser.parseRaw("null").getValueType(ctx);
Assert.assertNull(c);
Object o = parser.parseRaw("null").getValue(ctx,Integer.class);
Assert.assertNull(o);
}
@Test
public void whitespace() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2 + 3");
Assert.assertEquals(5,expr.getValue());
expr = parser.parseRaw("2 + 3");
Assert.assertEquals(5,expr.getValue());
expr = parser.parseRaw("2\n+ 3");
Assert.assertEquals(5,expr.getValue());
expr = parser.parseRaw("2\r\n+\t3");
Assert.assertEquals(5,expr.getValue());
}
@Test
public void arithmeticPlus1() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2+2");
Assert.assertNotNull(expr);
Assert.assertNotNull(expr.getAST());
Assert.assertEquals(4,expr.getValue());
}
@Test
public void arithmeticPlus2() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("37+41");
Assert.assertEquals(78,expr.getValue());
}
@Test
public void arithmeticMultiply1() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2*3");
Assert.assertNotNull(expr);
Assert.assertNotNull(expr.getAST());
// printAst(expr.getAST(),0);
Assert.assertEquals(6,expr.getValue());
}
@Test
public void arithmeticPrecedence1() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2*3+5");
Assert.assertEquals(11,expr.getValue());
}
@Test
public void generalExpressions() throws Exception {
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.MISSING_CONSTRUCTOR_ARGS,spe.getMessageCode());
Assert.assertEquals(10,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(3,");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode());
Assert.assertEquals(10,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(3");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode());
Assert.assertEquals(10,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode());
Assert.assertEquals(10,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("\"abc");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING,spe.getMessageCode());
Assert.assertEquals(0,spe.getPosition());
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("'abc");
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(SpelMessage.NON_TERMINATING_QUOTED_STRING,spe.getMessageCode());
Assert.assertEquals(0,spe.getPosition());
}
}
@Test
public void arithmeticPrecedence2() throws EvaluationException,ParseException {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2+3*5");
Assert.assertEquals(17,expr.getValue());
}
@Test
public void arithmeticPrecedence3() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("3+10/2");
Assert.assertEquals(8,expr.getValue());
}
@Test
public void arithmeticPrecedence4() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("10/2+3");
Assert.assertEquals(8,expr.getValue());
}
@Test
public void arithmeticPrecedence5() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("(4+10)/2");
Assert.assertEquals(7,expr.getValue());
}
@Test
public void arithmeticPrecedence6() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("(3+2)*2");
Assert.assertEquals(10,expr.getValue());
}
@Test
public void booleanOperators() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("true");
Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false");
Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false and false");
Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true and (true or false)");
Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true and true or false");
Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!true");
Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!(false or true)");
Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class));
}
@Test
public void testStringLiterals() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'");
Assert.assertEquals("howdy",expr.getValue());
expr = new SpelExpressionParser().parseRaw("'hello '' world'");
Assert.assertEquals("hello ' world",expr.getValue());
}
@Test
public void testStringLiterals2() throws EvaluationException,ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'.substring(0,2)");
Assert.assertEquals("ho",expr.getValue());
}
@Test
public void testPositionalInformation() throws EvaluationException, ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("true and true or false");
SpelNode rootAst = expr.getAST();
OpOr operatorOr = (OpOr)rootAst;
OpAnd operatorAnd = (OpAnd)operatorOr.getLeftOperand();
SpelNode rightOrOperand = operatorOr.getRightOperand();
// check position for final 'false'
Assert.assertEquals(17, rightOrOperand.getStartPosition());
Assert.assertEquals(22, rightOrOperand.getEndPosition());
// check position for first 'true'
Assert.assertEquals(0, operatorAnd.getLeftOperand().getStartPosition());
Assert.assertEquals(4, operatorAnd.getLeftOperand().getEndPosition());
// check position for second 'true'
Assert.assertEquals(9, operatorAnd.getRightOperand().getStartPosition());
Assert.assertEquals(13, operatorAnd.getRightOperand().getEndPosition());
// check position for OperatorAnd
Assert.assertEquals(5, operatorAnd.getStartPosition());
Assert.assertEquals(8, operatorAnd.getEndPosition());
// check position for OperatorOr
Assert.assertEquals(14, operatorOr.getStartPosition());
Assert.assertEquals(16, operatorOr.getEndPosition());
}
@Test
public void testTokenKind() {
TokenKind tk = TokenKind.NOT;
Assert.assertFalse(tk.hasPayload());
Assert.assertEquals("NOT(!)",tk.toString());
tk = TokenKind.MINUS;
Assert.assertFalse(tk.hasPayload());
Assert.assertEquals("MINUS(-)",tk.toString());
tk = TokenKind.LITERAL_STRING;
Assert.assertEquals("LITERAL_STRING",tk.toString());
Assert.assertTrue(tk.hasPayload());
}
@Test
public void testToken() {
Token token = new Token(TokenKind.NOT,0,3);
Assert.assertEquals(TokenKind.NOT,token.kind);
Assert.assertEquals(0,token.startpos);
Assert.assertEquals(3,token.endpos);
Assert.assertEquals("[NOT(!)](0,3)",token.toString());
token = new Token(TokenKind.LITERAL_STRING,"abc".toCharArray(),0,3);
Assert.assertEquals(TokenKind.LITERAL_STRING,token.kind);
Assert.assertEquals(0,token.startpos);
Assert.assertEquals(3,token.endpos);
Assert.assertEquals("[LITERAL_STRING:abc](0,3)",token.toString());
}
@Test
public void testExceptions() {
ExpressionException exprEx = new ExpressionException("test");
Assert.assertEquals("test", exprEx.getMessage());
Assert.assertEquals("test", exprEx.toDetailedString());
exprEx = new ExpressionException("wibble","test");
Assert.assertEquals("test", exprEx.getMessage());
Assert.assertEquals("Expression 'wibble': test", exprEx.toDetailedString());
exprEx = new ExpressionException("wibble",3, "test");
Assert.assertEquals("test", exprEx.getMessage());
Assert.assertEquals("Expression 'wibble' @ 3: test", exprEx.toDetailedString());
}
@Test
public void testNumerics() {
checkNumber("2",2,Integer.class);
checkNumber("22",22,Integer.class);
checkNumber("+22",22,Integer.class);
checkNumber("-22",-22,Integer.class);
checkNumber("2L",2L,Long.class);
checkNumber("22l",22L,Long.class);
checkNumber("0x1",1,Integer.class);
checkNumber("0x1L",1L,Long.class);
checkNumber("0xa",10,Integer.class);
checkNumber("0xAL",10L,Long.class);
checkNumberError("0x",SpelMessage.NOT_AN_INTEGER);
checkNumberError("0xL",SpelMessage.NOT_A_LONG);
checkNumberError(".324",SpelMessage.UNEXPECTED_DATA_AFTER_DOT);
checkNumberError("3.4L",SpelMessage.REAL_CANNOT_BE_LONG);
// Number is parsed as a float, but immediately promoted to a double
checkNumber("3.5f",3.5d,Double.class);
checkNumber("1.2e3", 1.2e3d, Double.class);
checkNumber("1.2e+3", 1.2e3d, Double.class);
checkNumber("1.2e-3", 1.2e-3d, Double.class);
checkNumber("1.2e3", 1.2e3d, Double.class);
checkNumber("1.e+3", 1.e3d, Double.class);
checkNumber("1e+3", 1e3d, Double.class);
}
private void checkNumber(String expression, Object value, Class<?> type) {
try {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw(expression);
Object o = expr.getValue();
Assert.assertEquals(value,o);
Assert.assertEquals(type,o.getClass());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
private void checkNumberError(String expression, SpelMessage expectedMessage) {
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw(expression);
Assert.fail();
} catch (ParseException e) {
Assert.assertTrue(e instanceof SpelParseException);
SpelParseException spe = (SpelParseException)e;
Assert.assertEquals(expectedMessage,spe.getMessageCode());
}
}
}

View File

@@ -1,79 +1,79 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation;
import org.springframework.expression.OperatorOverloader;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypeLocator;
public class StandardComponentsTests {
@Test
public void testStandardEvaluationContext() {
StandardEvaluationContext context = new StandardEvaluationContext();
Assert.assertNotNull(context.getTypeComparator());
TypeComparator tc = new StandardTypeComparator();
context.setTypeComparator(tc);
Assert.assertEquals(tc,context.getTypeComparator());
TypeLocator tl = new StandardTypeLocator();
context.setTypeLocator(tl);
Assert.assertEquals(tl,context.getTypeLocator());
}
@Test
public void testStandardOperatorOverloader() throws EvaluationException {
OperatorOverloader oo = new StandardOperatorOverloader();
Assert.assertFalse(oo.overridesOperation(Operation.ADD, null, null));
try {
oo.operate(Operation.ADD, 2, 3);
Assert.fail("should have failed");
} catch (EvaluationException e) {
// success
}
}
@Test
public void testStandardTypeLocator() {
StandardTypeLocator tl = new StandardTypeLocator();
List<String> prefixes = tl.getImportPrefixes();
Assert.assertEquals(1,prefixes.size());
tl.registerImport("java.util");
prefixes = tl.getImportPrefixes();
Assert.assertEquals(2,prefixes.size());
tl.removeImport("java.util");
prefixes = tl.getImportPrefixes();
Assert.assertEquals(1,prefixes.size());
}
@Test
public void testStandardTypeConverter() throws EvaluationException {
TypeConverter tc = new StandardTypeConverter();
tc.convertValue(3, TypeDescriptor.forObject(3), TypeDescriptor.valueOf(Double.class));
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.support;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation;
import org.springframework.expression.OperatorOverloader;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypeLocator;
public class StandardComponentsTests {
@Test
public void testStandardEvaluationContext() {
StandardEvaluationContext context = new StandardEvaluationContext();
Assert.assertNotNull(context.getTypeComparator());
TypeComparator tc = new StandardTypeComparator();
context.setTypeComparator(tc);
Assert.assertEquals(tc,context.getTypeComparator());
TypeLocator tl = new StandardTypeLocator();
context.setTypeLocator(tl);
Assert.assertEquals(tl,context.getTypeLocator());
}
@Test
public void testStandardOperatorOverloader() throws EvaluationException {
OperatorOverloader oo = new StandardOperatorOverloader();
Assert.assertFalse(oo.overridesOperation(Operation.ADD, null, null));
try {
oo.operate(Operation.ADD, 2, 3);
Assert.fail("should have failed");
} catch (EvaluationException e) {
// success
}
}
@Test
public void testStandardTypeLocator() {
StandardTypeLocator tl = new StandardTypeLocator();
List<String> prefixes = tl.getImportPrefixes();
Assert.assertEquals(1,prefixes.size());
tl.registerImport("java.util");
prefixes = tl.getImportPrefixes();
Assert.assertEquals(2,prefixes.size());
tl.removeImport("java.util");
prefixes = tl.getImportPrefixes();
Assert.assertEquals(1,prefixes.size());
}
@Test
public void testStandardTypeConverter() throws EvaluationException {
TypeConverter tc = new StandardTypeConverter();
tc.convertValue(3, TypeDescriptor.forObject(3), TypeDescriptor.valueOf(Double.class));
}
}

View File

@@ -1,21 +1,21 @@
package org.springframework.expression.spel.testresources;
import java.util.List;
public class TestAddress{
private String street;
private List<String> crossStreets;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public List<String> getCrossStreets() {
return crossStreets;
}
public void setCrossStreets(List<String> crossStreets) {
this.crossStreets = crossStreets;
}
}
package org.springframework.expression.spel.testresources;
import java.util.List;
public class TestAddress{
private String street;
private List<String> crossStreets;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public List<String> getCrossStreets() {
return crossStreets;
}
public void setCrossStreets(List<String> crossStreets) {
this.crossStreets = crossStreets;
}
}

View File

@@ -1,19 +1,19 @@
package org.springframework.expression.spel.testresources;
public class TestPerson {
private String name;
private TestAddress address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TestAddress getAddress() {
return address;
}
public void setAddress(TestAddress address) {
this.address = address;
}
package org.springframework.expression.spel.testresources;
public class TestPerson {
private String name;
private TestAddress address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TestAddress getAddress() {
return address;
}
public void setAddress(TestAddress address) {
this.address = address;
}
}