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 6be3c5e  [SCB-2289]support disable swagger data type check and use 
generics (#2450)
6be3c5e is described below

commit 6be3c5ef2afc1798c70baf82f6bde8eca2419614
Author: liubao68 <[email protected]>
AuthorDate: Tue Jul 6 17:37:30 2021 +0800

    [SCB-2289]support disable swagger data type check and use generics (#2450)
---
 .../pojo/client/TestNotRecommendedService.java     | 116 +++++++++++++++++++++
 .../src/main/resources/microservice.yaml           |   2 +
 .../demo/pojo/server/NotRecommendedService.java    |  55 ++++++++++
 .../src/main/resources/microservice.yaml           |   2 +
 .../servicecomb/demo/server/AbstractModel.java     |  49 +++++++++
 .../demo/server/DefaultAbstractModel.java          |  35 +++++++
 .../demo/server/NotRecommendedServiceInf.java      |  33 ++++++
 .../demo/server/SecondAbstractModel.java           |  35 +++++++
 .../demo/server/WrappedAbstractModel.java          |  63 +++++++++++
 .../swagger/extend/ModelResolverExt.java           |  14 ++-
 10 files changed, 403 insertions(+), 1 deletion(-)

diff --git 
a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestNotRecommendedService.java
 
b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestNotRecommendedService.java
new file mode 100644
index 0000000..b1771fa
--- /dev/null
+++ 
b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestNotRecommendedService.java
@@ -0,0 +1,116 @@
+/*
+ * 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.pojo.client;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicecomb.demo.CategorizedTestCase;
+import org.apache.servicecomb.demo.TestMgr;
+import org.apache.servicecomb.demo.server.AbstractModel;
+import org.apache.servicecomb.demo.server.DefaultAbstractModel;
+import org.apache.servicecomb.demo.server.NotRecommendedServiceInf;
+import org.apache.servicecomb.demo.server.SecondAbstractModel;
+import org.apache.servicecomb.demo.server.WrappedAbstractModel;
+import org.apache.servicecomb.provider.pojo.RpcReference;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TestNotRecommendedService implements CategorizedTestCase {
+  @RpcReference(microserviceName = "pojo", schemaId = "NotRecommendedService")
+  private NotRecommendedServiceInf pojo;
+
+  @Override
+  public void testRestTransport() throws Exception {
+    testLongMap();
+    testAbstractModel();
+    testListAbstractModel();
+    testMapAbstractModel();
+    testWrappedModel();
+  }
+
+  private void testWrappedModel() {
+    Map<Long, AbstractModel> data = new HashMap<>();
+    AbstractModel model = new DefaultAbstractModel();
+    model.setName("hello");
+    data.put(100L, model);
+
+    List<AbstractModel> data2 = new ArrayList<>();
+    AbstractModel model2 = new DefaultAbstractModel();
+    model2.setName("hello");
+    data2.add(model);
+
+    WrappedAbstractModel input = new WrappedAbstractModel();
+    input.setMapModel(data);
+    input.setListModel(data2);
+    AbstractModel secondModel = new SecondAbstractModel();
+    secondModel.setName("second");
+    input.setModel(secondModel);
+    input.setName("wrapped");
+
+    WrappedAbstractModel result = pojo.wrappedAbstractModel(input);
+
+    TestMgr.check(1, result.getMapModel().size());
+    TestMgr.check("hello", 
result.getMapModel().get(result.getMapModel().keySet().iterator().next()).getName());
+
+    TestMgr.check(1, result.getListModel().size());
+    TestMgr.check("hello", result.getListModel().get(0).getName());
+
+    TestMgr.check("second", result.getModel().getName());
+    TestMgr.check(true, result.getModel() instanceof SecondAbstractModel);
+    TestMgr.check("wrapped", result.getName());
+  }
+
+  private void testMapAbstractModel() {
+    Map<Long, AbstractModel> data = new HashMap<>();
+    AbstractModel model = new DefaultAbstractModel();
+    model.setName("hello");
+    data.put(100L, model);
+    Map<Long, AbstractModel> result = pojo.mapAbstractModel(data);
+    TestMgr.check(1, result.size());
+    TestMgr.check("hello", 
result.get(result.keySet().iterator().next()).getName());
+  }
+
+  private void testListAbstractModel() {
+    List<AbstractModel> data = new ArrayList<>();
+    AbstractModel model = new DefaultAbstractModel();
+    model.setName("hello");
+    data.add(model);
+    List<AbstractModel> result = pojo.listAbstractModel(data);
+    TestMgr.check(1, result.size());
+    TestMgr.check("hello", result.get(0).getName());
+  }
+
+  private void testAbstractModel() {
+    AbstractModel model = new DefaultAbstractModel();
+    model.setName("hello");
+
+    AbstractModel result = pojo.abstractModel(model);
+    TestMgr.check("hello", result.getName());
+  }
+
+  private void testLongMap() {
+    Map<Long, Long> data = new HashMap<>();
+    data.put(100L, 200L);
+    Map<Long, Long> result = pojo.longMap(data);
+    TestMgr.check(1, result.size());
+    TestMgr.check(200L, result.get(100L));
+  }
+}
diff --git a/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml 
b/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml
index 9fd500d..3f68ea6 100644
--- a/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml
+++ b/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml
@@ -30,6 +30,8 @@ servicecomb:
         empty:
           protection: true
   rest.client.enabled: false # using only http2
+  swagger:
+    disableDataTypeCheck: true
   handler:
     chain:
       Consumer:
diff --git 
a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/NotRecommendedService.java
 
b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/NotRecommendedService.java
new file mode 100644
index 0000000..cd2e3de
--- /dev/null
+++ 
b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/NotRecommendedService.java
@@ -0,0 +1,55 @@
+/*
+ * 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.pojo.server;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicecomb.demo.server.AbstractModel;
+import org.apache.servicecomb.demo.server.NotRecommendedServiceInf;
+import org.apache.servicecomb.demo.server.WrappedAbstractModel;
+import org.apache.servicecomb.provider.pojo.RpcSchema;
+
+@RpcSchema(schemaId = "NotRecommendedService", schemaInterface = 
NotRecommendedServiceInf.class)
+public class NotRecommendedService implements NotRecommendedServiceInf {
+
+  @Override
+  public Map<Long, Long> longMap(Map<Long, Long> map) {
+    return map;
+  }
+
+  @Override
+  public List<AbstractModel> listAbstractModel(List<AbstractModel> listModel) {
+    return listModel;
+  }
+
+  @Override
+  public AbstractModel abstractModel(AbstractModel model) {
+    return model;
+  }
+
+  @Override
+  public Map<Long, AbstractModel> mapAbstractModel(Map<Long, AbstractModel> 
mapModel) {
+    return mapModel;
+  }
+
+  @Override
+  public WrappedAbstractModel wrappedAbstractModel(WrappedAbstractModel 
wrappedModel) {
+    return wrappedModel;
+  }
+}
diff --git a/demo/demo-pojo/pojo-server/src/main/resources/microservice.yaml 
b/demo/demo-pojo/pojo-server/src/main/resources/microservice.yaml
index a3d73dc..4645aa0 100644
--- a/demo/demo-pojo/pojo-server/src/main/resources/microservice.yaml
+++ b/demo/demo-pojo/pojo-server/src/main/resources/microservice.yaml
@@ -30,6 +30,8 @@ servicecomb:
         useAlpnEnabled: false
   highway:
     address: 0.0.0.0:7070
+  swagger:
+    disableDataTypeCheck: true
   handler:
     chain:
       Provider:
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/AbstractModel.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/AbstractModel.java
new file mode 100644
index 0000000..9cf1328
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/AbstractModel.java
@@ -0,0 +1,49 @@
+/*
+ * 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.server;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+
+// 当使用 List<AbstractModel> 等 Collection 类型的时候, jackson 序列化不会携带类以外的其他属性
+// 即会忽略掉类型信息。 当抽象类型用于 Collection 类型参数的时候,必须使用已有的属性(例子中的 property = 
"type")来确定类型,
+// 并在子类中显示指定属性的值,而不能使用和依赖jackson根据类型信息自己生成的类型。
+
+// 还有一种方法,是序列化的时候指定类型, see: 
https://www.studytrails.com/2016/09/12/java-jackson-serialization-list/
+// 但是多数序列化接口,包括 RestTemplate 等,都无法得知参数的类型。 这种方式难于应用于开发框架实现,因此对于Collection 
类型参数场景,使用已有属性
+// 是最简洁的方法。
+
+@JsonTypeInfo(
+    use = Id.NAME, property = "type"
+)
+@JsonSubTypes({
+    @JsonSubTypes.Type(value = DefaultAbstractModel.class, name = "default"),
+    @JsonSubTypes.Type(value = SecondAbstractModel.class, name = "second"),
+})
+public abstract class AbstractModel {
+  protected String type;
+
+  protected String name;
+
+  public abstract String getType();
+
+  public abstract String getName();
+
+  public abstract void setName(String name);
+}
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/DefaultAbstractModel.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/DefaultAbstractModel.java
new file mode 100644
index 0000000..c9f06ee
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/DefaultAbstractModel.java
@@ -0,0 +1,35 @@
+/*
+ * 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.server;
+
+public class DefaultAbstractModel extends AbstractModel {
+  @Override
+  public String getType() {
+    return "default";
+  }
+
+  @Override
+  public String getName() {
+    return this.name;
+  }
+
+  @Override
+  public void setName(String name) {
+    this.name = name;
+  }
+}
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/NotRecommendedServiceInf.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/NotRecommendedServiceInf.java
new file mode 100644
index 0000000..f6be5ae
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/NotRecommendedServiceInf.java
@@ -0,0 +1,33 @@
+/*
+ * 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.server;
+
+import java.util.List;
+import java.util.Map;
+
+public interface NotRecommendedServiceInf {
+  Map<Long, Long> longMap(Map<Long, Long> map);
+
+  List<AbstractModel> listAbstractModel(List<AbstractModel> listModel);
+
+  AbstractModel abstractModel(AbstractModel model);
+
+  Map<Long, AbstractModel> mapAbstractModel(Map<Long, AbstractModel> mapModel);
+
+  WrappedAbstractModel wrappedAbstractModel(WrappedAbstractModel wrappedModel);
+}
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/SecondAbstractModel.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/SecondAbstractModel.java
new file mode 100644
index 0000000..46a0b85
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/SecondAbstractModel.java
@@ -0,0 +1,35 @@
+/*
+ * 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.server;
+
+public class SecondAbstractModel extends AbstractModel {
+  @Override
+  public String getType() {
+    return "second";
+  }
+
+  @Override
+  public String getName() {
+    return this.name;
+  }
+
+  @Override
+  public void setName(String name) {
+    this.name = name;
+  }
+}
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/WrappedAbstractModel.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/WrappedAbstractModel.java
new file mode 100644
index 0000000..8015ccf
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/WrappedAbstractModel.java
@@ -0,0 +1,63 @@
+/*
+ * 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.server;
+
+import java.util.List;
+import java.util.Map;
+
+public class WrappedAbstractModel {
+  private String name;
+
+  private Map<Long, AbstractModel> mapModel;
+
+  private List<AbstractModel> listModel;
+
+  private AbstractModel model;
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public Map<Long, AbstractModel> getMapModel() {
+    return mapModel;
+  }
+
+  public void setMapModel(Map<Long, AbstractModel> mapModel) {
+    this.mapModel = mapModel;
+  }
+
+  public List<AbstractModel> getListModel() {
+    return listModel;
+  }
+
+  public void setListModel(List<AbstractModel> listModel) {
+    this.listModel = listModel;
+  }
+
+  public AbstractModel getModel() {
+    return model;
+  }
+
+  public void setModel(AbstractModel model) {
+    this.model = model;
+  }
+}
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 cbb67d4..3969bb7 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
@@ -45,6 +45,7 @@ import 
org.apache.servicecomb.swagger.generator.SwaggerGeneratorFeature;
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.annotations.VisibleForTesting;
+import com.netflix.config.DynamicPropertyFactory;
 
 import io.swagger.converter.ModelConverter;
 import io.swagger.converter.ModelConverterContext;
@@ -63,6 +64,13 @@ public class ModelResolverExt extends ModelResolver {
 
   private Set<Type> concreteInterfaces = new HashSet<>();
 
+  private static final String DISABLE_DATA_TYPE_CHECK = 
"servicecomb.swagger.disableDataTypeCheck";
+
+  // This property is used only for compatible usage and is not recommended 
and may not compatible to
+  // OPEN API standard
+  private final boolean disableDataTypeCheck = 
DynamicPropertyFactory.getInstance()
+      .getBooleanProperty(DISABLE_DATA_TYPE_CHECK, false).get();
+
   public ModelResolverExt() {
     super(findMapper());
 
@@ -107,6 +115,10 @@ public class ModelResolverExt extends ModelResolver {
   }
 
   private void checkType(JavaType type) {
+    if (disableDataTypeCheck) {
+      return;
+    }
+
     // 原子类型/string在java中是abstract的
     if (type.getRawClass().isPrimitive()
         || propertyCreatorMap.containsKey(type.getRawClass())
@@ -120,7 +132,7 @@ public class ModelResolverExt extends ModelResolver {
       Class<?> keyTypeClass = type.getKeyType().getRawClass();
       if (!String.class.equals(keyTypeClass)) {
         // swagger中map的key只允许为string
-        throw new Error("Type of key in map must be string, but got " + 
keyTypeClass.getName());
+        throw new ServiceCombException("Type of key in map must be string, but 
got " + keyTypeClass.getName());
       }
     }
 

Reply via email to