Find interface method even for late-bound interface declaration in subclass

Closes gh-27995
This commit is contained in:
Juergen Hoeller
2022-02-04 23:21:27 +01:00
parent a71a45e719
commit bc9cd9a687
6 changed files with 78 additions and 42 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 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.
@@ -58,8 +58,18 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
* @param method the method to invoke
*/
public ReflectiveMethodExecutor(Method method) {
this(method, null);
}
/**
* Create a new executor for the given method.
* @param method the method to invoke
* @param targetClass the target class to invoke the method on
* @since 5.3.16
*/
public ReflectiveMethodExecutor(Method method, @Nullable Class<?> targetClass) {
this.originalMethod = method;
this.methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(method);
this.methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(method, targetClass);
if (method.isVarArgs()) {
this.varargsPosition = method.getParameterCount() - 1;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 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.
@@ -176,7 +176,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
}
if (matchInfo != null) {
if (matchInfo.isExactMatch()) {
return new ReflectiveMethodExecutor(method);
return new ReflectiveMethodExecutor(method, type);
}
else if (matchInfo.isCloseMatch()) {
if (this.useDistance) {
@@ -204,13 +204,13 @@ public class ReflectiveMethodResolver implements MethodResolver {
}
}
if (closeMatch != null) {
return new ReflectiveMethodExecutor(closeMatch);
return new ReflectiveMethodExecutor(closeMatch, type);
}
else if (matchRequiringConversion != null) {
if (multipleOptions) {
throw new SpelEvaluationException(SpelMessage.MULTIPLE_POSSIBLE_METHODS, name);
}
return new ReflectiveMethodExecutor(matchRequiringConversion);
return new ReflectiveMethodExecutor(matchRequiringConversion, type);
}
else {
return null;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 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.
@@ -139,7 +139,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
// The readerCache will only contain gettable properties (let's not worry about setters for now).
Property property = new Property(type, method, null);
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
method = ClassUtils.getInterfaceMethodIfPossible(method);
method = ClassUtils.getInterfaceMethodIfPossible(method, type);
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
@@ -182,7 +182,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
// The readerCache will only contain gettable properties (let's not worry about setters for now).
Property property = new Property(type, method, null);
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
method = ClassUtils.getInterfaceMethodIfPossible(method);
method = ClassUtils.getInterfaceMethodIfPossible(method, type);
invoker = new InvokerPair(method, typeDescriptor);
this.lastReadInvokerPair = invoker;
this.readerCache.put(cacheKey, invoker);
@@ -242,7 +242,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
// Treat it like a property
Property property = new Property(type, null, method);
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
method = ClassUtils.getInterfaceMethodIfPossible(method);
method = ClassUtils.getInterfaceMethodIfPossible(method, type);
this.writerCache.put(cacheKey, method);
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
@@ -291,7 +291,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (method == null) {
method = findSetterForProperty(name, type, target);
if (method != null) {
method = ClassUtils.getInterfaceMethodIfPossible(method);
method = ClassUtils.getInterfaceMethodIfPossible(method, type);
cachedMember = method;
this.writerCache.put(cacheKey, cachedMember);
}
@@ -533,21 +533,21 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (target == null) {
return this;
}
Class<?> clazz = (target instanceof Class ? (Class<?>) target : target.getClass());
if (clazz.isArray()) {
Class<?> type = (target instanceof Class ? (Class<?>) target : target.getClass());
if (type.isArray()) {
return this;
}
PropertyCacheKey cacheKey = new PropertyCacheKey(clazz, name, target instanceof Class);
PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
InvokerPair invocationTarget = this.readerCache.get(cacheKey);
if (invocationTarget == null || invocationTarget.member instanceof Method) {
Method method = (Method) (invocationTarget != null ? invocationTarget.member : null);
if (method == null) {
method = findGetterForProperty(name, clazz, target);
method = findGetterForProperty(name, type, target);
if (method != null) {
TypeDescriptor typeDescriptor = new TypeDescriptor(new MethodParameter(method, -1));
method = ClassUtils.getInterfaceMethodIfPossible(method);
method = ClassUtils.getInterfaceMethodIfPossible(method, type);
invocationTarget = new InvokerPair(method, typeDescriptor);
ReflectionUtils.makeAccessible(method);
this.readerCache.put(cacheKey, invocationTarget);
@@ -561,7 +561,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (invocationTarget == null || invocationTarget.member instanceof Field) {
Field field = (invocationTarget != null ? (Field) invocationTarget.member : null);
if (field == null) {
field = findField(name, clazz, target instanceof Class);
field = findField(name, type, target instanceof Class);
if (field != null) {
invocationTarget = new InvokerPair(field, new TypeDescriptor(field));
ReflectionUtils.makeAccessible(field);
@@ -600,7 +600,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
private final String property;
private boolean targetIsClass;
private final boolean targetIsClass;
public PropertyCacheKey(Class<?> clazz, String name, boolean targetIsClass) {
this.clazz = clazz;