Resolve bridged method when projected PropertyDescriptor resolves to a bridge method.
We now skip synthetic bridge methods when resolving a PropertyDescriptor from a called interface method on the target type and resolve the bridged method. Closes #3215
This commit is contained in:
@@ -20,8 +20,10 @@ import java.lang.reflect.Method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -63,7 +65,8 @@ class PropertyAccessingMethodInterceptor implements MethodInterceptor {
|
||||
PropertyDescriptor descriptor = BeanUtils.findPropertyForMethod(method);
|
||||
|
||||
if (descriptor == null) {
|
||||
throw new IllegalStateException("Invoked method is not a property accessor");
|
||||
throw new IllegalStateException("Invoked method '%s' is not a property accessor on '%s'"
|
||||
.formatted(invocation.getMethod(), target.getWrappedClass().getName()));
|
||||
}
|
||||
|
||||
if (!isSetterMethod(method, descriptor)) {
|
||||
@@ -84,9 +87,14 @@ class PropertyAccessingMethodInterceptor implements MethodInterceptor {
|
||||
|
||||
private static Method lookupTargetMethod(MethodInvocation invocation, Class<?> targetType) {
|
||||
|
||||
Method method = BeanUtils.findMethod(targetType, invocation.getMethod().getName(),
|
||||
invocation.getMethod().getParameterTypes());
|
||||
Method invokedMethod = invocation.getMethod();
|
||||
Method method = BeanUtils.findMethod(targetType, invokedMethod.getName(), invokedMethod.getParameterTypes());
|
||||
|
||||
return method != null ? method : invocation.getMethod();
|
||||
if (method == null) {
|
||||
return invokedMethod;
|
||||
}
|
||||
|
||||
return BridgeMethodResolver.findBridgedMethod(method);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -121,6 +121,19 @@ class PropertyAccessingMethodInterceptorUnitTests {
|
||||
assertThat(new PropertyAccessingMethodInterceptor(source).invoke(invocation)).isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test // GH-3697
|
||||
void considersPropertyDescriptorsFromPackageProtectedSuperclass() throws Throwable {
|
||||
|
||||
var source = new SomeExposedClass();
|
||||
source.setFirstname("Walter");
|
||||
|
||||
when(invocation.getMethod()).thenReturn(Projection.class.getMethod("getFirstname"));
|
||||
|
||||
Object result = new PropertyAccessingMethodInterceptor(source).invoke(invocation);
|
||||
|
||||
assertThat(result).isEqualTo(source.getFirstname());
|
||||
}
|
||||
|
||||
static class Source {
|
||||
|
||||
String firstname;
|
||||
@@ -138,4 +151,30 @@ class PropertyAccessingMethodInterceptorUnitTests {
|
||||
|
||||
String someGarbage();
|
||||
}
|
||||
|
||||
static class SomeBaseclass {
|
||||
|
||||
private String firstname;
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SomeExposedClass extends SomeBaseclass {
|
||||
|
||||
private String lastname;
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public void setLastname(String lastname) {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user