Fixed an NPE in ImplicitPropertyAccessor due to putting null value in ConcurrentHashMap

This commit is contained in:
Abhinav Sarkar 2012-05-18 00:27:51 +05:30
parent 2c3d0f10d9
commit 410dcdada2
4 changed files with 22 additions and 10 deletions

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(