From be6615c434fa7b8fc84d6771c513f3521c9ef778 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Mon, 20 Sep 2021 13:27:35 +0200 Subject: [PATCH] #1646 - Avoid trying to proxy Object for controller method dummy invocations. On JDK 17, trying to proxy Object doesn't work anymore. We now simply return the interceptor that would've been applied to the proxy directly and detect that properly in requests to extract the LastInvocationAware instance. --- .../server/core/DummyInvocationUtils.java | 18 +++++++++++++++++- .../mvc/DummyInvocationUtilsUnitTest.java | 17 +++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/hateoas/server/core/DummyInvocationUtils.java b/src/main/java/org/springframework/hateoas/server/core/DummyInvocationUtils.java index ba691c87..5de46371 100644 --- a/src/main/java/org/springframework/hateoas/server/core/DummyInvocationUtils.java +++ b/src/main/java/org/springframework/hateoas/server/core/DummyInvocationUtils.java @@ -144,13 +144,24 @@ public class DummyInvocationUtils { */ @Nullable public static LastInvocationAware getLastInvocationAware(Object source) { - return (LastInvocationAware) ((Advised) source).getAdvisors()[0].getAdvice(); + + if (InvocationRecordingMethodInterceptor.class.isInstance(source)) { + return LastInvocationAware.class.cast(source); + } + + return (LastInvocationAware) (Advised.class.isInstance(source) + ? ((Advised) source).getAdvisors()[0].getAdvice() + : source); } @SuppressWarnings("unchecked") private static T getProxyWithInterceptor(Class type, InvocationRecordingMethodInterceptor interceptor, ClassLoader classLoader) { + if (type.equals(Object.class)) { + return (T) interceptor; + } + ProxyFactory factory = new ProxyFactory(); factory.addAdvice(interceptor); factory.addInterface(LastInvocationAware.class); @@ -207,6 +218,11 @@ public class DummyInvocationUtils { return result; } + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override public String toString() { return "DummyInvocationUtils.CacheKey(type=" + this.type + ", arguments=" + Arrays.deepToString(this.arguments) diff --git a/src/test/java/org/springframework/hateoas/server/mvc/DummyInvocationUtilsUnitTest.java b/src/test/java/org/springframework/hateoas/server/mvc/DummyInvocationUtilsUnitTest.java index c654d6a9..caa932f2 100755 --- a/src/test/java/org/springframework/hateoas/server/mvc/DummyInvocationUtilsUnitTest.java +++ b/src/test/java/org/springframework/hateoas/server/mvc/DummyInvocationUtilsUnitTest.java @@ -19,8 +19,11 @@ import static org.assertj.core.api.Assertions.*; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; import org.junit.jupiter.api.Test; +import org.springframework.aop.framework.Advised; import org.springframework.hateoas.Link; import org.springframework.hateoas.TestUtils; +import org.springframework.hateoas.server.core.DummyInvocationUtils; +import org.springframework.hateoas.server.core.LastInvocationAware; import org.springframework.http.HttpEntity; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -48,6 +51,16 @@ class DummyInvocationUtilsUnitTest extends TestUtils { assertThat(link.getHref()).isEqualTo("http://localhost/sample/2/bar"); } + @Test // #1638 + void doesNotTryToProxyObject() { + + Object result = methodOn(SampleController.class).methodReturningObject(); + + assertThat(result).isInstanceOf(LastInvocationAware.class); + assertThat(result).isNotInstanceOf(Advised.class); + assertThat(DummyInvocationUtils.getLastInvocationAware(result)).isSameAs(result); + } + @RequestMapping("/sample") static class SampleController { @@ -60,5 +73,9 @@ class DummyInvocationUtilsUnitTest extends TestUtils { HttpEntity someOtherMethod(@PathVariable(name = "otherName") Long id) { return new ResponseEntity<>(HttpStatus.OK); } + + Object methodReturningObject() { + return Void.class; + } } }