You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@servicecomb.apache.org by GitBox <gi...@apache.org> on 2018/01/18 03:43:25 UTC

[GitHub] liubao68 closed pull request #515: [SCB-251] Support object

liubao68 closed pull request #515: [SCB-251] Support object
URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/515
 
 
   

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/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java
index 41cd844f8..f75247ff4 100644
--- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java
+++ b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java
@@ -172,11 +172,16 @@ private static void addEnumValuesMethod(CtClass ctClass, List<String> values) th
       }
 
       for (MethodConfig methodConfig : config.getMethodList()) {
-        CtMethod ctMethod = CtMethod.make(methodConfig.getSource(), ctClass);
-        if (methodConfig.getGenericSignature() != null) {
-          ctMethod.setGenericSignature(methodConfig.getGenericSignature());
+        try {
+          CtMethod ctMethod = CtMethod.make(methodConfig.getSource(), ctClass);
+          if (methodConfig.getGenericSignature() != null) {
+            ctMethod.setGenericSignature(methodConfig.getGenericSignature());
+          }
+          ctClass.addMethod(ctMethod);
+        } catch (CannotCompileException e) {
+          LOGGER.error("Failed to create method, source:\n{}.", methodConfig.getSource());
+          throw e;
         }
-        ctClass.addMethod(ctMethod);
       }
 
       LOGGER.info("generate {} in classLoader {}.", config.getClassName(), classLoader);
diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ProtobufSchemaUtils.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ProtobufSchemaUtils.java
index 900635476..14fb7a37f 100644
--- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ProtobufSchemaUtils.java
+++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ProtobufSchemaUtils.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.codec.protobuf.utils;
 
+import java.io.IOException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Parameter;
 import java.lang.reflect.Type;
@@ -28,22 +29,60 @@
 import org.apache.servicecomb.codec.protobuf.utils.schema.WrapSchemaFactory;
 import org.apache.servicecomb.common.javassist.JavassistUtils;
 import org.apache.servicecomb.core.definition.OperationMeta;
+import org.apache.servicecomb.foundation.common.utils.JsonUtils;
 import org.springframework.util.ClassUtils;
 
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.type.TypeFactory;
 
+import io.protostuff.Input;
+import io.protostuff.Output;
+import io.protostuff.Pipe;
 import io.protostuff.Schema;
+import io.protostuff.WireFormat.FieldType;
+import io.protostuff.runtime.DefaultIdStrategy;
+import io.protostuff.runtime.Delegate;
 import io.protostuff.runtime.ProtobufCompatibleUtils;
+import io.protostuff.runtime.RuntimeEnv;
 import io.protostuff.runtime.RuntimeSchema;
 
 public final class ProtobufSchemaUtils {
   private static volatile Map<String, WrapSchema> schemaCache = new ConcurrentHashMap<>();
 
   static {
+    initProtobufObjectCodec();
     ProtobufCompatibleUtils.init();
   }
 
+  protected static void initProtobufObjectCodec() {
+    ((DefaultIdStrategy) RuntimeEnv.ID_STRATEGY).registerDelegate(new Delegate<Object>() {
+      @Override
+      public FieldType getFieldType() {
+        return FieldType.BYTES;
+      }
+
+      @Override
+      public Object readFrom(Input input) throws IOException {
+        return JsonUtils.readValue(input.readByteArray(), Object.class);
+      }
+
+      @Override
+      public void writeTo(Output output, int number, Object value, boolean repeated) throws IOException {
+        output.writeByteArray(number, JsonUtils.writeValueAsBytes(value), false);
+      }
+
+      @Override
+      public void transfer(Pipe pipe, Input input, Output output, int number, boolean repeated) throws IOException {
+        throw new IllegalStateException("not support.");
+      }
+
+      @Override
+      public Class<?> typeClass() {
+        return Object.class;
+      }
+    });
+  }
+
   private interface SchemaCreator {
     WrapSchema create() throws Exception;
   }
@@ -83,12 +122,15 @@ private static boolean isArgsNeedWrap(Method method) {
   }
 
   private static boolean isNeedWrap(Class<?> cls) {
-    // protobuf????????enum?string????collection????msg???Object?????
+    // protobuf????????enum?string????collection????msg
+    // ??pojo?????
+    // java.lang.Object?????????????????????
     return ClassUtils.isPrimitiveOrWrapper(cls) || cls.isArray() || cls.isEnum()
         || String.class.isAssignableFrom(cls)
         || Collection.class.isAssignableFrom(cls)
         || Map.class.isAssignableFrom(cls)
-        || Date.class.isAssignableFrom(cls);
+        || Date.class.isAssignableFrom(cls)
+        || Object.class.equals(cls);
   }
 
   // ????method args????????ProtobufMessageWrapper??????????????????
diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/TestProtobufSchemaUtils.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/TestProtobufSchemaUtils.java
index af9c5c712..883edb07d 100644
--- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/TestProtobufSchemaUtils.java
+++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/TestProtobufSchemaUtils.java
@@ -22,6 +22,7 @@
 import java.util.Map;
 
 import org.apache.servicecomb.common.javassist.FieldConfig;
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -117,4 +118,19 @@ private Object toObject(WrapSchema schema, byte[] bytes) throws Exception {
 
     return schema.readObject(input);
   }
+
+  @Test
+  public void object() throws Exception {
+    WrapSchema schema = ProtobufSchemaUtils.getOrCreateSchema(Object.class);
+
+    LinkedBuffer linkedBuf = LinkedBuffer.allocate();
+    ProtobufOutput output = new ProtobufOutput(linkedBuf);
+    schema.writeObject(output, 1);
+
+    Input input = new ByteArrayInput(output.toByteArray(), false);
+    Object result = schema.readObject(input);
+
+    Assert.assertEquals(1, result);
+    Assert.assertThat(result, Matchers.instanceOf(Integer.class));
+  }
 }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapper.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapper.java
index b82e1a52c..3e279164b 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapper.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapper.java
@@ -21,6 +21,7 @@
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.type.TypeFactory;
 import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
 
@@ -36,6 +37,7 @@ private RestObjectMapper() {
     setDateFormat(new ISO8601DateFormat());
     getFactory().disable(Feature.AUTO_CLOSE_SOURCE);
     disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+    disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
   }
 
   public String convertToString(Object value) throws Exception {
diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CodeFirstRestTemplateJaxrs.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CodeFirstRestTemplateJaxrs.java
index d58b91eb8..935ad52cb 100644
--- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CodeFirstRestTemplateJaxrs.java
+++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CodeFirstRestTemplateJaxrs.java
@@ -23,10 +23,10 @@
 
 public class CodeFirstRestTemplateJaxrs extends CodeFirstRestTemplate {
   @Override
-  protected void testExtend(RestTemplate template, String cseUrlPrefix) {
-    super.testExtend(template, cseUrlPrefix);
-
+  protected void testAllTransport(String microserviceName, RestTemplate template, String cseUrlPrefix) {
     testDefaultPath(template, cseUrlPrefix);
+
+    super.testAllTransport(microserviceName, template, cseUrlPrefix);
   }
 
   private void testDefaultPath(RestTemplate template, String cseUrlPrefix) {
diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstRestTemplate.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstRestTemplate.java
index ac8d82cf1..4512e59a7 100644
--- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstRestTemplate.java
+++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstRestTemplate.java
@@ -40,46 +40,58 @@
 import io.vertx.core.json.JsonObject;
 
 public class CodeFirstRestTemplate {
+  protected void changeTransport(String microserviceName, String transport) {
+    CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport);
+    TestMgr.setMsg(microserviceName, transport);
+  }
+
   public void testCodeFirst(RestTemplate template, String microserviceName, String basePath) {
+    String cseUrlPrefix = "cse://" + microserviceName + basePath;
+    changeTransport(microserviceName, "highway");
+    testOnlyHighway(template, cseUrlPrefix);
+
+    changeTransport(microserviceName, Const.RESTFUL);
+    testOnlyRest(template, cseUrlPrefix);
+
     for (String transport : DemoConst.transports) {
-      CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport);
-      TestMgr.setMsg(microserviceName, transport);
-
-      String cseUrlPrefix = "cse://" + microserviceName + basePath;
-
-      testExtend(template, cseUrlPrefix);
-
-      testCodeFirstUserMap(template, cseUrlPrefix);
-      testCodeFirstTextPlain(template, cseUrlPrefix);
-      testCodeFirstBytes(template, cseUrlPrefix);
-      testCseResponse(microserviceName, template, cseUrlPrefix);
-      testCodeFirstAddDate(template, cseUrlPrefix);
-
-      testCodeFirstAdd(template, cseUrlPrefix);
-      testCodeFirstAddString(template, cseUrlPrefix);
-      testCodeFirstIsTrue(template, cseUrlPrefix);
-      testCodeFirstSayHi2(template, cseUrlPrefix);
-      testCodeFirstSayHi(template, cseUrlPrefix);
-      testCodeFirstSaySomething(template, cseUrlPrefix);
-      //            testCodeFirstRawJsonString(template, cseUrlPrefix);
-      testCodeFirstSayHello(template, cseUrlPrefix);
-      testCodeFirstReduce(template, cseUrlPrefix);
-
-      // TODO: highway unsupported until JAV-394 completed
-      if (transport.equals("rest")) {
-        testOnlyRest(template, cseUrlPrefix);
-        // only rest transport will set trace id
-        testTraceIdOnNotSetBefore(template, cseUrlPrefix);
-      }
-
-      testTraceIdOnContextContainsTraceId(template, cseUrlPrefix);
-
-      testRawJson(template, cseUrlPrefix);
+      changeTransport(microserviceName, transport);
+      testAllTransport(microserviceName, template, cseUrlPrefix);
     }
   }
 
+  protected void testAllTransport(String microserviceName, RestTemplate template, String cseUrlPrefix) {
+    testCodeFirstUserMap(template, cseUrlPrefix);
+    testCodeFirstTextPlain(template, cseUrlPrefix);
+    testCodeFirstBytes(template, cseUrlPrefix);
+    testCseResponse(microserviceName, template, cseUrlPrefix);
+    testCodeFirstAddDate(template, cseUrlPrefix);
+
+    testCodeFirstAdd(template, cseUrlPrefix);
+    testCodeFirstAddString(template, cseUrlPrefix);
+    testCodeFirstIsTrue(template, cseUrlPrefix);
+    testCodeFirstSayHi2(template, cseUrlPrefix);
+    testCodeFirstSayHi(template, cseUrlPrefix);
+    testCodeFirstSaySomething(template, cseUrlPrefix);
+    //            testCodeFirstRawJsonString(template, cseUrlPrefix);
+    testCodeFirstSayHello(template, cseUrlPrefix);
+    testCodeFirstReduce(template, cseUrlPrefix);
+
+    testTraceIdOnContextContainsTraceId(template, cseUrlPrefix);
+
+    testRawJson(template, cseUrlPrefix);
+  }
+
+  protected void testOnlyHighway(RestTemplate template, String cseUrlPrefix) {
+
+  }
+
   protected void testOnlyRest(RestTemplate template, String cseUrlPrefix) {
+    // TODO: highway unsupported until JAV-394 completed
     testModelFieldIgnore(template, cseUrlPrefix);
+
+    // only rest transport will set trace id
+    testTraceIdOnNotSetBefore(template, cseUrlPrefix);
+
   }
 
   private void testCodeFirstUserMap(RestTemplate template, String cseUrlPrefix) {
@@ -152,10 +164,6 @@ private void testCodeFirstAddDate(RestTemplate template, String cseUrlPrefix) {
     TestMgr.check(new Date(date.getTime() + seconds * 1000), result);
   }
 
-  protected void testExtend(RestTemplate template, String cseUrlPrefix) {
-
-  }
-
   protected void testCodeFirstAddString(RestTemplate template, String cseUrlPrefix) {
     ResponseEntity<String> responseEntity =
         template.exchange(cseUrlPrefix + "addstring?s=a&s=b",
@@ -233,7 +241,7 @@ protected void testCodeFirstReduce(RestTemplate template, String cseUrlPrefix) {
   protected void testModelFieldIgnore(RestTemplate template, String cseUrlPrefix) {
     InputModelForTestIgnore input = new InputModelForTestIgnore("input_id_rest", "input_id_content",
         new Person("inputSomeone"), new JsonObject("{\"InputJsonKey\" : \"InputJsonValue\"}"), () -> {
-    });
+        });
     OutputModelForTestIgnore output = template
         .postForObject(cseUrlPrefix + "ignore", input, OutputModelForTestIgnore.class);
 
diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/TemplateResponse.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/EmptyObject.java
similarity index 78%
rename from demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/TemplateResponse.java
rename to demo/demo-schema/src/main/java/org/apache/servicecomb/demo/EmptyObject.java
index cf19bce40..2c1baa472 100644
--- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/TemplateResponse.java
+++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/EmptyObject.java
@@ -14,18 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.servicecomb.demo;
 
-package org.apache.servicecomb.demo.springmvc.server;
+public class EmptyObject {
 
-public class TemplateResponse<T> {
-  private T value;
-
-  public T getValue() {
-    return value;
-  }
-
-  public void setValue(T value) {
-    this.value = value;
-  }
-  
 }
diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/TestMgr.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/TestMgr.java
index 1449ef568..c72bb3678 100644
--- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/TestMgr.java
+++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/TestMgr.java
@@ -40,6 +40,10 @@ public static void setMsg(String microserviceName, String transport) {
   }
 
   public static void check(Object expect, Object real) {
+    if (expect == real) {
+      return;
+    }
+
     String strExpect = String.valueOf(expect);
     String strReal = String.valueOf(real);
 
diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
index b3c005357..9076f852a 100644
--- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
@@ -35,10 +35,8 @@
 import org.apache.servicecomb.demo.TestMgr;
 import org.apache.servicecomb.foundation.common.part.FilePart;
 import org.apache.servicecomb.provider.pojo.Invoker;
-import org.apache.servicecomb.provider.pojo.RpcReference;
 import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
-import org.apache.servicecomb.swagger.invocation.Response;
 import org.springframework.core.io.FileSystemResource;
 import org.springframework.core.io.PathResource;
 import org.springframework.core.io.Resource;
@@ -66,8 +64,9 @@
   private UploadStreamAndResource uploadStreamAndResource =
       Invoker.createProxy("springmvc", "codeFirst", UploadStreamAndResource.class);
 
-  @RpcReference(microserviceName = "springmvc", schemaId = "codeFirst")
-  private CodeFirstSprigmvcIntf intf;
+  private TestResponse testResponse = new TestResponse();
+
+  private TestObject testObject = new TestObject();
 
   @Override
   protected void testOnlyRest(RestTemplate template, String cseUrlPrefix) {
@@ -77,17 +76,30 @@ protected void testOnlyRest(RestTemplate template, String cseUrlPrefix) {
       throw new IllegalStateException(e);
     }
 
+    testResponse.runRest();
+    testObject.runRest();
+
     super.testOnlyRest(template, cseUrlPrefix);
   }
 
   @Override
-  protected void testExtend(RestTemplate template, String cseUrlPrefix) {
-    super.testExtend(template, cseUrlPrefix);
+  protected void testOnlyHighway(RestTemplate template, String cseUrlPrefix) {
+    testResponse.runHighway();
+    testObject.runHighway();
+
+    super.testOnlyHighway(template, cseUrlPrefix);
+  }
+
+  @Override
+  protected void testAllTransport(String microserviceName, RestTemplate template, String cseUrlPrefix) {
+    testResponse.runAllTransport();
+    testObject.runAllTransport();
 
     testResponseEntity("springmvc", template, cseUrlPrefix);
     testCodeFirstTestForm(template, cseUrlPrefix);
-    testIntf();
     testFallback(template, cseUrlPrefix);
+
+    super.testAllTransport(microserviceName, template, cseUrlPrefix);
   }
 
   private void testUpload(RestTemplate template, String cseUrlPrefix) throws IOException {
@@ -167,24 +179,6 @@ private void testFallback(RestTemplate template, String cseUrlPrefix) {
     TestMgr.check(result, "mockedreslut");
   }
 
-  private void testIntf() {
-    Date date = new Date();
-
-    String srcName = RegistryUtils.getMicroservice().getServiceName();
-
-    ResponseEntity<Date> responseEntity = intf.responseEntity(date);
-    TestMgr.check(date, responseEntity.getBody());
-    TestMgr.check("h1v " + srcName, responseEntity.getHeaders().getFirst("h1"));
-    TestMgr.check("h2v " + srcName, responseEntity.getHeaders().getFirst("h2"));
-
-    checkStatusCode("springmvc", 202, responseEntity.getStatusCode());
-
-    Response cseResponse = intf.cseResponse();
-    TestMgr.check("User [name=nameA, age=100, index=0]", cseResponse.getResult());
-    TestMgr.check("h1v " + srcName, cseResponse.getHeaders().getFirst("h1"));
-    TestMgr.check("h2v " + srcName, cseResponse.getHeaders().getFirst("h2"));
-  }
-
   private void testResponseEntity(String microserviceName, RestTemplate template, String cseUrlPrefix) {
     Map<String, Object> body = new HashMap<>();
     Date date = new Date();
diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSprigmvcIntf.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSprigmvcIntf.java
index e1738734d..12b6b544f 100644
--- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSprigmvcIntf.java
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSprigmvcIntf.java
@@ -17,7 +17,13 @@
 package org.apache.servicecomb.demo.springmvc.client;
 
 import java.util.Date;
+import java.util.List;
+import java.util.Map;
 
+import javax.xml.ws.Holder;
+
+import org.apache.servicecomb.demo.EmptyObject;
+import org.apache.servicecomb.demo.server.User;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.springframework.http.ResponseEntity;
 
@@ -25,4 +31,16 @@
   ResponseEntity<Date> responseEntity(Date date);
 
   Response cseResponse();
+
+  Object testObject(Object input);
+
+  EmptyObject testEmpty(EmptyObject input);
+
+  Map<String, Object> testMapObject(Map<String, Object> input);
+
+  List<Object> testListObject(List<Object> input);
+
+  Holder<Object> testHolderObject(Holder<Object> input);
+
+  Holder<User> testGeneric(Holder<User> input);
 }
diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestObject.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestObject.java
new file mode 100644
index 000000000..90820058b
--- /dev/null
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestObject.java
@@ -0,0 +1,196 @@
+/*
+ * 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.demo.springmvc.client;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.ws.Holder;
+
+import org.apache.servicecomb.demo.EmptyObject;
+import org.apache.servicecomb.demo.TestMgr;
+import org.apache.servicecomb.demo.server.User;
+import org.apache.servicecomb.provider.pojo.Invoker;
+import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate;
+import org.springframework.web.client.RestTemplate;
+
+public class TestObject {
+  private CodeFirstSprigmvcIntf intf;
+
+  private RestTemplate restTemplate = new CseRestTemplate();
+
+  private String prefix = "cse://springmvc/codeFirstSpringmvc";
+
+  public TestObject() {
+    intf = Invoker.createProxy("springmvc", "codeFirst", CodeFirstSprigmvcIntf.class);
+  }
+
+  public void runRest() {
+    testEmptyObject_rest();
+    testMapObject_rest();
+  }
+
+  public void runHighway() {
+    testEmptyObject_highway();
+    testMapObject_highway();
+  }
+
+  public void runAllTransport() {
+    testObject();
+    testListObject();
+    testHolderObject();
+    testGeneric();
+  }
+
+  @SuppressWarnings("unchecked")
+  private void testGeneric() {
+    Holder<User> holder = new Holder<>(new User());
+    Holder<User> result = intf.testGeneric(holder);
+    TestMgr.check("{name=nameA, age=100, index=0, names=null}", result.value);
+
+    result = restTemplate.postForObject(prefix + "/generic", holder, Holder.class);
+    TestMgr.check("{name=nameA, age=100, index=0, names=null}", result.value);
+  }
+
+  @SuppressWarnings("unchecked")
+  private void testHolderObject() {
+    Holder<Object> holder = new Holder<>("v");
+    Holder<Object> result = intf.testHolderObject(holder);
+    TestMgr.check("v", result.value);
+
+    result = restTemplate.postForObject(prefix + "/holderObject", holder, Holder.class);
+    TestMgr.check("v", result.value);
+  }
+
+  @SuppressWarnings("unchecked")
+  private void testListObject() {
+    List<Object> list = Collections.singletonList("v");
+    List<Object> result = intf.testListObject(list);
+    TestMgr.check("[v]", result);
+    TestMgr.check(ArrayList.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/listObject", list, List.class);
+    TestMgr.check("[v]", result);
+    TestMgr.check(ArrayList.class, result.getClass());
+  }
+
+  @SuppressWarnings("unchecked")
+  private void testMapObject_rest() {
+    Map<String, Object> map = Collections.singletonMap("k", "v");
+    Map<String, Object> result = intf.testMapObject(map);
+    TestMgr.check("{k=v}", result);
+    TestMgr.check(LinkedHashMap.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/mapObject", map, Map.class);
+    TestMgr.check("{k=v}", result);
+    TestMgr.check(LinkedHashMap.class, result.getClass());
+  }
+
+  @SuppressWarnings("unchecked")
+  private void testMapObject_highway() {
+    Map<String, Object> map = Collections.singletonMap("k", "v");
+    Map<String, Object> result = intf.testMapObject(map);
+    TestMgr.check("{k=v}", result);
+    TestMgr.check(HashMap.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/mapObject", map, Map.class);
+    TestMgr.check("{k=v}", result);
+    TestMgr.check(HashMap.class, result.getClass());
+  }
+
+  private void testEmptyObject_highway() {
+    // protobuf can not express empty/null
+    // everything empty will be null
+    EmptyObject result = intf.testEmpty(new EmptyObject());
+    TestMgr.check(null, result);
+
+    result = restTemplate.postForObject(prefix + "/emptyObject", new EmptyObject(), EmptyObject.class);
+    TestMgr.check(null, result);
+  }
+
+  private void testEmptyObject_rest() {
+    EmptyObject result = intf.testEmpty(new EmptyObject());
+    TestMgr.check(EmptyObject.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/emptyObject", new EmptyObject(), EmptyObject.class);
+    TestMgr.check(EmptyObject.class, result.getClass());
+  }
+
+  @SuppressWarnings("unchecked")
+  private void testObject() {
+    // int
+    Object result = intf.testObject(1);
+    TestMgr.check(1, result);
+    TestMgr.check(Integer.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/object", 1, Integer.class);
+    TestMgr.check(1, result);
+    TestMgr.check(Integer.class, result.getClass());
+
+    // string
+    result = intf.testObject("str");
+    TestMgr.check("str", result);
+    TestMgr.check(String.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/object", "str", String.class);
+    TestMgr.check("str", result);
+    TestMgr.check(String.class, result.getClass());
+
+    // emptyObject
+    result = intf.testObject(new EmptyObject());
+    TestMgr.check("{}", result);
+    TestMgr.check(LinkedHashMap.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/object", new EmptyObject(), EmptyObject.class);
+    TestMgr.check("{}", result);
+    TestMgr.check(LinkedHashMap.class, result.getClass());
+
+    // map
+    Map<String, String> map = Collections.singletonMap("k", "v");
+    result = intf.testObject(map);
+    TestMgr.check("{k=v}", result);
+    TestMgr.check(LinkedHashMap.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/object", map, Map.class);
+    TestMgr.check("{k=v}", result);
+    TestMgr.check(LinkedHashMap.class, result.getClass());
+
+    // list
+    List<String> list = Collections.singletonList("v");
+    result = intf.testObject(list);
+    TestMgr.check("[v]", result);
+    TestMgr.check(ArrayList.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/object", list, List.class);
+    TestMgr.check("[v]", result);
+    TestMgr.check(ArrayList.class, result.getClass());
+
+    // generic
+    Holder<String> holder = new Holder<>("v");
+    result = intf.testObject(holder);
+    TestMgr.check("v", ((Map<String, String>) result).get("value"));
+    TestMgr.check(LinkedHashMap.class, result.getClass());
+
+    result = restTemplate.postForObject(prefix + "/object", holder, Holder.class);
+    TestMgr.check("v", ((Map<String, String>) result).get("value"));
+    TestMgr.check(LinkedHashMap.class, result.getClass());
+  }
+}
diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
new file mode 100644
index 000000000..4036bed5f
--- /dev/null
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
@@ -0,0 +1,65 @@
+/*
+ * 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.demo.springmvc.client;
+
+import java.util.Date;
+
+import org.apache.servicecomb.demo.TestMgr;
+import org.apache.servicecomb.provider.pojo.Invoker;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.springframework.http.ResponseEntity;
+
+public class TestResponse {
+  private CodeFirstSprigmvcIntf intf;
+
+  public TestResponse() {
+    intf = Invoker.createProxy("springmvc", "codeFirst", CodeFirstSprigmvcIntf.class);
+  }
+
+  public void runRest() {
+  }
+
+  public void runHighway() {
+  }
+
+  public void runAllTransport() {
+    testResponseEntity();
+    testCseResponse();
+  }
+
+  private void testCseResponse() {
+    String srcName = RegistryUtils.getMicroservice().getServiceName();
+    Response cseResponse = intf.cseResponse();
+    TestMgr.check("User [name=nameA, age=100, index=0]", cseResponse.getResult());
+    TestMgr.check("h1v " + srcName, cseResponse.getHeaders().getFirst("h1"));
+    TestMgr.check("h2v " + srcName, cseResponse.getHeaders().getFirst("h2"));
+  }
+
+  private void testResponseEntity() {
+    Date date = new Date();
+
+    String srcName = RegistryUtils.getMicroservice().getServiceName();
+
+    ResponseEntity<Date> responseEntity = intf.responseEntity(date);
+    TestMgr.check(date, responseEntity.getBody());
+    TestMgr.check("h1v " + srcName, responseEntity.getHeaders().getFirst("h1"));
+    TestMgr.check("h2v " + srcName, responseEntity.getHeaders().getFirst("h2"));
+
+    TestMgr.check(202, responseEntity.getStatusCode());
+  }
+}
diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
index 7286bf3d0..aceba90c3 100644
--- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
+++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
@@ -28,10 +28,12 @@
 import javax.servlet.http.Part;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Response.Status;
+import javax.xml.ws.Holder;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.servicecomb.common.rest.codec.RestObjectMapper;
 import org.apache.servicecomb.core.Const;
+import org.apache.servicecomb.demo.EmptyObject;
 import org.apache.servicecomb.demo.compute.Person;
 import org.apache.servicecomb.demo.ignore.InputModelForTestIgnore;
 import org.apache.servicecomb.demo.ignore.OutputModelForTestIgnore;
@@ -161,11 +163,6 @@ public Response cseResponse(InvocationContext c1) {
     return userMap;
   }
 
-  @RequestMapping(path = "/testUserMapGeneric", method = RequestMethod.POST)
-  public TemplateResponse<String> testUserMapGeneric(@RequestBody Map<String, User> userMap) {
-    return null;
-  }
-
   @RequestMapping(path = "/textPlain", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN_VALUE)
   public String textPlain(@RequestBody String body) {
     return body;
@@ -308,7 +305,7 @@ public OutputModelForTestIgnore testModelWithIgnoreField(@RequestBody InputModel
     return new OutputModelForTestIgnore("output_id", input.getInputId(), input.getContent(), input.getInputObject(),
         input.getInputJsonObject(), input.getInputIgnoreInterface(),
         new Person("outputSomeone"), new JsonObject("{\"OutputJsonKey\" : \"OutputJsonValue\"}"), () -> {
-    });
+        });
   }
 
   @SuppressWarnings("unchecked")
@@ -364,4 +361,34 @@ public String prometheusForTest() {
   public String getTraceId() {
     return ContextUtils.getInvocationContext().getContext(Const.TRACE_ID_NAME);
   }
+
+  @PostMapping(path = "/emptyObject")
+  public EmptyObject testEmpty(@RequestBody EmptyObject input) {
+    return input;
+  }
+
+  @PostMapping(path = "/object")
+  public Object testObject(@RequestBody Object input) {
+    return input;
+  }
+
+  @PostMapping(path = "/mapObject")
+  public Map<String, Object> testMapObject(@RequestBody Map<String, Object> input) {
+    return input;
+  }
+
+  @PostMapping(path = "/listObject")
+  public List<Object> testListObject(@RequestBody List<Object> input) {
+    return input;
+  }
+
+  @PostMapping(path = "/holderObject")
+  public Holder<Object> testHolderObject(@RequestBody Holder<Object> input) {
+    return input;
+  }
+
+  @PostMapping(path = "/generic")
+  public Holder<User> testGeneric(@RequestBody Holder<User> input) {
+    return input;
+  }
 }
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java
index 087034cad..75c7b36ef 100644
--- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java
@@ -21,30 +21,24 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
-import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonGenerationException;
 import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
 
 public final class JsonUtils {
   public static final ObjectMapper OBJ_MAPPER;
 
   static {
-    //?????????????????????????????????????????
-    JsonFactory jsonFactory = new JsonFactory();
-    jsonFactory.configure(JsonFactory.Feature.INTERN_FIELD_NAMES, false);
-    OBJ_MAPPER = new ObjectMapper(jsonFactory);
+    OBJ_MAPPER = new ObjectMapper();
+    OBJ_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+    OBJ_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
   }
 
-  //    static
-  //    {
-  //        //?????????json???????Java?????????
-  //        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
-  //    }
-
   private JsonUtils() {
   }
 
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java
index c4ed1fbcc..672693ad2 100644
--- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java
@@ -33,6 +33,7 @@
 import org.apache.servicecomb.swagger.converter.parameter.BodyParameterConverter;
 import org.apache.servicecomb.swagger.converter.property.ArrayPropertyConverter;
 import org.apache.servicecomb.swagger.converter.property.MapPropertyConverter;
+import org.apache.servicecomb.swagger.converter.property.ObjectPropertyConverter;
 import org.apache.servicecomb.swagger.converter.property.RefPropertyConverter;
 import org.apache.servicecomb.swagger.converter.property.StringPropertyConverter;
 import org.apache.servicecomb.swagger.extend.property.ByteProperty;
@@ -67,6 +68,7 @@
 import io.swagger.models.properties.IntegerProperty;
 import io.swagger.models.properties.LongProperty;
 import io.swagger.models.properties.MapProperty;
+import io.swagger.models.properties.ObjectProperty;
 import io.swagger.models.properties.Property;
 import io.swagger.models.properties.RefProperty;
 import io.swagger.models.properties.StringProperty;
@@ -143,6 +145,7 @@ private static void initConverters() {
     converterMap.put(ArrayProperty.class, new ArrayPropertyConverter());
     converterMap.put(MapProperty.class, new MapPropertyConverter());
     converterMap.put(StringProperty.class, new StringPropertyConverter());
+    converterMap.put(ObjectProperty.class, new ObjectPropertyConverter());
 
     converterMap.put(ModelImpl.class, new ModelImplConverter());
     converterMap.put(RefModel.class, new RefModelConverter());
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java
index a0d09d674..60f42344a 100644
--- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java
@@ -26,6 +26,7 @@
 
 import io.swagger.models.ModelImpl;
 import io.swagger.models.Swagger;
+import io.swagger.models.properties.ObjectProperty;
 
 public class ModelImplConverter extends AbstractModelConverter {
   @Override
@@ -48,6 +49,12 @@ public JavaType doConvert(ClassLoader classLoader, String packageName, Swagger s
           modelImpl.getAdditionalProperties());
     }
 
+    if (ObjectProperty.TYPE.equals(modelImpl.getType())
+        && modelImpl.getProperties() == null
+        && modelImpl.getName() == null) {
+      return TypeFactory.defaultInstance().constructType(Object.class);
+    }
+
     // ??name?property????class
     if (packageName == null) {
       throw new Error("packageName should not be null");
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.java
new file mode 100644
index 000000000..c35e0f606
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.java
@@ -0,0 +1,32 @@
+/*
+ * 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.swagger.converter.property;
+
+import org.apache.servicecomb.swagger.converter.Converter;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
+import io.swagger.models.Swagger;
+
+public class ObjectPropertyConverter implements Converter {
+  @Override
+  public JavaType convert(ClassLoader classLoader, String packageName, Swagger swagger, Object def) {
+    return TypeFactory.defaultInstance().constructType(Object.class);
+  }
+
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java
index 7748ef0a1..7f028ae3e 100644
--- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java
@@ -32,8 +32,6 @@
 import org.apache.servicecomb.swagger.extend.property.creator.PartPropertyCreator;
 import org.apache.servicecomb.swagger.extend.property.creator.PropertyCreator;
 import org.apache.servicecomb.swagger.extend.property.creator.ShortPropertyCreator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.util.StringUtils;
 
 import com.fasterxml.jackson.databind.JavaType;
@@ -48,8 +46,6 @@
 import io.swagger.util.Json;
 
 public class ModelResolverExt extends ModelResolver {
-  private static final Logger LOGGER = LoggerFactory.getLogger(ModelResolverExt.class);
-
   private Map<Class<?>, PropertyCreator> propertyCreatorMap = new HashMap<>();
 
   public ModelResolverExt() {
@@ -87,14 +83,6 @@ private void checkType(JavaType type) {
     }
 
     String msg = "Must be a concrete type.";
-    if (type.getRawClass().equals(Object.class)) {
-      LOGGER.warn("***********************");
-      LOGGER.warn(type.getRawClass().getName() + " have some potential problems when working with "
-          + "different platforms and transports. It's recommended to change your service definition. "
-          + "This feature will be removed without notice in the future.");
-      LOGGER.warn("***********************");
-    }
-
     if (type.isMapLikeType()) {
       Class<?> keyTypeClass = type.getKeyType().getRawClass();
       if (!String.class.equals(keyTypeClass)) {


 

----------------------------------------------------------------
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:
users@infra.apache.org


With regards,
Apache Git Services