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());
}
}