This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new be2e665  [SCB-2122] consumer interface support default method (#2075)
be2e665 is described below

commit be2e665ce38e913eca150269508bad1f533a6a65
Author: wujimin <wuji...@huawei.com>
AuthorDate: Tue Nov 24 14:31:32 2020 +0800

    [SCB-2122] consumer interface support default method (#2075)
---
 .../servicecomb/it/testcase/TestDefaultMethod.java | 84 ++++++++++++++++++++++
 .../provider/pojo/DefaultMethodMeta.java           | 73 +++++++++++++++++++
 .../apache/servicecomb/provider/pojo/Invoker.java  |  7 ++
 .../swagger/generator/core/utils/MethodUtils.java  |  3 +
 4 files changed, 167 insertions(+)

diff --git 
a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultMethod.java
 
b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultMethod.java
new file mode 100644
index 0000000..5fe8879
--- /dev/null
+++ 
b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultMethod.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.it.testcase;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.servicecomb.it.Consumers;
+import org.apache.servicecomb.swagger.SwaggerUtils;
+import org.apache.servicecomb.swagger.generator.SwaggerGenerator;
+import org.junit.Test;
+
+import io.swagger.models.Swagger;
+
+public class TestDefaultMethod {
+  interface DataTypePojoIntf {
+    default int intBodyWithDefault() {
+      return intBody(100);
+    }
+
+    int intBody(int input);
+  }
+
+  private static Consumers<DataTypePojoIntf> consumersPojo = new 
Consumers<>("dataTypePojo",
+      DataTypePojoIntf.class);
+
+  @Test
+  public void should_support_default_method() {
+    assertEquals(100, consumersPojo.getIntf().intBodyWithDefault());
+  }
+
+  @Test
+  public void should_generate_swagger_without_default_method() {
+    Swagger swagger = SwaggerGenerator.generate(DataTypePojoIntf.class);
+    assertEquals("---\n"
+            + "swagger: \"2.0\"\n"
+            + "info:\n"
+            + "  version: \"1.0.0\"\n"
+            + "  title: \"swagger definition for 
org.apache.servicecomb.it.testcase.TestDefaultMethod$DataTypePojoIntf\"\n"
+            + "  x-java-interface: 
\"org.apache.servicecomb.it.testcase.TestDefaultMethod$DataTypePojoIntf\"\n"
+            + "basePath: \"/DataTypePojoIntf\"\n"
+            + "consumes:\n"
+            + "- \"application/json\"\n"
+            + "produces:\n"
+            + "- \"application/json\"\n"
+            + "paths:\n"
+            + "  /intBody:\n"
+            + "    post:\n"
+            + "      operationId: \"intBody\"\n"
+            + "      parameters:\n"
+            + "      - in: \"body\"\n"
+            + "        name: \"input\"\n"
+            + "        required: false\n"
+            + "        schema:\n"
+            + "          $ref: \"#/definitions/intBodyBody\"\n"
+            + "      responses:\n"
+            + "        \"200\":\n"
+            + "          description: \"response of 200\"\n"
+            + "          schema:\n"
+            + "            type: \"integer\"\n"
+            + "            format: \"int32\"\n"
+            + "definitions:\n"
+            + "  intBodyBody:\n"
+            + "    type: \"object\"\n"
+            + "    properties:\n"
+            + "      input:\n"
+            + "        type: \"integer\"\n"
+            + "        format: \"int32\"\n",
+        SwaggerUtils.swaggerToString(swagger));
+  }
+}
diff --git 
a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/DefaultMethodMeta.java
 
b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/DefaultMethodMeta.java
new file mode 100644
index 0000000..30711af
--- /dev/null
+++ 
b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/DefaultMethodMeta.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.provider.pojo;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
+import org.apache.servicecomb.foundation.common.utils.AsyncUtils;
+import org.springframework.util.ReflectionUtils;
+
+public class DefaultMethodMeta {
+  private final Map<Method, MethodHandle> defaultMethodHandles = new 
ConcurrentHashMapEx<>();
+
+  // java11
+  private final Method privateLookupIn = 
ReflectionUtils.findMethod(MethodHandles.class,
+      "privateLookupIn", Class.class, Lookup.class);
+
+  // only for java8
+  private Constructor<Lookup> lookupConstructor;
+
+  public MethodHandle getOrCreateMethodHandle(Object proxy, Method method) {
+    return defaultMethodHandles.computeIfAbsent(method, key -> 
createMethodHandle(proxy, method));
+  }
+
+  protected MethodHandle createMethodHandle(Object proxy, Method method) {
+    try {
+      if (privateLookupIn != null) {
+        return createForJava11(proxy, method);
+      }
+
+      return createForJava8(proxy, method);
+    } catch (Exception e) {
+      AsyncUtils.rethrow(e);
+      return null;
+    }
+  }
+
+  protected MethodHandle createForJava11(Object proxy, Method method) throws 
Exception {
+    Lookup lookup = MethodHandles.lookup();
+    Lookup privateLookup = (Lookup) privateLookupIn.invoke(null, 
method.getDeclaringClass(), lookup);
+    return privateLookup
+        .unreflectSpecial(method, method.getDeclaringClass())
+        .bindTo(proxy);
+  }
+
+  protected MethodHandle createForJava8(Object proxy, Method method) throws 
Exception {
+    if (lookupConstructor == null) {
+      lookupConstructor = ReflectionUtils.accessibleConstructor(Lookup.class, 
Class.class);
+    }
+    return lookupConstructor.newInstance(method.getDeclaringClass())
+        .unreflectSpecial(method, method.getDeclaringClass())
+        .bindTo(proxy);
+  }
+}
diff --git 
a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/Invoker.java
 
b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/Invoker.java
index b486cfb..cd050ac 100644
--- 
a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/Invoker.java
+++ 
b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/Invoker.java
@@ -36,6 +36,8 @@ public class Invoker implements InvocationHandler {
 
   protected final PojoInvocationCreator invocationCreator;
 
+  protected final DefaultMethodMeta defaultMethodMeta = new 
DefaultMethodMeta();
+
   @SuppressWarnings("unchecked")
   public static <T> T createProxy(String microserviceName, String schemaId, 
Class<?> consumerIntf) {
     Invoker invoker = new Invoker(microserviceName, schemaId, consumerIntf);
@@ -58,6 +60,11 @@ public class Invoker implements InvocationHandler {
 
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws 
Throwable {
+    if (method.isDefault()) {
+      return defaultMethodMeta.getOrCreateMethodHandle(proxy, method)
+          .invokeWithArguments(args);
+    }
+    
     PojoConsumerMeta pojoConsumerMeta = metaRefresher.getLatestMeta();
     PojoConsumerOperationMeta consumerOperationMeta = 
pojoConsumerMeta.ensureFindOperationMeta(method);
     Invocation invocation = invocationCreator.create(consumerOperationMeta, 
args);
diff --git 
a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/MethodUtils.java
 
b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/MethodUtils.java
index e2d34b8..3c8bcd8 100644
--- 
a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/MethodUtils.java
+++ 
b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/MethodUtils.java
@@ -67,6 +67,9 @@ public class MethodUtils {
    * false if this method should be added in to Swagger schema
    */
   public static boolean isSkipMethod(Class<?> cls, Method method) {
+    if (method.isDefault()) {
+      return true;
+    }
     if (method.getDeclaringClass() == Object.class) {
       return true;
     }

Reply via email to