Compare commits
9 Commits
SpelHelper
...
master
Author | SHA1 | Date |
---|---|---|
Abhinav Sarkar | f39d4eaf64 | |
Abhinav Sarkar | dfabc55c82 | |
Abhinav Sarkar | 9ebd8862d4 | |
Abhinav Sarkar | 410dcdada2 | |
Abhinav Sarkar | fc55ca72fb | |
Abhinav Sarkar | 2c3d0f10d9 | |
Abhinav Sarkar | eab471311c | |
Abhinav Sarkar | 9fe01a9403 | |
Abhinav Sarkar | f39f6ff692 |
|
@ -1,2 +1,4 @@
|
|||
target/*
|
||||
.pmd
|
||||
.scala_dependencies
|
||||
.settings/
|
||||
|
|
20
README.mdown
20
README.mdown
|
@ -3,6 +3,18 @@ SpelHelper provides additional functionalities to work with
|
|||
|
||||
SpelHelper is available under GNU Lesser General Public License (GNU LGPL).
|
||||
|
||||
**Maven Usage**
|
||||
|
||||
To use SpelHelper with Maven, add the following snippet in the dependencies section of your project's POM file:
|
||||
|
||||
<dependency>
|
||||
<groupId>net.abhinavsarkar</groupId>
|
||||
<artifactId>SpelHelper</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
**Functionalities**
|
||||
|
||||
The addition functionalities provided are:
|
||||
|
||||
1. Implicit methods
|
||||
|
@ -10,7 +22,7 @@ The addition functionalities provided are:
|
|||
3. Simplified extension functions
|
||||
4. Simplified constructors
|
||||
|
||||
**Implicit Methods**
|
||||
_**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
|
||||
|
@ -27,7 +39,7 @@ So when an expression like `"#list(1,4,2).sorted()"` is evaluated, the
|
|||
first parameter and its return value is used in further evaluation of the
|
||||
expression.
|
||||
|
||||
**Implicit Properties**
|
||||
_**Implicit properties**_
|
||||
|
||||
Implicit properties allow one to treat no argument methods of an object
|
||||
as properties of the object. SpelHelper intercepts the property resolution
|
||||
|
@ -42,7 +54,7 @@ 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**
|
||||
_**Simplified extension functions**_
|
||||
|
||||
SpEL [allows][2] to register extension function on the context by providing a
|
||||
name and a java.lang.reflect.Method object. SpelHelper simplifies this by taking a class
|
||||
|
@ -54,7 +66,7 @@ registered by SpelHelper. Hence the method [ExtensionFunctions#list(Object...)][
|
|||
can be called from inside a SpEL expression using the function call syntax:
|
||||
`"#list(1,2,3)`".
|
||||
|
||||
**Simplified constructors**
|
||||
_**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:
|
||||
|
|
8
pom.xml
8
pom.xml
|
@ -3,7 +3,7 @@
|
|||
|
||||
<groupId>net.abhinavsarkar</groupId>
|
||||
<artifactId>SpelHelper</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.3-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>SpelHelper</name>
|
||||
|
@ -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>
|
||||
|
||||
|
|
|
@ -18,26 +18,29 @@
|
|||
package net.abhinavsarkar.spelhelper;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
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 {
|
||||
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 {
|
||||
@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 + Arrays.toString(argumentTypes));
|
||||
.lookupImplicitConstructor(typeName + argumentTypes.toString());
|
||||
if (variable instanceof Constructor<?>) {
|
||||
Constructor<?> constructor = (Constructor<?>) variable;
|
||||
return delegate.resolve(context, constructor.getDeclaringClass().getName(), argumentTypes);
|
||||
|
|
|
@ -19,8 +19,11 @@ 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;
|
||||
|
@ -33,21 +36,24 @@ 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() {
|
||||
@Override
|
||||
public TypedValue execute(final EvaluationContext context, final Object target,
|
||||
final Object... arguments) throws AccessException {
|
||||
return null;
|
||||
throw new UnsupportedOperationException("This method should never be called");
|
||||
}
|
||||
};
|
||||
|
||||
private static final class ImplicitMethodExecutor implements
|
||||
MethodExecutor {
|
||||
private static final class ImplicitMethodExecutor implements MethodExecutor {
|
||||
private final MethodExecutor executor;
|
||||
|
||||
public ImplicitMethodExecutor(final MethodExecutor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue execute(final EvaluationContext context, final Object target,
|
||||
final Object... arguments) throws AccessException {
|
||||
Object[] modifiedArguments = new Object[arguments.length + 1];
|
||||
|
@ -57,8 +63,10 @@ final class ImplicitMethodResolver implements MethodResolver {
|
|||
}
|
||||
}
|
||||
|
||||
public MethodExecutor resolve(final EvaluationContext context,
|
||||
final Object targetObject, final String name, final Class<?>[] argumentTypes)
|
||||
@Override
|
||||
public MethodExecutor resolve(
|
||||
final EvaluationContext context, final Object targetObject,
|
||||
final String name, final List<TypeDescriptor> argumentTypes)
|
||||
throws AccessException {
|
||||
if (targetObject == null) {
|
||||
return null;
|
||||
|
@ -78,13 +86,13 @@ final class ImplicitMethodResolver implements MethodResolver {
|
|||
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);
|
||||
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) {
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
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;
|
||||
|
@ -32,27 +34,38 @@ final class ImplicitPropertyAccessor extends ReadOnlyGenericPropertyAccessor {
|
|||
private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
|
||||
new ConcurrentHashMap<String, MethodExecutor>();
|
||||
|
||||
private static final MethodExecutor NULL_ME = new MethodExecutor() {
|
||||
@Override
|
||||
public TypedValue execute(final EvaluationContext context, final Object target,
|
||||
final Object... arguments) throws AccessException {
|
||||
throw new UnsupportedOperationException("This method should never be called");
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
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;
|
||||
return CACHE.get(cacheKey) != NULL_ME;
|
||||
}
|
||||
|
||||
for (MethodResolver mr : context.getMethodResolvers()) {
|
||||
MethodExecutor me = mr.resolve(context, target, name, new Class[0]);
|
||||
MethodExecutor me =
|
||||
mr.resolve(context, target, name, Collections.<TypeDescriptor>emptyList());
|
||||
if (me != null) {
|
||||
CACHE.putIfAbsent(cacheKey, me);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
CACHE.putIfAbsent(cacheKey, null);
|
||||
CACHE.putIfAbsent(cacheKey, NULL_ME);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue read(final EvaluationContext context,
|
||||
final Object target, final String name)
|
||||
throws AccessException {
|
||||
|
|
|
@ -23,19 +23,21 @@ import org.springframework.expression.AccessException;
|
|||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
|
||||
abstract class ReadOnlyGenericPropertyAccessor implements
|
||||
PropertyAccessor {
|
||||
abstract class ReadOnlyGenericPropertyAccessor implements PropertyAccessor {
|
||||
|
||||
@Override
|
||||
public final boolean canWrite(final EvaluationContext context,
|
||||
final Object target, final String name) throws AccessException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public final Class[] getSpecificTargetClasses() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void write(final EvaluationContext context, final Object target,
|
||||
final String name, final Object newValue) throws AccessException {
|
||||
throw new AccessException(MessageFormat.format(
|
||||
|
|
Loading…
Reference in New Issue