Updated to spring 3.0.6

master
Abhinav Sarkar 2011-10-12 18:36:00 +05:30
부모 f39f6ff692
커밋 9fe01a9403
14개의 변경된 파일1185개의 추가작업 그리고 1167개의 파일을 삭제

6
.gitignore vendored
파일 보기

@ -1,2 +1,4 @@
target/*
.pmd
target/*
.pmd
.scala_dependencies
.settings/

파일 보기

@ -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)
}
}