From cc56da7735291d1576d08f0f853e6dad07de0aa6 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Wed, 25 May 2022 09:24:15 +0100 Subject: [PATCH] Support default methods in @HttpExchange interface Closes gh-28491 --- .../service/invoker/HttpServiceProxyFactory.java | 15 +++++++++++++-- .../service/invoker/HttpServiceMethodTests.java | 6 ++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java index 1892913435f..30d8029346d 100644 --- a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java +++ b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java @@ -16,6 +16,7 @@ package org.springframework.web.service.invoker; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.time.Duration; import java.util.ArrayList; @@ -28,6 +29,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.framework.ReflectiveMethodInvocation; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.core.MethodIntrospector; @@ -215,10 +217,19 @@ public final class HttpServiceProxyFactory implements InitializingBean, Embedded } @Override - public Object invoke(MethodInvocation invocation) { + public Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); HttpServiceMethod httpServiceMethod = this.httpServiceMethods.get(method); - return httpServiceMethod.invoke(invocation.getArguments()); + if (httpServiceMethod != null) { + return httpServiceMethod.invoke(invocation.getArguments()); + } + if (method.isDefault()) { + if (invocation instanceof ReflectiveMethodInvocation reflectiveMethodInvocation) { + Object proxy = reflectiveMethodInvocation.getProxy(); + return InvocationHandler.invokeDefault(proxy, method, invocation.getArguments()); + } + } + throw new IllegalStateException("Unexpected method invocation: " + method); } } diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java index ea8711b395b..84ab3eade0b 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java @@ -100,6 +100,8 @@ public class HttpServiceMethodTests { Mono>> fluxEntity= service.getFluxEntity(); StepVerifier.create(fluxEntity.flatMapMany(HttpEntity::getBody)).expectNext("request", "To", "Entity", "Flux").verifyComplete(); verifyClientInvocation("requestToEntityFlux", BODY_TYPE); + + assertThat(service.getDefaultMethodValue()).isEqualTo("default value"); } @Test @@ -228,6 +230,10 @@ public class HttpServiceMethodTests { @GetExchange Mono>> getFluxEntity(); + + default String getDefaultMethodValue() { + return "default value"; + } }