Updated to spring 3.0.6
This commit is contained in:
parent
f39f6ff692
commit
9fe01a9403
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
target/*
|
||||
.pmd
|
||||
target/*
|
||||
.pmd
|
||||
.scala_dependencies
|
||||
.settings/
|
||||
|
6
pom.xml
6
pom.xml
@ -19,6 +19,7 @@
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<scala.version>2.7.7</scala.version>
|
||||
<spring.version>3.0.6.RELEASE</spring.version>
|
||||
</properties>
|
||||
|
||||
<issueManagement>
|
||||
@ -189,6 +190,7 @@
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-library</artifactId>
|
||||
<version>${scala.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scalatest</groupId>
|
||||
@ -205,12 +207,12 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -1,97 +1,97 @@
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Provides some extension functions to create some basic collection types
|
||||
* inline in SpEL expressions.
|
||||
* These functions are automatically registered with {@link SpelHelper}.
|
||||
*
|
||||
* **See Also:**
|
||||
* [Spring Docs on extension functions](http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#expressions-ref-functions)
|
||||
* @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
|
||||
*/
|
||||
public final class ExtensionFunctions {
|
||||
|
||||
private ExtensionFunctions() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@link List} of the arguments provided.
|
||||
*
|
||||
* Example use: `"#list('one', 'two', 'three')"`
|
||||
* @param <T> Type of the arguments provided.
|
||||
* @param args Arguments to create list of.
|
||||
* @return An unmodifiable list of the arguments provided.
|
||||
*/
|
||||
public static <T> List<T> list(final T... args) {
|
||||
return unmodifiableList(Arrays.asList(args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@link Set} of the arguments provided.
|
||||
*
|
||||
* Example use: `"#set('one', 'two', 'three')"`
|
||||
* @param <T> Type of the arguments provided.
|
||||
* @param args Arguments to create set of.
|
||||
* @return An unmodifiable set of the arguments provided.
|
||||
*/
|
||||
public static <T> Set<T> set(final T... args) {
|
||||
return unmodifiableSet(new HashSet<T>(list(args)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@link Map} using the {@link List} of keys
|
||||
* provided as the first argument and the {@link List} of values provided
|
||||
* as the second argument.
|
||||
*
|
||||
* Example use: `"#map(#list('one', 'two', 'three'), #list(1, 2, 3))"`
|
||||
* @param <K> Type of the keys of the map.
|
||||
* @param <V> Type of the values of map.
|
||||
* @param keys List of the keys.
|
||||
* @param values List of the values.
|
||||
* @return A unmodifiable map created from the key and value lists.
|
||||
* @throws IllegalArgumentException if the number of keys and the number of
|
||||
* values is not equal.
|
||||
*/
|
||||
public static <K,V> Map<K,V> map(final List<? extends K> keys,
|
||||
final List<? extends V> values) {
|
||||
Assert.isTrue(keys.size() == values.size(),
|
||||
"There should be equal number of keys and values");
|
||||
Map<K,V> map = new HashMap<K,V>();
|
||||
int length = keys.size();
|
||||
for (int i = 0; i < length; i++) {
|
||||
map.put(keys.get(i), values.get(i));
|
||||
}
|
||||
return unmodifiableMap(map);
|
||||
}
|
||||
|
||||
}
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Provides some extension functions to create some basic collection types
|
||||
* inline in SpEL expressions.
|
||||
* These functions are automatically registered with {@link SpelHelper}.
|
||||
*
|
||||
* **See Also:**
|
||||
* [Spring Docs on extension functions](http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#expressions-ref-functions)
|
||||
* @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
|
||||
*/
|
||||
public final class ExtensionFunctions {
|
||||
|
||||
private ExtensionFunctions() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@link List} of the arguments provided.
|
||||
*
|
||||
* Example use: `"#list('one', 'two', 'three')"`
|
||||
* @param <T> Type of the arguments provided.
|
||||
* @param args Arguments to create list of.
|
||||
* @return An unmodifiable list of the arguments provided.
|
||||
*/
|
||||
public static <T> List<T> list(final T... args) {
|
||||
return unmodifiableList(Arrays.asList(args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@link Set} of the arguments provided.
|
||||
*
|
||||
* Example use: `"#set('one', 'two', 'three')"`
|
||||
* @param <T> Type of the arguments provided.
|
||||
* @param args Arguments to create set of.
|
||||
* @return An unmodifiable set of the arguments provided.
|
||||
*/
|
||||
public static <T> Set<T> set(final T... args) {
|
||||
return unmodifiableSet(new HashSet<T>(list(args)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@link Map} using the {@link List} of keys
|
||||
* provided as the first argument and the {@link List} of values provided
|
||||
* as the second argument.
|
||||
*
|
||||
* Example use: `"#map(#list('one', 'two', 'three'), #list(1, 2, 3))"`
|
||||
* @param <K> Type of the keys of the map.
|
||||
* @param <V> Type of the values of map.
|
||||
* @param keys List of the keys.
|
||||
* @param values List of the values.
|
||||
* @return A unmodifiable map created from the key and value lists.
|
||||
* @throws IllegalArgumentException if the number of keys and the number of
|
||||
* values is not equal.
|
||||
*/
|
||||
public static <K,V> Map<K,V> map(final List<? extends K> keys,
|
||||
final List<? extends V> values) {
|
||||
Assert.isTrue(keys.size() == values.size(),
|
||||
"There should be equal number of keys and values");
|
||||
Map<K,V> map = new HashMap<K,V>();
|
||||
int length = keys.size();
|
||||
for (int i = 0; i < length; i++) {
|
||||
map.put(keys.get(i), values.get(i));
|
||||
}
|
||||
return unmodifiableMap(map);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,48 +1,52 @@
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.ConstructorExecutor;
|
||||
import org.springframework.expression.ConstructorResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.spel.support.ReflectiveConstructorResolver;
|
||||
|
||||
final class ImplicitConstructorResolver implements
|
||||
ConstructorResolver {
|
||||
|
||||
private final ReflectiveConstructorResolver delegate = new ReflectiveConstructorResolver();
|
||||
|
||||
public ConstructorExecutor resolve(final EvaluationContext context,
|
||||
final String typeName, final Class<?>[] argumentTypes) throws AccessException {
|
||||
try {
|
||||
return delegate.resolve(context, typeName, argumentTypes);
|
||||
} catch (AccessException ex) {
|
||||
Object variable = ((SpelHelper) context.lookupVariable(SpelHelper.CONTEXT_LOOKUP_KEY))
|
||||
.lookupImplicitConstructor(typeName + Arrays.toString(argumentTypes));
|
||||
if (variable instanceof Constructor<?>) {
|
||||
Constructor<?> constructor = (Constructor<?>) variable;
|
||||
return delegate.resolve(context, constructor.getDeclaringClass().getName(), argumentTypes);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.ConstructorExecutor;
|
||||
import org.springframework.expression.ConstructorResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.spel.support.ReflectiveConstructorResolver;
|
||||
|
||||
final class ImplicitConstructorResolver implements
|
||||
ConstructorResolver {
|
||||
|
||||
private final ReflectiveConstructorResolver delegate = new ReflectiveConstructorResolver();
|
||||
|
||||
@Override
|
||||
public ConstructorExecutor resolve(
|
||||
final EvaluationContext context, final String typeName,
|
||||
final List<TypeDescriptor> argumentTypes)
|
||||
throws AccessException {
|
||||
try {
|
||||
return delegate.resolve(context, typeName, argumentTypes);
|
||||
} catch (AccessException ex) {
|
||||
Object variable = ((SpelHelper) context.lookupVariable(SpelHelper.CONTEXT_LOOKUP_KEY))
|
||||
.lookupImplicitConstructor(typeName + argumentTypes.toString());
|
||||
if (variable instanceof Constructor<?>) {
|
||||
Constructor<?> constructor = (Constructor<?>) variable;
|
||||
return delegate.resolve(context, constructor.getDeclaringClass().getName(), argumentTypes);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,113 +1,120 @@
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.MethodExecutor;
|
||||
import org.springframework.expression.MethodResolver;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.support.ReflectiveMethodResolver;
|
||||
|
||||
final class ImplicitMethodResolver implements MethodResolver {
|
||||
|
||||
private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
|
||||
new ConcurrentHashMap<String, MethodExecutor>();
|
||||
|
||||
private static final MethodExecutor NULL_ME = new MethodExecutor() {
|
||||
public TypedValue execute(final EvaluationContext context, final Object target,
|
||||
final Object... arguments) throws AccessException {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final class ImplicitMethodExecutor implements
|
||||
MethodExecutor {
|
||||
private final MethodExecutor executor;
|
||||
|
||||
public ImplicitMethodExecutor(final MethodExecutor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public TypedValue execute(final EvaluationContext context, final Object target,
|
||||
final Object... arguments) throws AccessException {
|
||||
Object[] modifiedArguments = new Object[arguments.length + 1];
|
||||
modifiedArguments[0] = target;
|
||||
System.arraycopy(arguments, 0, modifiedArguments, 1, arguments.length);
|
||||
return executor.execute(context, null, modifiedArguments);
|
||||
}
|
||||
}
|
||||
|
||||
public MethodExecutor resolve(final EvaluationContext context,
|
||||
final Object targetObject, final String name, final Class<?>[] argumentTypes)
|
||||
throws AccessException {
|
||||
if (targetObject == null) {
|
||||
return null;
|
||||
}
|
||||
Class<?> type = targetObject.getClass();
|
||||
String cacheKey = type.getName() + "." + name;
|
||||
if (CACHE.containsKey(cacheKey)) {
|
||||
MethodExecutor executor = CACHE.get(cacheKey);
|
||||
return executor == NULL_ME ? null : executor;
|
||||
}
|
||||
|
||||
Method method = lookupMethod(context, type, name);
|
||||
if (method != null) {
|
||||
int modifiers = method.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Class<?> firstParamType = parameterTypes[0];
|
||||
if (parameterTypes.length > 0
|
||||
&& firstParamType.isAssignableFrom(type)) {
|
||||
Class<?>[] newArgumentTypes = new Class[argumentTypes.length + 1];
|
||||
newArgumentTypes[0] = firstParamType;
|
||||
System.arraycopy(argumentTypes, 0, newArgumentTypes,
|
||||
1, argumentTypes.length);
|
||||
MethodExecutor executor = new ReflectiveMethodResolver()
|
||||
.resolve(context, method.getDeclaringClass(), name,
|
||||
newArgumentTypes);
|
||||
MethodExecutor wrappedExecutor = executor == null ? null
|
||||
: new ImplicitMethodExecutor(executor);
|
||||
if (wrappedExecutor == null) {
|
||||
CACHE.putIfAbsent(cacheKey, NULL_ME);
|
||||
}
|
||||
return wrappedExecutor;
|
||||
}
|
||||
}
|
||||
}
|
||||
CACHE.putIfAbsent(cacheKey, NULL_ME);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Method lookupMethod(final EvaluationContext context,
|
||||
final Class<?> type, final String name) {
|
||||
for (Class<?> clazz : InheritenceUtil.getInheritance(type)) {
|
||||
Object variable = ((SpelHelper) context.lookupVariable(SpelHelper.CONTEXT_LOOKUP_KEY))
|
||||
.lookupImplicitMethod(clazz.getName() + "." + name);
|
||||
if (variable instanceof Method) {
|
||||
return (Method) variable;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
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.MethodResolver;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.support.ReflectiveMethodResolver;
|
||||
|
||||
final class ImplicitMethodResolver implements MethodResolver {
|
||||
|
||||
private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
|
||||
new ConcurrentHashMap<String, MethodExecutor>();
|
||||
|
||||
private final ReflectiveMethodResolver delegate = new ReflectiveMethodResolver();
|
||||
|
||||
private static final MethodExecutor NULL_ME = new MethodExecutor() {
|
||||
public TypedValue execute(final EvaluationContext context, final Object target,
|
||||
final Object... arguments) throws AccessException {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final class ImplicitMethodExecutor implements
|
||||
MethodExecutor {
|
||||
private final MethodExecutor executor;
|
||||
|
||||
public ImplicitMethodExecutor(final MethodExecutor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public TypedValue execute(final EvaluationContext context, final Object target,
|
||||
final Object... arguments) throws AccessException {
|
||||
Object[] modifiedArguments = new Object[arguments.length + 1];
|
||||
modifiedArguments[0] = target;
|
||||
System.arraycopy(arguments, 0, modifiedArguments, 1, arguments.length);
|
||||
return executor.execute(context, null, modifiedArguments);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodExecutor resolve(
|
||||
final EvaluationContext context, final Object targetObject,
|
||||
final String name, final List<TypeDescriptor> argumentTypes)
|
||||
throws AccessException {
|
||||
if (targetObject == null) {
|
||||
return null;
|
||||
}
|
||||
Class<?> type = targetObject.getClass();
|
||||
String cacheKey = type.getName() + "." + name;
|
||||
if (CACHE.containsKey(cacheKey)) {
|
||||
MethodExecutor executor = CACHE.get(cacheKey);
|
||||
return executor == NULL_ME ? null : executor;
|
||||
}
|
||||
|
||||
Method method = lookupMethod(context, type, name);
|
||||
if (method != null) {
|
||||
int modifiers = method.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Class<?> firstParamType = parameterTypes[0];
|
||||
if (parameterTypes.length > 0
|
||||
&& firstParamType.isAssignableFrom(type)) {
|
||||
List<TypeDescriptor> newArgumentTypes = new ArrayList<TypeDescriptor>();
|
||||
newArgumentTypes.add(TypeDescriptor.valueOf(firstParamType));
|
||||
newArgumentTypes.addAll(argumentTypes);
|
||||
|
||||
MethodExecutor executor =
|
||||
delegate.resolve(context, method.getDeclaringClass(),
|
||||
name, newArgumentTypes);
|
||||
MethodExecutor wrappedExecutor = executor == null ? null
|
||||
: new ImplicitMethodExecutor(executor);
|
||||
if (wrappedExecutor == null) {
|
||||
CACHE.putIfAbsent(cacheKey, NULL_ME);
|
||||
}
|
||||
return wrappedExecutor;
|
||||
}
|
||||
}
|
||||
}
|
||||
CACHE.putIfAbsent(cacheKey, NULL_ME);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Method lookupMethod(final EvaluationContext context,
|
||||
final Class<?> type, final String name) {
|
||||
for (Class<?> clazz : InheritenceUtil.getInheritance(type)) {
|
||||
Object variable = ((SpelHelper) context.lookupVariable(SpelHelper.CONTEXT_LOOKUP_KEY))
|
||||
.lookupImplicitMethod(clazz.getName() + "." + name);
|
||||
if (variable instanceof Method) {
|
||||
return (Method) variable;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,129 +1,129 @@
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides some implicit methods which can be invoked on the instances of
|
||||
* class of the first parameter of the method inside a SpEL expression.
|
||||
* @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
|
||||
*/
|
||||
public final class ImplicitMethods {
|
||||
|
||||
private ImplicitMethods() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `distinct` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('a','b','a').distinct()" //should return List('a','b')`
|
||||
*
|
||||
* With implicit property support provided by {@link SpelHelper} this can
|
||||
* also be written as:
|
||||
*
|
||||
* `"#list('a','b','a').distinct" //same output as earlier`
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @return An unmodifiable {@link Set} containing the distinct items of the list.
|
||||
*/
|
||||
public static <T> Set<T> distinct(final List<? extends T> list) {
|
||||
return unmodifiableSet(new HashSet<T>(list));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `sorted` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('c','b','a').sorted()" //should return List('a','b','c')`
|
||||
*
|
||||
* With implicit property support provided by {@link SpelHelper} this can
|
||||
* also be written as:
|
||||
*
|
||||
* `"#list('c','b','a').sorted" //same output as earlier`
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @return An unmodifiable {@link List} containing the sorted items
|
||||
* of the list.
|
||||
* @see Collections#sort(List)
|
||||
*/
|
||||
public static <T extends Comparable<? super T>> List<T> sorted(
|
||||
final List<? extends T> list) {
|
||||
List<T> temp = new ArrayList<T>(list);
|
||||
Collections.sort(temp);
|
||||
return unmodifiableList(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `reversed` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('c','b','a').reversed()" //should return List('a','b','c')`
|
||||
*
|
||||
* With implicit property support provided by {@link SpelHelper} this can
|
||||
* also be written as:
|
||||
*
|
||||
* `"#list('c','b','a').reversed" //same output as earlier`
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @return An unmodifiable {@link List} containing the items of the
|
||||
* list in reverse order.
|
||||
* @see Collections#reverse(List)
|
||||
*/
|
||||
public static <T> List<T> reversed(final List<? extends T> list) {
|
||||
List<T> temp = new ArrayList<T>(list);
|
||||
Collections.reverse(temp);
|
||||
return unmodifiableList(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `take` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('c','b','a').take(2)" //should return List('a','b')`
|
||||
*
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @param n Number of items to _take_ from the list.
|
||||
* @return An unmodifiable {@link List} containing the first `n` items
|
||||
* of the list.
|
||||
*/
|
||||
public static <T> List<T> take(final List<T> list, final int n) {
|
||||
return unmodifiableList(list.subList(0, n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `drop` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('c','b','a').drop(2)" //should return List('a')`
|
||||
*
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @param n Number of items to _drop_ from the list.
|
||||
* @return An unmodifiable {@link List} containing the items after the
|
||||
* first `n` items of the list.
|
||||
*/
|
||||
public static <T> List<T> drop(final List<T> list, final int n) {
|
||||
return unmodifiableList(list.subList(n, list.size()));
|
||||
}
|
||||
|
||||
}
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides some implicit methods which can be invoked on the instances of
|
||||
* class of the first parameter of the method inside a SpEL expression.
|
||||
* @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
|
||||
*/
|
||||
public final class ImplicitMethods {
|
||||
|
||||
private ImplicitMethods() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `distinct` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('a','b','a').distinct()" //should return List('a','b')`
|
||||
*
|
||||
* With implicit property support provided by {@link SpelHelper} this can
|
||||
* also be written as:
|
||||
*
|
||||
* `"#list('a','b','a').distinct" //same output as earlier`
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @return An unmodifiable {@link Set} containing the distinct items of the list.
|
||||
*/
|
||||
public static <T> Set<T> distinct(final List<? extends T> list) {
|
||||
return unmodifiableSet(new HashSet<T>(list));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `sorted` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('c','b','a').sorted()" //should return List('a','b','c')`
|
||||
*
|
||||
* With implicit property support provided by {@link SpelHelper} this can
|
||||
* also be written as:
|
||||
*
|
||||
* `"#list('c','b','a').sorted" //same output as earlier`
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @return An unmodifiable {@link List} containing the sorted items
|
||||
* of the list.
|
||||
* @see Collections#sort(List)
|
||||
*/
|
||||
public static <T extends Comparable<? super T>> List<T> sorted(
|
||||
final List<? extends T> list) {
|
||||
List<T> temp = new ArrayList<T>(list);
|
||||
Collections.sort(temp);
|
||||
return unmodifiableList(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `reversed` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('c','b','a').reversed()" //should return List('a','b','c')`
|
||||
*
|
||||
* With implicit property support provided by {@link SpelHelper} this can
|
||||
* also be written as:
|
||||
*
|
||||
* `"#list('c','b','a').reversed" //same output as earlier`
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @return An unmodifiable {@link List} containing the items of the
|
||||
* list in reverse order.
|
||||
* @see Collections#reverse(List)
|
||||
*/
|
||||
public static <T> List<T> reversed(final List<? extends T> list) {
|
||||
List<T> temp = new ArrayList<T>(list);
|
||||
Collections.reverse(temp);
|
||||
return unmodifiableList(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `take` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('c','b','a').take(2)" //should return List('a','b')`
|
||||
*
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @param n Number of items to _take_ from the list.
|
||||
* @return An unmodifiable {@link List} containing the first `n` items
|
||||
* of the list.
|
||||
*/
|
||||
public static <T> List<T> take(final List<T> list, final int n) {
|
||||
return unmodifiableList(list.subList(0, n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides implicit method `drop` on the {@link List} class.
|
||||
*
|
||||
* Example: `"#list('c','b','a').drop(2)" //should return List('a')`
|
||||
*
|
||||
* @param <T> Type of the list's elements.
|
||||
* @param list The list to call this method upon.
|
||||
* @param n Number of items to _drop_ from the list.
|
||||
* @return An unmodifiable {@link List} containing the items after the
|
||||
* first `n` items of the list.
|
||||
*/
|
||||
public static <T> List<T> drop(final List<T> list, final int n) {
|
||||
return unmodifiableList(list.subList(n, list.size()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,67 +1,70 @@
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.MethodExecutor;
|
||||
import org.springframework.expression.MethodResolver;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
final class ImplicitPropertyAccessor extends ReadOnlyGenericPropertyAccessor {
|
||||
|
||||
private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
|
||||
new ConcurrentHashMap<String, MethodExecutor>();
|
||||
|
||||
public boolean canRead(final EvaluationContext context,
|
||||
final Object target, final String name)
|
||||
throws AccessException {
|
||||
Assert.notNull(target, "target is null");
|
||||
String cacheKey = target.getClass().getName() + "." + name;
|
||||
if (CACHE.containsKey(cacheKey)) {
|
||||
return CACHE.get(cacheKey) != null;
|
||||
}
|
||||
|
||||
for (MethodResolver mr : context.getMethodResolvers()) {
|
||||
MethodExecutor me = mr.resolve(context, target, name, new Class[0]);
|
||||
if (me != null) {
|
||||
CACHE.putIfAbsent(cacheKey, me);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
CACHE.putIfAbsent(cacheKey, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
public TypedValue read(final EvaluationContext context,
|
||||
final Object target, final String name)
|
||||
throws AccessException {
|
||||
if (canRead(context, target, name)) {
|
||||
String cacheKey = target.getClass().getName() + "." + name;
|
||||
return CACHE.get(cacheKey).execute(context, target, new Object[0]);
|
||||
}
|
||||
throw new AccessException(MessageFormat.format(
|
||||
"Cannot read property: {0} of target: {1}", name, target));
|
||||
}
|
||||
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
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.MethodResolver;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
final class ImplicitPropertyAccessor extends ReadOnlyGenericPropertyAccessor {
|
||||
|
||||
private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
|
||||
new ConcurrentHashMap<String, MethodExecutor>();
|
||||
|
||||
public boolean canRead(final EvaluationContext context,
|
||||
final Object target, final String name)
|
||||
throws AccessException {
|
||||
Assert.notNull(target, "target is null");
|
||||
String cacheKey = target.getClass().getName() + "." + name;
|
||||
if (CACHE.containsKey(cacheKey)) {
|
||||
return CACHE.get(cacheKey) != null;
|
||||
}
|
||||
|
||||
for (MethodResolver mr : context.getMethodResolvers()) {
|
||||
MethodExecutor me =
|
||||
mr.resolve(context, target, name, Collections.<TypeDescriptor>emptyList());
|
||||
if (me != null) {
|
||||
CACHE.putIfAbsent(cacheKey, me);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
CACHE.putIfAbsent(cacheKey, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
public TypedValue read(final EvaluationContext context,
|
||||
final Object target, final String name)
|
||||
throws AccessException {
|
||||
if (canRead(context, target, name)) {
|
||||
String cacheKey = target.getClass().getName() + "." + name;
|
||||
return CACHE.get(cacheKey).execute(context, target, new Object[0]);
|
||||
}
|
||||
throw new AccessException(MessageFormat.format(
|
||||
"Cannot read property: {0} of target: {1}", name, target));
|
||||
}
|
||||
|
||||
}
|
@ -1,86 +1,86 @@
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
final class InheritenceUtil {
|
||||
|
||||
private InheritenceUtil() {
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getInheritance(final Class<?> clazz) {
|
||||
LinkedHashSet<Class<?>> result = new LinkedHashSet<Class<?>>();
|
||||
result.add(clazz);
|
||||
getInheritance(clazz, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inheritance of type.
|
||||
*
|
||||
* @param clazz
|
||||
* @param result
|
||||
*/
|
||||
private static void getInheritance(final Class<?> clazz, final Set<Class<?>> result) {
|
||||
Class<?> superclass = getSuperclass(clazz);
|
||||
|
||||
if (superclass != null) {
|
||||
result.add(superclass);
|
||||
getInheritance(superclass, result);
|
||||
}
|
||||
|
||||
getInterfaceInheritance(clazz, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get interfaces that the type inherits from.
|
||||
*
|
||||
* @param clazz
|
||||
* @param result
|
||||
*/
|
||||
private static void getInterfaceInheritance(final Class<?> clazz,
|
||||
final Set<Class<?>> result) {
|
||||
for (Class<?> c : clazz.getInterfaces()) {
|
||||
result.add(c);
|
||||
getInterfaceInheritance(c, result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get superclass of class.
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
private static Class<?> getSuperclass(final Class<?> clazz) {
|
||||
if (clazz == null) {
|
||||
return null;
|
||||
}
|
||||
if (clazz.isArray() && clazz != Object[].class) {
|
||||
Class<?> type = clazz.getComponentType();
|
||||
while (type.isArray()) {
|
||||
type = type.getComponentType();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
return clazz.getSuperclass();
|
||||
}
|
||||
|
||||
}
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
final class InheritenceUtil {
|
||||
|
||||
private InheritenceUtil() {
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getInheritance(final Class<?> clazz) {
|
||||
LinkedHashSet<Class<?>> result = new LinkedHashSet<Class<?>>();
|
||||
result.add(clazz);
|
||||
getInheritance(clazz, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inheritance of type.
|
||||
*
|
||||
* @param clazz
|
||||
* @param result
|
||||
*/
|
||||
private static void getInheritance(final Class<?> clazz, final Set<Class<?>> result) {
|
||||
Class<?> superclass = getSuperclass(clazz);
|
||||
|
||||
if (superclass != null) {
|
||||
result.add(superclass);
|
||||
getInheritance(superclass, result);
|
||||
}
|
||||
|
||||
getInterfaceInheritance(clazz, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get interfaces that the type inherits from.
|
||||
*
|
||||
* @param clazz
|
||||
* @param result
|
||||
*/
|
||||
private static void getInterfaceInheritance(final Class<?> clazz,
|
||||
final Set<Class<?>> result) {
|
||||
for (Class<?> c : clazz.getInterfaces()) {
|
||||
result.add(c);
|
||||
getInterfaceInheritance(c, result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get superclass of class.
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
private static Class<?> getSuperclass(final Class<?> clazz) {
|
||||
if (clazz == null) {
|
||||
return null;
|
||||
}
|
||||
if (clazz.isArray() && clazz != Object[].class) {
|
||||
Class<?> type = clazz.getComponentType();
|
||||
while (type.isArray()) {
|
||||
type = type.getComponentType();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
return clazz.getSuperclass();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,45 +1,45 @@
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
|
||||
abstract class ReadOnlyGenericPropertyAccessor implements
|
||||
PropertyAccessor {
|
||||
|
||||
public final boolean canWrite(final EvaluationContext context,
|
||||
final Object target, final String name) throws AccessException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public final Class[] getSpecificTargetClasses() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void write(final EvaluationContext context, final Object target,
|
||||
final String name, final Object newValue) throws AccessException {
|
||||
throw new AccessException(MessageFormat.format(
|
||||
"Cannot write property: {0} of target: {1}", name, target));
|
||||
}
|
||||
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
|
||||
abstract class ReadOnlyGenericPropertyAccessor implements
|
||||
PropertyAccessor {
|
||||
|
||||
public final boolean canWrite(final EvaluationContext context,
|
||||
final Object target, final String name) throws AccessException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public final Class[] getSpecificTargetClasses() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void write(final EvaluationContext context, final Object target,
|
||||
final String name, final Object newValue) throws AccessException {
|
||||
throw new AccessException(MessageFormat.format(
|
||||
"Cannot write property: {0} of target: {1}", name, target));
|
||||
}
|
||||
|
||||
}
|
@ -1,349 +1,349 @@
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.expression.ConstructorResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* SpelHelper provides additional functionalities to work with
|
||||
* [Spring Expression Language (SpEL)][1].
|
||||
*
|
||||
* The addition functionalities provided are:
|
||||
*
|
||||
* 1. Implicit methods
|
||||
* 2. Implicit properties
|
||||
* 3. Simplified extension functions
|
||||
* 4. Simplified constructors
|
||||
*
|
||||
* **Implicit Methods**
|
||||
*
|
||||
* Implicit methods allow one to registers methods with SpelHelper and attach
|
||||
* them to particular classes. After that, when that method is called on an
|
||||
* object of that particular class inside a SpEL expression, SpelHelper
|
||||
* redirects the method call to the registered method.
|
||||
*
|
||||
* Example: {@link ImplicitMethods#sorted(List)} method is automatically
|
||||
* registered by SpelHelper. The class that the method should be invoked for
|
||||
* is the type of the first parameter of the method. In this case, the class is
|
||||
* {@link List}.
|
||||
*
|
||||
* So when an expression like `"#list(1,4,2).sorted()"` is evaluated, the
|
||||
* {@link ImplicitMethods#sorted(List)} method is invoked with the list as its
|
||||
* first parameter and its return value is used in further evaluation of the
|
||||
* expression.
|
||||
*
|
||||
* See {@link SpelHelper#registerImplicitMethodsFromClass(Class)}.
|
||||
*
|
||||
* **Implicit Properties**
|
||||
*
|
||||
* Implicit properties allow one to treat no argument methods of an object
|
||||
* as properties of the object. SpelHelper intercepts the property resolution
|
||||
* of SpEL and if the property name is same as some no-arg method of the target
|
||||
* object then it invokes the method on the object and provides its return value
|
||||
* as the property value for further evaluation of the expression.
|
||||
*
|
||||
* Example: Using implicit properties, the example of implicit methods can be
|
||||
* written as: `"#list(1,4,2).sorted"` - dropping the parens - and it will return
|
||||
* the same value as the last example.
|
||||
*
|
||||
* Implicit property resolution considers both the actual methods of the object
|
||||
* and the implicit methods registered on the object's class.
|
||||
*
|
||||
* **Simplified extension functions**
|
||||
*
|
||||
* SpEL [allows][2] to register extension function on the context by providing a
|
||||
* name and a {@link Method} object. SpelHelper simplifies this by taking a class
|
||||
* and registering all the `public static` methods of the class which do not
|
||||
* have a `void` return type. The methods are registered by their simple name.
|
||||
*
|
||||
* Example: All the methods of {@link ExtensionFunctions} class are automatically
|
||||
* registered by SpelHelper. Hence the method {@link ExtensionFunctions#list(Object...)}
|
||||
* can be called from inside a SpEL expression using the function call syntax:
|
||||
* `"#list(1,2,3)`".
|
||||
*
|
||||
* See {@link SpelHelper#registerFunctionsFromClass(Class)}.
|
||||
*
|
||||
* **Simplified constructors**
|
||||
*
|
||||
* SpEL [allows][3] calling constructors from inside a SpEL expression using the
|
||||
* `new` operator. But they have to be called with their full name like:
|
||||
* `"new org.example.Foo('bar')"`. SpelHelper simplifies this by taking a class
|
||||
* and registering all its public constructors to the SpEL context by their
|
||||
* simple name.
|
||||
*
|
||||
* Example: After registering the `org.example.Foo` class with SpelHelper, its
|
||||
* constructor can be called from inside a SpEL expression by: `"new Foo('bar')"`.
|
||||
*
|
||||
* See {@link SpelHelper#registerConstructorsFromClass(Class)}.
|
||||
*
|
||||
* In addition to all the above functionalities, SpelHelper automatically registers
|
||||
* some extension functions and implicit methods which are always available in
|
||||
* the SpEL expressions evaluated through SpelHelper. See {@link ExtensionFunctions}
|
||||
* and {@link ImplicitMethods} for further details.
|
||||
*
|
||||
* [1]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html
|
||||
* [2]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#expressions-ref-functions
|
||||
* [3]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#d0e11927
|
||||
*
|
||||
* @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
|
||||
*/
|
||||
public final class SpelHelper {
|
||||
|
||||
static final String CONTEXT_LOOKUP_KEY = SpelHelper.class.getName();
|
||||
|
||||
private final ExpressionParser PARSER = new SpelExpressionParser();
|
||||
private static final ThreadLocal<EvaluationContext> CURRENT_CONTEXT =
|
||||
new ThreadLocal<EvaluationContext>();
|
||||
|
||||
private final Set<Method> registeredFunctions = new HashSet<Method>();
|
||||
private final Map<String,Method> registeredMethods =
|
||||
new ConcurrentHashMap<String, Method>();
|
||||
private final Map<String,Constructor<?>> registeredConstructors =
|
||||
new ConcurrentHashMap<String, Constructor<?>>();
|
||||
|
||||
/**
|
||||
* Creates an instance of SpelHelper.
|
||||
*/
|
||||
public SpelHelper() {
|
||||
registerFunctionsFromClass(ExtensionFunctions.class);
|
||||
registerImplicitMethodsFromClass(ImplicitMethods.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the public static methods in the class `clazz` as implicit
|
||||
* methods for the class of the first parameter of the methods.
|
||||
*
|
||||
* Only registers the public static methods with non void return type and at
|
||||
* least one argument.
|
||||
* @see ImplicitMethods
|
||||
* @param clazz The class to register the methods from.
|
||||
* @return The current instance of SpelHelper. This is for chaining
|
||||
* the methods calls.
|
||||
*/
|
||||
public SpelHelper registerImplicitMethodsFromClass(final Class<?> clazz) {
|
||||
for (Method method : filterMethods(clazz)) {
|
||||
registeredMethods.put(String.format(
|
||||
"%s.%s", method.getParameterTypes()[0].getName(), method.getName()),
|
||||
method);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the public static methods in the class `clazz` as functions
|
||||
* which can be called from SpEL expressions.
|
||||
* The functions are registered with the simple name of the methods.
|
||||
*
|
||||
* Only registers the public static methods with non void return type.
|
||||
* @see ExtensionFunctions
|
||||
* @param clazz The class to register the functions from.
|
||||
* @return The current instance of SpelHelper. This is for chaining
|
||||
* the methods calls.
|
||||
*/
|
||||
public SpelHelper registerFunctionsFromClass(final Class<?> clazz) {
|
||||
registeredFunctions.addAll(filterFunctions(clazz));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the public constructors of the class `clazz` so that they
|
||||
* can be called by their simple name from SpEL expressions.
|
||||
* @param clazz The class to register the constructors from.
|
||||
* @return The current instance of SpelHelper. This is for chaining
|
||||
* the methods calls.
|
||||
*/
|
||||
public SpelHelper registerConstructorsFromClass(final Class<?> clazz) {
|
||||
for (Constructor<?> constructor : asList(clazz.getConstructors())) {
|
||||
registeredConstructors.put(
|
||||
constructor.getDeclaringClass().getSimpleName()
|
||||
+ Arrays.toString(constructor.getParameterTypes()),
|
||||
constructor);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a SpEL expression `expressionString` in the context
|
||||
* of root element `rootElement` and gives back a result of type
|
||||
* `desiredType`.
|
||||
* @param <T> The type of the result desired.
|
||||
* @param expressionString The SpEL expression to evaluate.
|
||||
* @param rootElement The root element in context of which the expression
|
||||
* is to be evaluated.
|
||||
* @param desiredType The class of the result desired.
|
||||
* @return The result of the evaluation of the expression.
|
||||
* @see ExpressionParser#parseExpression(String)
|
||||
* @see Expression#getValue(EvaluationContext, Class)
|
||||
*/
|
||||
public <T> T evalExpression(final String expressionString,
|
||||
final Object rootElement, final Class<T> desiredType) {
|
||||
EvaluationContext evaluationContext = getEvaluationContext(rootElement);
|
||||
CURRENT_CONTEXT.set(evaluationContext);
|
||||
T value = evalExpression(expressionString, evaluationContext, desiredType);
|
||||
CURRENT_CONTEXT.set(null);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a SpEL expression `expressionString` in the provided
|
||||
* context `evaluationContext` and gives back a result of type
|
||||
* `desiredType`.
|
||||
* @param <T> The type of the result desired.
|
||||
* @param expressionString The SpEL expression to evaluate.
|
||||
* @param evaluationContext The context in which the expression is to be evaluated.
|
||||
* @param desiredType The class of the result desired.
|
||||
* @return The result of the evaluation of the expression.
|
||||
* @see ExpressionParser#parseExpression(String)
|
||||
* @see Expression#getValue(EvaluationContext, Class)
|
||||
*/
|
||||
public <T> T evalExpression(final String expressionString,
|
||||
final EvaluationContext evaluationContext, final Class<T> desiredType) {
|
||||
return PARSER.parseExpression(expressionString)
|
||||
.getValue(evaluationContext, desiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates multiple SpEL expressions and returns the result of the last
|
||||
* expression.
|
||||
* @param <T> The type of the result desired.
|
||||
* @param expressionStrings The SpEL expressions to evaluate.
|
||||
* @param rootElement The root element in context of which the expressions
|
||||
* are to be evaluated.
|
||||
* @param desiredType The class of the result desired.
|
||||
* @return The result of the evaluation of the last expression.
|
||||
* @see SpelHelper#evalExpression(String, EvaluationContext, Class)
|
||||
* @see SpelHelper#evalExpression(String, Object, Class)
|
||||
*/
|
||||
public <T> T evalExpressions(final String[] expressionStrings,
|
||||
final Object rootElement, final Class<T> desiredType) {
|
||||
return evalExpressions(
|
||||
expressionStrings, getEvaluationContext(rootElement), desiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates multiple SpEL expressions and returns the result of the last
|
||||
* expression.
|
||||
* @param <T> The type of the result desired.
|
||||
* @param expressionStrings The SpEL expressions to evaluate.
|
||||
* @param evaluationContext The context in which the expression is to be evaluated.
|
||||
* @param desiredType The class of the result desired.
|
||||
* @return The result of the evaluation of the last expression.
|
||||
* @see SpelHelper#evalExpression(String, EvaluationContext, Class)
|
||||
* @see SpelHelper#evalExpression(String, Object, Class)
|
||||
*/
|
||||
public <T> T evalExpressions(final String[] expressionStrings,
|
||||
final EvaluationContext evaluationContext, final Class<T> desiredType) {
|
||||
int length = expressionStrings.length;
|
||||
Assert.isTrue(length > 0,
|
||||
"expressionStrings should have length more than 0");
|
||||
for (int i = 0; i < length - 1; i++) {
|
||||
evalExpression(expressionStrings[i], evaluationContext, Object.class);
|
||||
}
|
||||
return evalExpression(expressionStrings[length - 1],
|
||||
evaluationContext, desiredType);
|
||||
}
|
||||
|
||||
private EvaluationContext getEvaluationContext(final Object rootObject) {
|
||||
StandardEvaluationContext newContext = new StandardEvaluationContext(rootObject);
|
||||
newContext.getMethodResolvers().add(new ImplicitMethodResolver());
|
||||
newContext.getPropertyAccessors().add(new ImplicitPropertyAccessor());
|
||||
newContext.setConstructorResolvers(
|
||||
asList((ConstructorResolver) new ImplicitConstructorResolver()));
|
||||
for (Method method : registeredFunctions) {
|
||||
newContext.setVariable(method.getName(), method);
|
||||
}
|
||||
newContext.setVariable(CONTEXT_LOOKUP_KEY, this);
|
||||
return newContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up an implicit method registered with this instance.
|
||||
* @param lookup key to lookup which should be of form:
|
||||
* `method.getParameterTypes()[0].getName() + "." + method.getName()`
|
||||
* @return The registered method if found, else null.
|
||||
*/
|
||||
public Method lookupImplicitMethod(final String lookup) {
|
||||
Assert.notNull(lookup);
|
||||
return registeredMethods.get(lookup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up an implicit constructor registered with this instance.
|
||||
* @param lookup key to lookup which should be of form:
|
||||
* `constructor.getDeclaringClass().getSimpleName()`
|
||||
* `+ Arrays.toString(constructor.getParameterTypes())`
|
||||
* @return The registered constructor if found, else null.
|
||||
*/
|
||||
public Constructor<?> lookupImplicitConstructor(final String lookup) {
|
||||
Assert.notNull(lookup);
|
||||
return registeredConstructors.get(lookup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current evaluation context. Null if there is no context.
|
||||
* @return The current evaluation context.
|
||||
*/
|
||||
public static EvaluationContext getCurrentContext() {
|
||||
return CURRENT_CONTEXT.get();
|
||||
}
|
||||
|
||||
private static List<Method> filterMethods(final Class<?> clazz) {
|
||||
List<Method> allowedMethods = new ArrayList<Method>();
|
||||
for (Method method : clazz.getMethods()) {
|
||||
int modifiers = method.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
|
||||
&& !method.getReturnType().equals(Void.TYPE)
|
||||
&& method.getParameterTypes().length > 0) {
|
||||
allowedMethods.add(method);
|
||||
}
|
||||
}
|
||||
return allowedMethods;
|
||||
}
|
||||
|
||||
private static List<Method> filterFunctions(final Class<?> clazz) {
|
||||
List<Method> allowedMethods = new ArrayList<Method>();
|
||||
for (Method method : clazz.getMethods()) {
|
||||
int modifiers = method.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
|
||||
&& !method.getReturnType().equals(Void.TYPE)) {
|
||||
allowedMethods.add(method);
|
||||
}
|
||||
}
|
||||
return allowedMethods;
|
||||
}
|
||||
|
||||
}
|
||||
/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
|
||||
*
|
||||
* This file is a part of SpelHelper library.
|
||||
*
|
||||
* SpelHelper library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (GNU LGPL) as
|
||||
* published by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* SpelHelper library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SpelHelper library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.expression.ConstructorResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* SpelHelper provides additional functionalities to work with
|
||||
* [Spring Expression Language (SpEL)][1].
|
||||
*
|
||||
* The addition functionalities provided are:
|
||||
*
|
||||
* 1. Implicit methods
|
||||
* 2. Implicit properties
|
||||
* 3. Simplified extension functions
|
||||
* 4. Simplified constructors
|
||||
*
|
||||
* **Implicit Methods**
|
||||
*
|
||||
* Implicit methods allow one to registers methods with SpelHelper and attach
|
||||
* them to particular classes. After that, when that method is called on an
|
||||
* object of that particular class inside a SpEL expression, SpelHelper
|
||||
* redirects the method call to the registered method.
|
||||
*
|
||||
* Example: {@link ImplicitMethods#sorted(List)} method is automatically
|
||||
* registered by SpelHelper. The class that the method should be invoked for
|
||||
* is the type of the first parameter of the method. In this case, the class is
|
||||
* {@link List}.
|
||||
*
|
||||
* So when an expression like `"#list(1,4,2).sorted()"` is evaluated, the
|
||||
* {@link ImplicitMethods#sorted(List)} method is invoked with the list as its
|
||||
* first parameter and its return value is used in further evaluation of the
|
||||
* expression.
|
||||
*
|
||||
* See {@link SpelHelper#registerImplicitMethodsFromClass(Class)}.
|
||||
*
|
||||
* **Implicit Properties**
|
||||
*
|
||||
* Implicit properties allow one to treat no argument methods of an object
|
||||
* as properties of the object. SpelHelper intercepts the property resolution
|
||||
* of SpEL and if the property name is same as some no-arg method of the target
|
||||
* object then it invokes the method on the object and provides its return value
|
||||
* as the property value for further evaluation of the expression.
|
||||
*
|
||||
* Example: Using implicit properties, the example of implicit methods can be
|
||||
* written as: `"#list(1,4,2).sorted"` - dropping the parens - and it will return
|
||||
* the same value as the last example.
|
||||
*
|
||||
* Implicit property resolution considers both the actual methods of the object
|
||||
* and the implicit methods registered on the object's class.
|
||||
*
|
||||
* **Simplified extension functions**
|
||||
*
|
||||
* SpEL [allows][2] to register extension function on the context by providing a
|
||||
* name and a {@link Method} object. SpelHelper simplifies this by taking a class
|
||||
* and registering all the `public static` methods of the class which do not
|
||||
* have a `void` return type. The methods are registered by their simple name.
|
||||
*
|
||||
* Example: All the methods of {@link ExtensionFunctions} class are automatically
|
||||
* registered by SpelHelper. Hence the method {@link ExtensionFunctions#list(Object...)}
|
||||
* can be called from inside a SpEL expression using the function call syntax:
|
||||
* `"#list(1,2,3)`".
|
||||
*
|
||||
* See {@link SpelHelper#registerFunctionsFromClass(Class)}.
|
||||
*
|
||||
* **Simplified constructors**
|
||||
*
|
||||
* SpEL [allows][3] calling constructors from inside a SpEL expression using the
|
||||
* `new` operator. But they have to be called with their full name like:
|
||||
* `"new org.example.Foo('bar')"`. SpelHelper simplifies this by taking a class
|
||||
* and registering all its public constructors to the SpEL context by their
|
||||
* simple name.
|
||||
*
|
||||
* Example: After registering the `org.example.Foo` class with SpelHelper, its
|
||||
* constructor can be called from inside a SpEL expression by: `"new Foo('bar')"`.
|
||||
*
|
||||
* See {@link SpelHelper#registerConstructorsFromClass(Class)}.
|
||||
*
|
||||
* In addition to all the above functionalities, SpelHelper automatically registers
|
||||
* some extension functions and implicit methods which are always available in
|
||||
* the SpEL expressions evaluated through SpelHelper. See {@link ExtensionFunctions}
|
||||
* and {@link ImplicitMethods} for further details.
|
||||
*
|
||||
* [1]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html
|
||||
* [2]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#expressions-ref-functions
|
||||
* [3]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#d0e11927
|
||||
*
|
||||
* @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
|
||||
*/
|
||||
public final class SpelHelper {
|
||||
|
||||
static final String CONTEXT_LOOKUP_KEY = SpelHelper.class.getName();
|
||||
|
||||
private final ExpressionParser PARSER = new SpelExpressionParser();
|
||||
private static final ThreadLocal<EvaluationContext> CURRENT_CONTEXT =
|
||||
new ThreadLocal<EvaluationContext>();
|
||||
|
||||
private final Set<Method> registeredFunctions = new HashSet<Method>();
|
||||
private final Map<String,Method> registeredMethods =
|
||||
new ConcurrentHashMap<String, Method>();
|
||||
private final Map<String,Constructor<?>> registeredConstructors =
|
||||
new ConcurrentHashMap<String, Constructor<?>>();
|
||||
|
||||
/**
|
||||
* Creates an instance of SpelHelper.
|
||||
*/
|
||||
public SpelHelper() {
|
||||
registerFunctionsFromClass(ExtensionFunctions.class);
|
||||
registerImplicitMethodsFromClass(ImplicitMethods.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the public static methods in the class `clazz` as implicit
|
||||
* methods for the class of the first parameter of the methods.
|
||||
*
|
||||
* Only registers the public static methods with non void return type and at
|
||||
* least one argument.
|
||||
* @see ImplicitMethods
|
||||
* @param clazz The class to register the methods from.
|
||||
* @return The current instance of SpelHelper. This is for chaining
|
||||
* the methods calls.
|
||||
*/
|
||||
public SpelHelper registerImplicitMethodsFromClass(final Class<?> clazz) {
|
||||
for (Method method : filterMethods(clazz)) {
|
||||
registeredMethods.put(String.format(
|
||||
"%s.%s", method.getParameterTypes()[0].getName(), method.getName()),
|
||||
method);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the public static methods in the class `clazz` as functions
|
||||
* which can be called from SpEL expressions.
|
||||
* The functions are registered with the simple name of the methods.
|
||||
*
|
||||
* Only registers the public static methods with non void return type.
|
||||
* @see ExtensionFunctions
|
||||
* @param clazz The class to register the functions from.
|
||||
* @return The current instance of SpelHelper. This is for chaining
|
||||
* the methods calls.
|
||||
*/
|
||||
public SpelHelper registerFunctionsFromClass(final Class<?> clazz) {
|
||||
registeredFunctions.addAll(filterFunctions(clazz));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the public constructors of the class `clazz` so that they
|
||||
* can be called by their simple name from SpEL expressions.
|
||||
* @param clazz The class to register the constructors from.
|
||||
* @return The current instance of SpelHelper. This is for chaining
|
||||
* the methods calls.
|
||||
*/
|
||||
public SpelHelper registerConstructorsFromClass(final Class<?> clazz) {
|
||||
for (Constructor<?> constructor : asList(clazz.getConstructors())) {
|
||||
registeredConstructors.put(
|
||||
constructor.getDeclaringClass().getSimpleName()
|
||||
+ Arrays.toString(constructor.getParameterTypes()),
|
||||
constructor);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a SpEL expression `expressionString` in the context
|
||||
* of root element `rootElement` and gives back a result of type
|
||||
* `desiredType`.
|
||||
* @param <T> The type of the result desired.
|
||||
* @param expressionString The SpEL expression to evaluate.
|
||||
* @param rootElement The root element in context of which the expression
|
||||
* is to be evaluated.
|
||||
* @param desiredType The class of the result desired.
|
||||
* @return The result of the evaluation of the expression.
|
||||
* @see ExpressionParser#parseExpression(String)
|
||||
* @see Expression#getValue(EvaluationContext, Class)
|
||||
*/
|
||||
public <T> T evalExpression(final String expressionString,
|
||||
final Object rootElement, final Class<T> desiredType) {
|
||||
EvaluationContext evaluationContext = getEvaluationContext(rootElement);
|
||||
CURRENT_CONTEXT.set(evaluationContext);
|
||||
T value = evalExpression(expressionString, evaluationContext, desiredType);
|
||||
CURRENT_CONTEXT.set(null);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a SpEL expression `expressionString` in the provided
|
||||
* context `evaluationContext` and gives back a result of type
|
||||
* `desiredType`.
|
||||
* @param <T> The type of the result desired.
|
||||
* @param expressionString The SpEL expression to evaluate.
|
||||
* @param evaluationContext The context in which the expression is to be evaluated.
|
||||
* @param desiredType The class of the result desired.
|
||||
* @return The result of the evaluation of the expression.
|
||||
* @see ExpressionParser#parseExpression(String)
|
||||
* @see Expression#getValue(EvaluationContext, Class)
|
||||
*/
|
||||
public <T> T evalExpression(final String expressionString,
|
||||
final EvaluationContext evaluationContext, final Class<T> desiredType) {
|
||||
return PARSER.parseExpression(expressionString)
|
||||
.getValue(evaluationContext, desiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates multiple SpEL expressions and returns the result of the last
|
||||
* expression.
|
||||
* @param <T> The type of the result desired.
|
||||
* @param expressionStrings The SpEL expressions to evaluate.
|
||||
* @param rootElement The root element in context of which the expressions
|
||||
* are to be evaluated.
|
||||
* @param desiredType The class of the result desired.
|
||||
* @return The result of the evaluation of the last expression.
|
||||
* @see SpelHelper#evalExpression(String, EvaluationContext, Class)
|
||||
* @see SpelHelper#evalExpression(String, Object, Class)
|
||||
*/
|
||||
public <T> T evalExpressions(final String[] expressionStrings,
|
||||
final Object rootElement, final Class<T> desiredType) {
|
||||
return evalExpressions(
|
||||
expressionStrings, getEvaluationContext(rootElement), desiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates multiple SpEL expressions and returns the result of the last
|
||||
* expression.
|
||||
* @param <T> The type of the result desired.
|
||||
* @param expressionStrings The SpEL expressions to evaluate.
|
||||
* @param evaluationContext The context in which the expression is to be evaluated.
|
||||
* @param desiredType The class of the result desired.
|
||||
* @return The result of the evaluation of the last expression.
|
||||
* @see SpelHelper#evalExpression(String, EvaluationContext, Class)
|
||||
* @see SpelHelper#evalExpression(String, Object, Class)
|
||||
*/
|
||||
public <T> T evalExpressions(final String[] expressionStrings,
|
||||
final EvaluationContext evaluationContext, final Class<T> desiredType) {
|
||||
int length = expressionStrings.length;
|
||||
Assert.isTrue(length > 0,
|
||||
"expressionStrings should have length more than 0");
|
||||
for (int i = 0; i < length - 1; i++) {
|
||||
evalExpression(expressionStrings[i], evaluationContext, Object.class);
|
||||
}
|
||||
return evalExpression(expressionStrings[length - 1],
|
||||
evaluationContext, desiredType);
|
||||
}
|
||||
|
||||
private EvaluationContext getEvaluationContext(final Object rootObject) {
|
||||
StandardEvaluationContext newContext = new StandardEvaluationContext(rootObject);
|
||||
newContext.getMethodResolvers().add(new ImplicitMethodResolver());
|
||||
newContext.getPropertyAccessors().add(new ImplicitPropertyAccessor());
|
||||
newContext.setConstructorResolvers(
|
||||
asList((ConstructorResolver) new ImplicitConstructorResolver()));
|
||||
for (Method method : registeredFunctions) {
|
||||
newContext.setVariable(method.getName(), method);
|
||||
}
|
||||
newContext.setVariable(CONTEXT_LOOKUP_KEY, this);
|
||||
return newContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up an implicit method registered with this instance.
|
||||
* @param lookup key to lookup which should be of form:
|
||||
* `method.getParameterTypes()[0].getName() + "." + method.getName()`
|
||||
* @return The registered method if found, else null.
|
||||
*/
|
||||
public Method lookupImplicitMethod(final String lookup) {
|
||||
Assert.notNull(lookup);
|
||||
return registeredMethods.get(lookup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up an implicit constructor registered with this instance.
|
||||
* @param lookup key to lookup which should be of form:
|
||||
* `constructor.getDeclaringClass().getSimpleName()`
|
||||
* `+ Arrays.toString(constructor.getParameterTypes())`
|
||||
* @return The registered constructor if found, else null.
|
||||
*/
|
||||
public Constructor<?> lookupImplicitConstructor(final String lookup) {
|
||||
Assert.notNull(lookup);
|
||||
return registeredConstructors.get(lookup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current evaluation context. Null if there is no context.
|
||||
* @return The current evaluation context.
|
||||
*/
|
||||
public static EvaluationContext getCurrentContext() {
|
||||
return CURRENT_CONTEXT.get();
|
||||
}
|
||||
|
||||
private static List<Method> filterMethods(final Class<?> clazz) {
|
||||
List<Method> allowedMethods = new ArrayList<Method>();
|
||||
for (Method method : clazz.getMethods()) {
|
||||
int modifiers = method.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
|
||||
&& !method.getReturnType().equals(Void.TYPE)
|
||||
&& method.getParameterTypes().length > 0) {
|
||||
allowedMethods.add(method);
|
||||
}
|
||||
}
|
||||
return allowedMethods;
|
||||
}
|
||||
|
||||
private static List<Method> filterFunctions(final Class<?> clazz) {
|
||||
List<Method> allowedMethods = new ArrayList<Method>();
|
||||
for (Method method : clazz.getMethods()) {
|
||||
int modifiers = method.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
|
||||
&& !method.getReturnType().equals(Void.TYPE)) {
|
||||
allowedMethods.add(method);
|
||||
}
|
||||
}
|
||||
return allowedMethods;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,36 +1,36 @@
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
public final class Functions {
|
||||
|
||||
public static String test(final String str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
static String testNonPublic(final String str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
public String testNonStatic(final String str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
public static void testVoid(final String str) {
|
||||
return;
|
||||
}
|
||||
|
||||
public static String testNoArg() {
|
||||
return "a";
|
||||
}
|
||||
|
||||
public static String testContext(final String str) {
|
||||
if (SpelHelper.getCurrentContext() == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
return o instanceof Functions;
|
||||
}
|
||||
}
|
||||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
public final class Functions {
|
||||
|
||||
public static String test(final String str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
static String testNonPublic(final String str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
public String testNonStatic(final String str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
public static void testVoid(final String str) {
|
||||
return;
|
||||
}
|
||||
|
||||
public static String testNoArg() {
|
||||
return "a";
|
||||
}
|
||||
|
||||
public static String testContext(final String str) {
|
||||
if (SpelHelper.getCurrentContext() == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
return o instanceof Functions;
|
||||
}
|
||||
}
|
||||
|
@ -1,42 +1,42 @@
|
||||
package net.abhinavsarkar.spelhelper
|
||||
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FlatSpec
|
||||
import org.scalatest.junit.ShouldMatchersForJUnit
|
||||
import java.util.{Set => JSet, HashSet,
|
||||
List => JList, ArrayList,
|
||||
Map => JMap, HashMap}
|
||||
import org.springframework.expression.spel.SpelEvaluationException
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class ExtensionFunctionsSpec extends FlatSpec with ShouldMatchersForJUnit {
|
||||
|
||||
"Extension Function 'list'" should "return a java.util.List " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("a", "b", "c") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('a','b','c')",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
"Extension Function 'set'" should "return a java.util.Set " in {
|
||||
val set: JSet[String] = new HashSet
|
||||
List("a", "b", "c") foreach { set add _ }
|
||||
new SpelHelper().evalExpression("#set('a','b','c')",
|
||||
new {}, classOf[JSet[String]]) should equal(set)
|
||||
}
|
||||
|
||||
"Extension Function 'map'" should "return a java.util.Map " in {
|
||||
val map: JMap[String,Int] = new HashMap
|
||||
List("a", "b", "c").zipWithIndex.foreach { x => map.put(x._1, x._2) }
|
||||
new SpelHelper().evalExpression("#map(#list('a','b','c'),#list(0,1,2))",
|
||||
new {}, classOf[JMap[String,Int]]) should equal(map)
|
||||
}
|
||||
|
||||
"Extension Function 'map'" should "throw SpelEvaluationException " +
|
||||
"if length of key and values lists is not same " in {
|
||||
evaluating { new SpelHelper().evalExpression("#map(#list('a','b','c'),#list(1,2))",
|
||||
new {}, classOf[JMap[String,Int]]) } should produce [SpelEvaluationException]
|
||||
}
|
||||
|
||||
}
|
||||
package net.abhinavsarkar.spelhelper
|
||||
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FlatSpec
|
||||
import org.scalatest.junit.ShouldMatchersForJUnit
|
||||
import java.util.{Set => JSet, HashSet,
|
||||
List => JList, ArrayList,
|
||||
Map => JMap, HashMap}
|
||||
import org.springframework.expression.spel.SpelEvaluationException
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class ExtensionFunctionsSpec extends FlatSpec with ShouldMatchersForJUnit {
|
||||
|
||||
"Extension Function 'list'" should "return a java.util.List " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("a", "b", "c") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('a','b','c')",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
"Extension Function 'set'" should "return a java.util.Set " in {
|
||||
val set: JSet[String] = new HashSet
|
||||
List("a", "b", "c") foreach { set add _ }
|
||||
new SpelHelper().evalExpression("#set('a','b','c')",
|
||||
new {}, classOf[JSet[String]]) should equal(set)
|
||||
}
|
||||
|
||||
"Extension Function 'map'" should "return a java.util.Map " in {
|
||||
val map: JMap[String,Int] = new HashMap
|
||||
List("a", "b", "c").zipWithIndex.foreach { x => map.put(x._1, x._2) }
|
||||
new SpelHelper().evalExpression("#map(#list('a','b','c'),#list(0,1,2))",
|
||||
new {}, classOf[JMap[String,Int]]) should equal(map)
|
||||
}
|
||||
|
||||
"Extension Function 'map'" should "throw SpelEvaluationException " +
|
||||
"if length of key and values lists is not same " in {
|
||||
evaluating { new SpelHelper().evalExpression("#map(#list('a','b','c'),#list(1,2))",
|
||||
new {}, classOf[JMap[String,Int]]) } should produce [SpelEvaluationException]
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,52 +1,52 @@
|
||||
package net.abhinavsarkar.spelhelper
|
||||
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FlatSpec
|
||||
import org.scalatest.junit.ShouldMatchersForJUnit
|
||||
import java.util.{HashSet, Set => JSet, List => JList, ArrayList}
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class ImplicitMethodsSpec extends FlatSpec with ShouldMatchersForJUnit {
|
||||
|
||||
"Implicit Function 'distinct' on List" should
|
||||
"return distinct items in a list " in {
|
||||
val set: JSet[String] = new HashSet
|
||||
set add "a"; set add "b"
|
||||
new SpelHelper().evalExpression("#list('a','b','a').distinct()",
|
||||
new {}, classOf[JSet[String]]) should equal(set)
|
||||
}
|
||||
|
||||
"Implicit Function 'sorted' on List" should
|
||||
"return a sorted list " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("a", "b", "c") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('c','b','a').sorted()",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
"Implicit Function 'reversed' on List" should
|
||||
"return a reversed list " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("a", "b", "c") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('c','b','a').reversed()",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
"Implicit Function 'take' on List" should
|
||||
"return a list containing first n items of a list " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("a", "b", "c") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('a','b','c','d').take(3)",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
"Implicit Function 'drop' on List" should
|
||||
"return a list containing items after the first n items of a list " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("c", "d") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('a','b','c','d').drop(2)",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
}
|
||||
package net.abhinavsarkar.spelhelper
|
||||
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FlatSpec
|
||||
import org.scalatest.junit.ShouldMatchersForJUnit
|
||||
import java.util.{HashSet, Set => JSet, List => JList, ArrayList}
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class ImplicitMethodsSpec extends FlatSpec with ShouldMatchersForJUnit {
|
||||
|
||||
"Implicit Function 'distinct' on List" should
|
||||
"return distinct items in a list " in {
|
||||
val set: JSet[String] = new HashSet
|
||||
set add "a"; set add "b"
|
||||
new SpelHelper().evalExpression("#list('a','b','a').distinct()",
|
||||
new {}, classOf[JSet[String]]) should equal(set)
|
||||
}
|
||||
|
||||
"Implicit Function 'sorted' on List" should
|
||||
"return a sorted list " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("a", "b", "c") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('c','b','a').sorted()",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
"Implicit Function 'reversed' on List" should
|
||||
"return a reversed list " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("a", "b", "c") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('c','b','a').reversed()",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
"Implicit Function 'take' on List" should
|
||||
"return a list containing first n items of a list " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("a", "b", "c") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('a','b','c','d').take(3)",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
"Implicit Function 'drop' on List" should
|
||||
"return a list containing items after the first n items of a list " in {
|
||||
val list: JList[String] = new ArrayList
|
||||
List("c", "d") foreach { list add _ }
|
||||
new SpelHelper().evalExpression("#list('a','b','c','d').drop(2)",
|
||||
new {}, classOf[JList[String]]) should equal(list)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,103 +1,103 @@
|
||||
package net.abhinavsarkar.spelhelper
|
||||
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FlatSpec
|
||||
import org.scalatest.junit.ShouldMatchersForJUnit
|
||||
import org.springframework.expression.spel.SpelEvaluationException
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class SpelHelperSpec extends FlatSpec with ShouldMatchersForJUnit {
|
||||
|
||||
"SpelHelper" should "register and evaluate functions " in {
|
||||
new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
.evalExpression(
|
||||
"#test('check')", new {}, classOf[String]) should equal ("check")
|
||||
}
|
||||
|
||||
it should "not register non public methods " in {
|
||||
val spelHelper = new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
evaluating { spelHelper.evalExpression("#testNonPublic('check')",
|
||||
new {}, classOf[String]) } should produce [SpelEvaluationException]
|
||||
}
|
||||
|
||||
it should "not register non static methods " in {
|
||||
val spelHelper = new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
evaluating { spelHelper.evalExpression("#testNonStatic('check')",
|
||||
new {}, classOf[String]) } should produce [SpelEvaluationException]
|
||||
}
|
||||
|
||||
it should "not register void methods " in {
|
||||
val spelHelper = new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
evaluating { spelHelper.evalExpression("#testVoid('check')",
|
||||
new {}, classOf[String]) } should produce [SpelEvaluationException]
|
||||
}
|
||||
|
||||
it should "register implicit methods " in {
|
||||
new SpelHelper()
|
||||
.registerImplicitMethodsFromClass(classOf[Functions])
|
||||
.lookupImplicitMethod("java.lang.String.test") should equal(
|
||||
classOf[Functions].getMethod("test", classOf[String]))
|
||||
}
|
||||
|
||||
it should "not register methods with no args as implicit methods " in {
|
||||
new SpelHelper()
|
||||
.registerImplicitMethodsFromClass(classOf[Functions])
|
||||
.lookupImplicitMethod("java.lang.String.testNoArg") should be (null);
|
||||
}
|
||||
|
||||
it should "register implicit constructors " in {
|
||||
new SpelHelper()
|
||||
.registerConstructorsFromClass(classOf[Functions])
|
||||
.lookupImplicitConstructor("Functions[]") should equal(
|
||||
classOf[Functions].getConstructor())
|
||||
}
|
||||
|
||||
it should "evaluate implicit methods " in {
|
||||
new SpelHelper()
|
||||
.registerImplicitMethodsFromClass(classOf[Functions])
|
||||
.evalExpression(
|
||||
"'check'.test()", new {}, classOf[String]) should equal ("check")
|
||||
}
|
||||
|
||||
it should "evaluate implicit constructors " in {
|
||||
new SpelHelper()
|
||||
.registerConstructorsFromClass(classOf[Functions])
|
||||
.evalExpression(
|
||||
"new Functions()", new {}, classOf[Functions]) should equal (new Functions)
|
||||
}
|
||||
|
||||
it should "evaluate implicit properties " in {
|
||||
new SpelHelper().evalExpression(
|
||||
"'abc'.hashCode", new {}, classOf[int]) should equal ("abc".hashCode)
|
||||
}
|
||||
|
||||
it should "evaluate multiple expressions " in {
|
||||
new SpelHelper().evalExpressions(
|
||||
Array("#s='check'", "#s"), new {}, classOf[String]) should equal ("check")
|
||||
}
|
||||
|
||||
it should "throw IllegalArgumentException when trying to evaluate " +
|
||||
"blank multiple expressions " in {
|
||||
evaluating { new SpelHelper().evalExpressions(
|
||||
Array[String](), new {}, classOf[String]) } should produce [IllegalArgumentException]
|
||||
}
|
||||
|
||||
it should "return evaluation context inside a method called " +
|
||||
"from SpEL expression " in {
|
||||
new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
.evalExpression(
|
||||
"#testContext('check')", new {}, classOf[String]) should equal ("check")
|
||||
}
|
||||
|
||||
it should "not return evaluation context outside a method called " +
|
||||
"from SpEL expression " in {
|
||||
SpelHelper.getCurrentContext should be (null)
|
||||
}
|
||||
|
||||
}
|
||||
package net.abhinavsarkar.spelhelper
|
||||
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FlatSpec
|
||||
import org.scalatest.junit.ShouldMatchersForJUnit
|
||||
import org.springframework.expression.spel.SpelEvaluationException
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class SpelHelperSpec extends FlatSpec with ShouldMatchersForJUnit {
|
||||
|
||||
"SpelHelper" should "register and evaluate functions " in {
|
||||
new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
.evalExpression(
|
||||
"#test('check')", new {}, classOf[String]) should equal ("check")
|
||||
}
|
||||
|
||||
it should "not register non public methods " in {
|
||||
val spelHelper = new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
evaluating { spelHelper.evalExpression("#testNonPublic('check')",
|
||||
new {}, classOf[String]) } should produce [SpelEvaluationException]
|
||||
}
|
||||
|
||||
it should "not register non static methods " in {
|
||||
val spelHelper = new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
evaluating { spelHelper.evalExpression("#testNonStatic('check')",
|
||||
new {}, classOf[String]) } should produce [SpelEvaluationException]
|
||||
}
|
||||
|
||||
it should "not register void methods " in {
|
||||
val spelHelper = new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
evaluating { spelHelper.evalExpression("#testVoid('check')",
|
||||
new {}, classOf[String]) } should produce [SpelEvaluationException]
|
||||
}
|
||||
|
||||
it should "register implicit methods " in {
|
||||
new SpelHelper()
|
||||
.registerImplicitMethodsFromClass(classOf[Functions])
|
||||
.lookupImplicitMethod("java.lang.String.test") should equal(
|
||||
classOf[Functions].getMethod("test", classOf[String]))
|
||||
}
|
||||
|
||||
it should "not register methods with no args as implicit methods " in {
|
||||
new SpelHelper()
|
||||
.registerImplicitMethodsFromClass(classOf[Functions])
|
||||
.lookupImplicitMethod("java.lang.String.testNoArg") should be (null);
|
||||
}
|
||||
|
||||
it should "register implicit constructors " in {
|
||||
new SpelHelper()
|
||||
.registerConstructorsFromClass(classOf[Functions])
|
||||
.lookupImplicitConstructor("Functions[]") should equal(
|
||||
classOf[Functions].getConstructor())
|
||||
}
|
||||
|
||||
it should "evaluate implicit methods " in {
|
||||
new SpelHelper()
|
||||
.registerImplicitMethodsFromClass(classOf[Functions])
|
||||
.evalExpression(
|
||||
"'check'.test()", new {}, classOf[String]) should equal ("check")
|
||||
}
|
||||
|
||||
it should "evaluate implicit constructors " in {
|
||||
new SpelHelper()
|
||||
.registerConstructorsFromClass(classOf[Functions])
|
||||
.evalExpression(
|
||||
"new Functions()", new {}, classOf[Functions]) should equal (new Functions)
|
||||
}
|
||||
|
||||
it should "evaluate implicit properties " in {
|
||||
new SpelHelper().evalExpression(
|
||||
"'abc'.hashCode", new {}, classOf[int]) should equal ("abc".hashCode)
|
||||
}
|
||||
|
||||
it should "evaluate multiple expressions " in {
|
||||
new SpelHelper().evalExpressions(
|
||||
Array("#s='check'", "#s"), new {}, classOf[String]) should equal ("check")
|
||||
}
|
||||
|
||||
it should "throw IllegalArgumentException when trying to evaluate " +
|
||||
"blank multiple expressions " in {
|
||||
evaluating { new SpelHelper().evalExpressions(
|
||||
Array[String](), new {}, classOf[String]) } should produce [IllegalArgumentException]
|
||||
}
|
||||
|
||||
it should "return evaluation context inside a method called " +
|
||||
"from SpEL expression " in {
|
||||
new SpelHelper()
|
||||
.registerFunctionsFromClass(classOf[Functions])
|
||||
.evalExpression(
|
||||
"#testContext('check')", new {}, classOf[String]) should equal ("check")
|
||||
}
|
||||
|
||||
it should "not return evaluation context outside a method called " +
|
||||
"from SpEL expression " in {
|
||||
SpelHelper.getCurrentContext should be (null)
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user