andymc12 closed pull request #480: [CXF-7922] Invoke default interface methods on client interfaces URL: https://github.com/apache/cxf/pull/480
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java index a567f83a04f..6aaee1c623d 100644 --- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java +++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java @@ -21,11 +21,16 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Annotation; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.net.URI; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -154,6 +159,55 @@ private void initValuesMap(Object... varValues) { } } + private static class WrappedException extends Exception { + final Throwable wrapped; + WrappedException(Throwable wrapped) { + this.wrapped = wrapped; + } + Throwable getWrapped() { + return wrapped; + } + } + + private static Object invokeDefaultMethod(Class<?> declaringClass, Object o, Method m, Object[] params) + throws Throwable { + + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { + @Override + public Object run() throws Exception { + try { + final MethodHandles.Lookup lookup = MethodHandles.publicLookup() + .in(declaringClass); + + // force private access so unreflectSpecial can invoke the interface's default method + final Field f = MethodHandles.Lookup.class.getDeclaredField("allowedModes"); + final int modifiers = f.getModifiers(); + if (Modifier.isFinal(modifiers)) { + final Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(f, modifiers & ~Modifier.FINAL); + f.setAccessible(true); + f.set(lookup, MethodHandles.Lookup.PRIVATE); + } + + return lookup.unreflectSpecial(m, declaringClass) + .bindTo(o) + .invokeWithArguments(params); + } catch (Throwable t) { + throw new WrappedException(t); + } + } + }); + } catch (PrivilegedActionException pae) { + Throwable wrapped = pae.getCause(); + if (wrapped instanceof WrappedException) { + throw ((WrappedException)wrapped).getWrapped(); + } + throw wrapped; + } + } + /** * Updates the current state if Client method is invoked, otherwise * does the remote invocation or returns a new proxy if subresource @@ -171,6 +225,9 @@ public Object invoke(Object o, Method m, Object[] params) throws Throwable { resetResponse(); OperationResourceInfo ori = cri.getMethodDispatcher().getOperationResourceInfo(m); if (ori == null) { + if (m.isDefault()) { + return invokeDefaultMethod(declaringClass, o, m, params); + } reportInvalidResourceMethod(m, "INVALID_RESOURCE_METHOD"); } diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilderTest.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilderTest.java index b1e88558127..54be86ecd65 100644 --- a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilderTest.java +++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilderTest.java @@ -18,6 +18,7 @@ */ package org.apache.cxf.microprofile.client; +import java.io.IOException; import java.net.URI; import java.net.URL; @@ -163,6 +164,24 @@ public void testClientPropertiesAreSet() throws Exception { WebClientUtil.getClientConfigFromProxy(client).getRequestContext().get("hello")); } + @Test + public void testCanInvokeDefaultInterfaceMethods() throws Exception { + MyClient client = RestClientBuilder.newBuilder() + .register(InvokedMethodClientRequestFilter.class) + .baseUri(new URI("http://localhost:8080/neverUsed")) + .build(MyClient.class); + assertEquals("defaultValue", client.myDefaultMethod(false)); + } + + @Test(expected = IOException.class) + public void testCanInvokeDefaultInterfaceMethodsWithException() throws Exception { + MyClient client = RestClientBuilder.newBuilder() + .register(InvokedMethodClientRequestFilter.class) + .baseUri(new URI("http://localhost:8080/neverUsed")) + .build(MyClient.class); + client.myDefaultMethod(true); + fail("Should have thrown IOException"); + } private void fail(Response r, String failureMessage) { System.out.println(r.getStatus()); fail(failureMessage); diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MyClient.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MyClient.java index c3808456f6e..beafc977d75 100644 --- a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MyClient.java +++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MyClient.java @@ -18,6 +18,8 @@ */ package org.apache.cxf.microprofile.client.mock; +import java.io.IOException; + import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Response; @@ -26,4 +28,11 @@ public interface MyClient { @GET Response get(); + + default String myDefaultMethod(boolean throwException) throws IOException { + if (throwException) { + throw new IOException("expected"); + } + return "defaultValue"; + } } ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services