SpEL support for methods and properties on class …
Update the ReflectiveMethodResolver and ReflectivePropertyAccessor to allow methods and properties of java.lang.Class to be resolved when the target object is a class. Issue: SPR-9017
This commit is contained in:
parent
98808347ca
commit
d28592a6c6
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -21,8 +21,10 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
@ -90,7 +92,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
|||
try {
|
||||
TypeConverter typeConverter = context.getTypeConverter();
|
||||
Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass());
|
||||
Method[] methods = getMethods(type);
|
||||
Method[] methods = getMethods(type, targetObject);
|
||||
|
||||
// If a filter is registered for this type, call it
|
||||
MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
|
||||
|
@ -197,6 +199,16 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
|||
}
|
||||
}
|
||||
|
||||
private Method[] getMethods(Class<?> type, Object targetObject) {
|
||||
if(targetObject instanceof Class) {
|
||||
Set<Method> methods = new HashSet<Method>();
|
||||
methods.addAll(Arrays.asList(getMethods(type)));
|
||||
methods.addAll(Arrays.asList(getMethods(targetObject.getClass())));
|
||||
return methods.toArray(new Method[methods.size()]);
|
||||
}
|
||||
return getMethods(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of methods for this type. The default implementation returns the
|
||||
* result of Class#getMethods for the given {@code type}, but subclasses may override
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -71,7 +71,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
if (this.readerCache.containsKey(cacheKey)) {
|
||||
return true;
|
||||
}
|
||||
Method method = findGetterForProperty(name, type, target instanceof Class);
|
||||
Method method = findGetterForProperty(name, type, target);
|
||||
if (method != null) {
|
||||
// Treat it like a property
|
||||
// The readerCache will only contain gettable properties (let's not worry about setters for now)
|
||||
|
@ -82,7 +82,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
Field field = findField(name, type, target instanceof Class);
|
||||
Field field = findField(name, type, target);
|
||||
if (field != null) {
|
||||
TypeDescriptor typeDescriptor = new TypeDescriptor(field);
|
||||
this.readerCache.put(cacheKey, new InvokerPair(field,typeDescriptor));
|
||||
|
@ -112,7 +112,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
if (invoker == null || invoker.member instanceof Method) {
|
||||
Method method = (Method) (invoker != null ? invoker.member : null);
|
||||
if (method == null) {
|
||||
method = findGetterForProperty(name, type, target instanceof Class);
|
||||
method = findGetterForProperty(name, type, target);
|
||||
if (method != null) {
|
||||
// TODO remove the duplication here between canRead and read
|
||||
// Treat it like a property
|
||||
|
@ -138,7 +138,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
if (invoker == null || invoker.member instanceof Field) {
|
||||
Field field = (Field) (invoker == null ? null : invoker.member);
|
||||
if (field == null) {
|
||||
field = findField(name, type, target instanceof Class);
|
||||
field = findField(name, type, target);
|
||||
if (field != null) {
|
||||
invoker = new InvokerPair(field, new TypeDescriptor(field));
|
||||
this.readerCache.put(cacheKey, invoker);
|
||||
|
@ -168,7 +168,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
if (this.writerCache.containsKey(cacheKey)) {
|
||||
return true;
|
||||
}
|
||||
Method method = findSetterForProperty(name, type, target instanceof Class);
|
||||
Method method = findSetterForProperty(name, type, target);
|
||||
if (method != null) {
|
||||
// Treat it like a property
|
||||
Property property = new Property(type, null, method);
|
||||
|
@ -178,7 +178,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
Field field = findField(name, type, target instanceof Class);
|
||||
Field field = findField(name, type, target);
|
||||
if (field != null) {
|
||||
this.writerCache.put(cacheKey, field);
|
||||
this.typeDescriptorCache.put(cacheKey, new TypeDescriptor(field));
|
||||
|
@ -211,7 +211,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
if (cachedMember == null || cachedMember instanceof Method) {
|
||||
Method method = (Method) cachedMember;
|
||||
if (method == null) {
|
||||
method = findSetterForProperty(name, type, target instanceof Class);
|
||||
method = findSetterForProperty(name, type, target);
|
||||
if (method != null) {
|
||||
cachedMember = method;
|
||||
this.writerCache.put(cacheKey, cachedMember);
|
||||
|
@ -232,7 +232,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
if (cachedMember == null || cachedMember instanceof Field) {
|
||||
Field field = (Field) cachedMember;
|
||||
if (field == null) {
|
||||
field = findField(name, type, target instanceof Class);
|
||||
field = findField(name, type, target);
|
||||
if (field != null) {
|
||||
cachedMember = field;
|
||||
this.writerCache.put(cacheKey, cachedMember);
|
||||
|
@ -281,6 +281,30 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
return typeDescriptor;
|
||||
}
|
||||
|
||||
private Method findGetterForProperty(String propertyName, Class<?> clazz, Object target) {
|
||||
Method method = findGetterForProperty(propertyName, clazz, target instanceof Class);
|
||||
if(method == null && target instanceof Class) {
|
||||
method = findGetterForProperty(propertyName, target.getClass(), false);
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
private Method findSetterForProperty(String propertyName, Class<?> clazz, Object target) {
|
||||
Method method = findSetterForProperty(propertyName, clazz, target instanceof Class);
|
||||
if(method == null && target instanceof Class) {
|
||||
method = findSetterForProperty(propertyName, target.getClass(), false);
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
private Field findField(String name, Class<?> clazz, Object target) {
|
||||
Field field = findField(name, clazz, target instanceof Class);
|
||||
if(field == null && target instanceof Class) {
|
||||
field = findField(name, target.getClass(), false);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a getter method for the specified property.
|
||||
*/
|
||||
|
@ -410,7 +434,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
|||
if (invocationTarget == null || invocationTarget.member instanceof Method) {
|
||||
Method method = (Method) (invocationTarget==null?null:invocationTarget.member);
|
||||
if (method == null) {
|
||||
method = findGetterForProperty(name, type, target instanceof Class);
|
||||
method = findGetterForProperty(name, type, target);
|
||||
if (method != null) {
|
||||
invocationTarget = new InvokerPair(method,new TypeDescriptor(new MethodParameter(method,-1)));
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -361,4 +363,10 @@ public class MethodInvocationTests extends ExpressionTestCase {
|
|||
evaluateAndCheckError("null.toString()",SpelMessage.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodOfClass() throws Exception {
|
||||
Expression expression = parser.parseExpression("getName()");
|
||||
Object value = expression.getValue(new StandardEvaluationContext(String.class));
|
||||
assertEquals(value, "java.lang.String");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -155,6 +157,13 @@ public class PropertyAccessTests extends ExpressionTestCase {
|
|||
Assert.assertEquals(2,ctx.getPropertyAccessors().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessingPropertyOfClass() throws Exception {
|
||||
Expression expression = parser.parseExpression("name");
|
||||
Object value = expression.getValue(new StandardEvaluationContext(String.class));
|
||||
assertEquals(value, "java.lang.String");
|
||||
}
|
||||
|
||||
|
||||
// This can resolve the property 'flibbles' on any String (very useful...)
|
||||
private static class StringyPropertyAccessor implements PropertyAccessor {
|
||||
|
|
Loading…
Reference in New Issue