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). 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: The addition functionalities provided are:
1. Implicit methods 1. Implicit methods
@ -10,7 +22,7 @@ The addition functionalities provided are:
3. Simplified extension functions 3. Simplified extension functions
4. Simplified constructors 4. Simplified constructors
**Implicit Methods** _**Implicit methods**_
Implicit methods allow one to registers methods with SpelHelper and attach Implicit methods allow one to registers methods with SpelHelper and attach
them to particular classes. After that, when that method is called on an 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 first parameter and its return value is used in further evaluation of the
expression. expression.
**Implicit Properties** _**Implicit properties**_
Implicit properties allow one to treat no argument methods of an object Implicit properties allow one to treat no argument methods of an object
as properties of the object. SpelHelper intercepts the property resolution 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 Implicit property resolution considers both the actual methods of the object
and the implicit methods registered on the object's class. 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 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 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: can be called from inside a SpEL expression using the function call syntax:
`"#list(1,2,3)`". `"#list(1,2,3)`".
**Simplified constructors** _**Simplified constructors**_
SpEL [allows][3] calling constructors from inside a SpEL expression using the 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` operator. But they have to be called with their full name like:

View File

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

View File

@ -27,8 +27,7 @@ import org.springframework.expression.ConstructorResolver;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.support.ReflectiveConstructorResolver; import org.springframework.expression.spel.support.ReflectiveConstructorResolver;
final class ImplicitConstructorResolver implements final class ImplicitConstructorResolver implements ConstructorResolver {
ConstructorResolver {
private final ReflectiveConstructorResolver delegate = new ReflectiveConstructorResolver(); private final ReflectiveConstructorResolver delegate = new ReflectiveConstructorResolver();

View File

@ -39,20 +39,21 @@ final class ImplicitMethodResolver implements MethodResolver {
private final ReflectiveMethodResolver delegate = new ReflectiveMethodResolver(); private final ReflectiveMethodResolver delegate = new ReflectiveMethodResolver();
private static final MethodExecutor NULL_ME = new MethodExecutor() { private static final MethodExecutor NULL_ME = new MethodExecutor() {
@Override
public TypedValue execute(final EvaluationContext context, final Object target, public TypedValue execute(final EvaluationContext context, final Object target,
final Object... arguments) throws AccessException { final Object... arguments) throws AccessException {
return null; throw new UnsupportedOperationException("This method should never be called");
} }
}; };
private static final class ImplicitMethodExecutor implements private static final class ImplicitMethodExecutor implements MethodExecutor {
MethodExecutor {
private final MethodExecutor executor; private final MethodExecutor executor;
public ImplicitMethodExecutor(final MethodExecutor executor) { public ImplicitMethodExecutor(final MethodExecutor executor) {
this.executor = executor; this.executor = executor;
} }
@Override
public TypedValue execute(final EvaluationContext context, final Object target, public TypedValue execute(final EvaluationContext context, final Object target,
final Object... arguments) throws AccessException { final Object... arguments) throws AccessException {
Object[] modifiedArguments = new Object[arguments.length + 1]; Object[] modifiedArguments = new Object[arguments.length + 1];
@ -66,7 +67,7 @@ final class ImplicitMethodResolver implements MethodResolver {
public MethodExecutor resolve( public MethodExecutor resolve(
final EvaluationContext context, final Object targetObject, final EvaluationContext context, final Object targetObject,
final String name, final List<TypeDescriptor> argumentTypes) final String name, final List<TypeDescriptor> argumentTypes)
throws AccessException { throws AccessException {
if (targetObject == null) { if (targetObject == null) {
return null; return null;
} }

View File

@ -34,13 +34,22 @@ final class ImplicitPropertyAccessor extends ReadOnlyGenericPropertyAccessor {
private static final ConcurrentHashMap<String, MethodExecutor> CACHE = private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
new ConcurrentHashMap<String, MethodExecutor>(); 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, public boolean canRead(final EvaluationContext context,
final Object target, final String name) final Object target, final String name)
throws AccessException { throws AccessException {
Assert.notNull(target, "target is null"); Assert.notNull(target, "target is null");
String cacheKey = target.getClass().getName() + "." + name; String cacheKey = target.getClass().getName() + "." + name;
if (CACHE.containsKey(cacheKey)) { if (CACHE.containsKey(cacheKey)) {
return CACHE.get(cacheKey) != null; return CACHE.get(cacheKey) != NULL_ME;
} }
for (MethodResolver mr : context.getMethodResolvers()) { 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; return false;
} }
@Override
public TypedValue read(final EvaluationContext context, public TypedValue read(final EvaluationContext context,
final Object target, final String name) final Object target, final String name)
throws AccessException { throws AccessException {

View File

@ -23,19 +23,21 @@ import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.PropertyAccessor; import org.springframework.expression.PropertyAccessor;
abstract class ReadOnlyGenericPropertyAccessor implements abstract class ReadOnlyGenericPropertyAccessor implements PropertyAccessor {
PropertyAccessor {
@Override
public final boolean canWrite(final EvaluationContext context, public final boolean canWrite(final EvaluationContext context,
final Object target, final String name) throws AccessException { final Object target, final String name) throws AccessException {
return false; return false;
} }
@Override
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public final Class[] getSpecificTargetClasses() { public final Class[] getSpecificTargetClasses() {
return null; return null;
} }
@Override
public final void write(final EvaluationContext context, final Object target, public final void write(final EvaluationContext context, final Object target,
final String name, final Object newValue) throws AccessException { final String name, final Object newValue) throws AccessException {
throw new AccessException(MessageFormat.format( throw new AccessException(MessageFormat.format(