Compare commits

...

6 Commits

6 changed files with 39 additions and 15 deletions

View File

@ -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:

View File

@ -3,7 +3,7 @@
<groupId>net.abhinavsarkar</groupId>
<artifactId>SpelHelper</artifactId>
<version>1.1</version>
<version>1.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SpelHelper</name>

View File

@ -27,8 +27,7 @@ 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();

View File

@ -39,20 +39,21 @@ final class ImplicitMethodResolver implements MethodResolver {
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];
@ -66,7 +67,7 @@ final class ImplicitMethodResolver implements MethodResolver {
public MethodExecutor resolve(
final EvaluationContext context, final Object targetObject,
final String name, final List<TypeDescriptor> argumentTypes)
throws AccessException {
throws AccessException {
if (targetObject == null) {
return null;
}

View File

@ -34,13 +34,22 @@ 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()) {
@ -52,10 +61,11 @@ final class ImplicitPropertyAccessor extends ReadOnlyGenericPropertyAccessor {
}
}
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 {

View File

@ -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(