cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From amccri...@apache.org
Subject [cxf] branch 3.2.x-fixes updated: [CXF-7922] Invoke default interface methods on client interfaces
Date Thu, 13 Dec 2018 17:36:21 GMT
This is an automated email from the ASF dual-hosted git repository.

amccright pushed a commit to branch 3.2.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/3.2.x-fixes by this push:
     new defc56a  [CXF-7922] Invoke default interface methods on client interfaces
defc56a is described below

commit defc56a7e54a2b793454c60e6e88481913191819
Author: Andy McCright <j.andrew.mccright@gmail.com>
AuthorDate: Thu Dec 6 13:47:59 2018 -0600

    [CXF-7922] Invoke default interface methods on client interfaces
    
    (cherry picked from commit df66817b837d118f49b4790a04a35602db8f0187)
---
 .../apache/cxf/jaxrs/client/ClientProxyImpl.java   | 57 ++++++++++++++++++++++
 .../client/CxfTypeSafeClientBuilderTest.java       | 19 ++++++++
 .../cxf/microprofile/client/mock/MyClient.java     |  9 ++++
 3 files changed, 85 insertions(+)

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 a567f83..6aaee1c 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 @@ package org.apache.cxf.jaxrs.client;
 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 @@ public class ClientProxyImpl extends AbstractClient implements
         }
     }
 
+    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 class ClientProxyImpl extends AbstractClient implements
         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 b1e8855..54be86e 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 class CxfTypeSafeClientBuilderTest extends Assert {
             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 c380845..beafc97 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 @@ import javax.ws.rs.core.Response;
 public interface MyClient {
     @GET
     Response get();
+
+    default String myDefaultMethod(boolean throwException) throws IOException {
+        if (throwException) {
+            throw new IOException("expected");
+        }
+        return "defaultValue";
+    }
 }


Mime
View raw message