From 0c96f79a2aec0d72e947d976c8279764ae76d059 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Wed, 4 May 2022 14:57:45 +0200 Subject: [PATCH] MethodInvocationRecorder now supports traversing primitive properties. We now return a default value for invocations of methods returning a primitive value to pass the AOP infrastructure's check for compatible values. Before, that barked at the null value returned for the invocation. Fixes #2612. --- .../data/util/MethodInvocationRecorder.java | 15 ++++++++++----- .../util/MethodInvocationRecorderUnitTests.java | 9 +++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/springframework/data/util/MethodInvocationRecorder.java b/src/main/java/org/springframework/data/util/MethodInvocationRecorder.java index d7c33f910..2399de3a8 100644 --- a/src/main/java/org/springframework/data/util/MethodInvocationRecorder.java +++ b/src/main/java/org/springframework/data/util/MethodInvocationRecorder.java @@ -15,6 +15,7 @@ */ package org.springframework.data.util; +import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; @@ -158,7 +159,7 @@ public class MethodInvocationRecorder { private InvocationInformation registerInvocation(Method method, Class proxyType) { - Recorded create = Modifier.isFinal(proxyType.getModifiers()) ? new Unrecorded() : create(proxyType); + Recorded create = Modifier.isFinal(proxyType.getModifiers()) ? new Unrecorded(proxyType) : create(proxyType); InvocationInformation information = new InvocationInformation(create, method); return this.information = information; @@ -167,7 +168,7 @@ public class MethodInvocationRecorder { private static final class InvocationInformation { - private static final InvocationInformation NOT_INVOKED = new InvocationInformation(new Unrecorded(), null); + private static final InvocationInformation NOT_INVOKED = new InvocationInformation(new Unrecorded(null), null); private final Recorded recorded; private final @Nullable Method invokedMethod; @@ -251,7 +252,7 @@ public class MethodInvocationRecorder { int result = ObjectUtils.nullSafeHashCode(recorded); - result = 31 * result + ObjectUtils.nullSafeHashCode(invokedMethod); + result = (31 * result) + ObjectUtils.nullSafeHashCode(invokedMethod); return result; } @@ -386,8 +387,8 @@ public class MethodInvocationRecorder { static class Unrecorded extends Recorded { - private Unrecorded() { - super(null, null); + private Unrecorded(@Nullable Class type) { + super(type == null ? null : type.isPrimitive() ? getDefaultValue(type) : null, null); } /* @@ -398,5 +399,9 @@ public class MethodInvocationRecorder { public Optional getPropertyPath(List strategies) { return Optional.empty(); } + + private static Object getDefaultValue(Class clazz) { + return Array.get(Array.newInstance(clazz, 1), 0); + } } } diff --git a/src/test/java/org/springframework/data/util/MethodInvocationRecorderUnitTests.java b/src/test/java/org/springframework/data/util/MethodInvocationRecorderUnitTests.java index 63425143b..9d204ec0a 100644 --- a/src/test/java/org/springframework/data/util/MethodInvocationRecorderUnitTests.java +++ b/src/test/java/org/springframework/data/util/MethodInvocationRecorderUnitTests.java @@ -86,6 +86,14 @@ class MethodInvocationRecorderUnitTests { assertThat(recorder.record(Sample::getName).getPropertyPath()).hasValue("name"); } + @Test // #2612 + void registersLookupForPrimitiveValue() { + + Recorded recorder = MethodInvocationRecorder.forProxyOf(Foo.class); + + assertThat(recorder.record(Foo::getAge).getPropertyPath()).hasValue("age"); + } + static final class FinalType {} @Getter @@ -93,6 +101,7 @@ class MethodInvocationRecorderUnitTests { Bar bar; Collection bars; String name; + int age; } @Getter