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
commit 3dd9fc0115150c39595a4e654fc0d477a080bbae Author: liubao <bi...@qq.com> AuthorDate: Thu Jan 16 10:18:09 2020 +0800 [SCB-1727]support encode/decode Object(Any) types --- .../protobuf/definition/OperationProtobuf.java | 10 +-- .../definition/RequestRootDeserializer.java | 7 +- .../definition/ResponseRootDeserializer.java | 24 ++++--- .../internal/converter/TestSchemaMetaCodec.java | 81 ++++++++++++++++++++-- .../converter/TestSchemaMetaCodecRestTemplate.java | 8 ++- .../servicecomb/demo/pojo/client/TestWeakPojo.java | 36 ++++++++-- .../servicecomb/demo/pojo/server/WeakPojo.java | 4 ++ .../demo/springmvc/client/TestObject.java | 19 ++--- .../foundation/protobuf/internal/ProtoUtils.java | 4 ++ .../internal/schema/any/AnyEntrySchema.java | 47 +++++++++++-- .../protobuf/internal/schema/any/AnySchema.java | 4 +- .../deserializer/DeserializerSchemaManager.java | 7 +- .../repeated/impl/AnyRepeatedReadSchemas.java | 2 +- .../schema/serializer/SerializerSchemaManager.java | 5 ++ .../protobuf/internal/schema/TestAnySchema.java | 3 +- .../foundation/test/scaffolding/model/People.java | 24 ++----- .../transport/highway/HighwayCodec.java | 2 +- 17 files changed, 218 insertions(+), 69 deletions(-) diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/OperationProtobuf.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/OperationProtobuf.java index eb6e22c..e475712 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/OperationProtobuf.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/OperationProtobuf.java @@ -29,6 +29,8 @@ import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.foundation.protobuf.ProtoMapper; import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import com.fasterxml.jackson.databind.JavaType; + import io.protostuff.compiler.model.Message; @SuppressWarnings("rawtypes") @@ -123,7 +125,7 @@ public class OperationProtobuf { ProtoMapper mapper = scopedProtobufSchemaManager.getOrCreateProtoMapper(operationMeta.getSchemaMeta()); Message responseMessage = mapper.getResponseMessage(operationMeta.getOperationId()); - Type responseType = operationMeta.getResponsesMeta().findResponseType(Status.OK.getStatusCode()); + JavaType responseType = operationMeta.getResponsesMeta().findResponseType(Status.OK.getStatusCode()); if (operationMeta.getSwaggerProducerOperation() != null) { if (ProtoUtils.isWrapProperty(responseMessage)) { responseRootSerializer = new ResponseRootSerializer( @@ -142,18 +144,18 @@ public class OperationProtobuf { responseRootSerializer = new ResponseRootSerializer( mapper.createRootSerializer(responseMessage, responseType), true, false); responseRootDeserializer = new ResponseRootDeserializer<>( - mapper.createRootDeserializer(responseMessage, responseType), true, false); + mapper.createRootDeserializer(responseMessage, responseType), false); } else { if (ProtoUtils.isEmptyMessage(responseMessage)) { responseRootSerializer = new ResponseRootSerializer(mapper.createRootSerializer(responseMessage, Object.class), false, false); responseRootDeserializer = new ResponseRootDeserializer<>( - mapper.createRootDeserializer(responseMessage, Object.class), false, true); + mapper.createRootDeserializer(responseMessage, Object.class), true); } else { responseRootSerializer = new ResponseRootSerializer(mapper.createRootSerializer(responseMessage, responseType), false, false); responseRootDeserializer = new ResponseRootDeserializer<>( - mapper.createRootDeserializer(responseMessage, responseType), false, false); + mapper.createRootDeserializer(responseMessage, responseType), false); } } } diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootDeserializer.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootDeserializer.java index 049c7c0..c8b70f4 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootDeserializer.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootDeserializer.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.Map; import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; public class RequestRootDeserializer<T> { private boolean wrapArgument; @@ -42,7 +43,11 @@ public class RequestRootDeserializer<T> { return null; } Map<String, Object> result = new HashMap<>(1); - result.put(parameterName, rootDeserializer.deserialize(bytes)); + Object obj = rootDeserializer.deserialize(bytes); + if (obj instanceof PropertyWrapper) { + obj = ((PropertyWrapper) obj).getValue(); + } + result.put(parameterName, obj); return result; } else { return (Map<String, Object>) rootDeserializer.deserialize(bytes); diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootDeserializer.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootDeserializer.java index 467b07c..f32a010 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootDeserializer.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootDeserializer.java @@ -18,33 +18,37 @@ package org.apache.servicecomb.codec.protobuf.definition; import java.io.IOException; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; import org.apache.servicecomb.foundation.protobuf.RootDeserializer; import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; -public class ResponseRootDeserializer<T> { - private boolean wrapProperty; +import com.fasterxml.jackson.databind.JavaType; +public class ResponseRootDeserializer<T> { private RootDeserializer<T> rootDeserializer; private boolean empty; - public ResponseRootDeserializer(RootDeserializer<T> rootDeserializer, boolean wrapProperty, boolean empty) { + public ResponseRootDeserializer(RootDeserializer<T> rootDeserializer, boolean empty) { this.rootDeserializer = rootDeserializer; - this.wrapProperty = wrapProperty; this.empty = empty; } @SuppressWarnings("unchecked") - public T deserialize(byte[] bytes) throws IOException { + public T deserialize(byte[] bytes, JavaType invocationTimeType) throws IOException { if (empty) { - T a = rootDeserializer.deserialize(bytes); // read buffers if possible. + rootDeserializer.deserialize(bytes); // read buffers if possible. return null; } - if (wrapProperty) { - return ((PropertyWrapper<T>) rootDeserializer.deserialize(bytes)).getValue(); - } else { - return rootDeserializer.deserialize(bytes); + Object obj = rootDeserializer.deserialize(bytes); + if (obj instanceof PropertyWrapper) { + obj = ((PropertyWrapper) obj).getValue(); + } + if (obj != null && !invocationTimeType.isPrimitive() && !invocationTimeType.getRawClass() + .isAssignableFrom(obj.getClass())) { + obj = JsonUtils.convertValue(obj, invocationTimeType.getRawClass()); } + return (T) obj; } } diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodec.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodec.java index 4d74073..01823e9 100644 --- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodec.java +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodec.java @@ -38,8 +38,10 @@ import org.apache.servicecomb.codec.protobuf.internal.converter.model.ProtoSchem import org.apache.servicecomb.core.definition.MicroserviceMeta; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; import org.apache.servicecomb.foundation.test.scaffolding.model.Color; import org.apache.servicecomb.foundation.test.scaffolding.model.Empty; +import org.apache.servicecomb.foundation.test.scaffolding.model.People; import org.apache.servicecomb.foundation.test.scaffolding.model.User; import org.apache.servicecomb.swagger.engine.SwaggerConsumer; import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; @@ -53,6 +55,8 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.fasterxml.jackson.databind.type.TypeFactory; + import io.swagger.models.Swagger; import mockit.Expectations; import mockit.Injectable; @@ -166,13 +170,15 @@ public class TestSchemaMetaCodec { ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); values = responseSerializer.serialize(user); ResponseRootDeserializer<Object> responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); - User decodedUser = (User) responseDeserializer.deserialize(values); + User decodedUser = (User) responseDeserializer + .deserialize(values, TypeFactory.defaultInstance().constructType(User.class)); Assert.assertEquals(user.name, decodedUser.name); Assert.assertEquals(user.friends.get(0).name, decodedUser.friends.get(0).name); user.friends = new ArrayList<>(); values = responseSerializer.serialize(user); - decodedUser = (User) responseDeserializer.deserialize(values); + decodedUser = (User) responseDeserializer + .deserialize(values, TypeFactory.defaultInstance().constructType(User.class)); Assert.assertEquals(user.name, decodedUser.name); // proto buffer encode and decode empty list to be null Assert.assertEquals(null, decodedUser.friends); @@ -236,13 +242,13 @@ public class TestSchemaMetaCodec { ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); values = responseSerializer.serialize(userMap); ResponseRootDeserializer<Object> responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); - Map<String, User> decodedUser = (Map<String, User>) responseDeserializer.deserialize(values); + Map<String, User> decodedUser = (Map<String, User>) responseDeserializer.deserialize(values, ProtoConst.MAP_TYPE); Assert.assertEquals(user.name, decodedUser.get("test").name); Assert.assertEquals(user.friends.get(0).name, decodedUser.get("test").friends.get(0).name); user.friends = new ArrayList<>(); values = responseSerializer.serialize(userMap); - decodedUser = (Map<String, User>) responseDeserializer.deserialize(values); + decodedUser = (Map<String, User>) responseDeserializer.deserialize(values, ProtoConst.MAP_TYPE); Assert.assertEquals(user.name, decodedUser.get("test").name); // proto buffer encode and decode empty list to be null Assert.assertEquals(null, decodedUser.get("test").friends); @@ -359,7 +365,8 @@ public class TestSchemaMetaCodec { ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); values = responseSerializer.serialize(30); ResponseRootDeserializer<Object> responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); - Object decodedValue = responseDeserializer.deserialize(values); + Object decodedValue = responseDeserializer + .deserialize(values, TypeFactory.defaultInstance().constructType(int.class)); Assert.assertEquals(30, (int) decodedValue); } @@ -432,4 +439,68 @@ public class TestSchemaMetaCodec { Assert.assertEquals("friend", user.friends.get(0).name); } } + + @Test + public void testProtoSchemaOperationObjSpringMVC() throws Exception { + mockSchemaMeta(new SpringmvcSwaggerGenerator(ProtoSchema.class), new ProtoSchema()); + testProtoSchemaOperationObjImpl(false); + } + + @Test + public void testProtoSchemaOperationObjPOJO() throws Exception { + mockSchemaMeta(new PojoSwaggerGenerator(ProtoSchemaPojo.class), new ProtoSchemaPojo()); + testProtoSchemaOperationObjImpl(true); + } + + private void testProtoSchemaOperationObjImpl(boolean isPojo) throws IOException { + OperationProtobuf providerOperationProtobuf = ProtobufManager + .getOrCreateOperation(providerSchemaMeta.getOperations().get("obj")); + OperationProtobuf consumerOperationProtobuf = ProtobufManager + .getOrCreateOperation(consumerSchemaMeta.getOperations().get("obj")); + byte[] values; + + // request message + RequestRootSerializer requestSerializer = consumerOperationProtobuf.getRequestRootSerializer(); + Map<String, Object> args = new HashMap<>(); + args.put("value", 2); + + values = requestSerializer.serialize(args); + RequestRootDeserializer<Object> requestDeserializer = providerOperationProtobuf.getRequestRootDeserializer(); + Map<String, Object> decodedArgs = requestDeserializer.deserialize(values); + int result = (int) decodedArgs.get("value"); + Assert.assertEquals(2, result); + + User user = new User(); + user.name = "user"; + User friend = new User(); + friend.name = "friend"; + List<User> friends = new ArrayList<>(); + friends.add(friend); + user.friends = friends; + args.put("value", user); + values = requestSerializer.serialize(args); + decodedArgs = requestDeserializer.deserialize(values); + Map<String, Object> userMap = (Map<String, Object>) decodedArgs.get("value"); + Assert.assertEquals("user", userMap.get("name")); + // proto buffer encode and decode empty list to be null + friends = (List<User>) userMap.get("friends"); + Map<String, Object> friendMap = (Map<String, Object>) friends.get(0); + Assert.assertEquals("friend", friendMap.get("name")); + + args.clear(); + People people = new People(); + people.name = "user"; + People pFriend = new People(); + pFriend.name = "friend"; + List<People> pFriends = new ArrayList<>(); + pFriends.add(pFriend); + people.friends = pFriends; + args.put("value", people); + values = requestSerializer.serialize(args); + decodedArgs = requestDeserializer.deserialize(values); + people = (People) decodedArgs.get("value"); + Assert.assertEquals("user", people.name); + // proto buffer encode and decode empty list to be null + Assert.assertEquals("friend", people.friends.get(0).name); + } } diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodecRestTemplate.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodecRestTemplate.java index 25d4eb4..0472b37 100644 --- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodecRestTemplate.java +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodecRestTemplate.java @@ -46,6 +46,8 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.fasterxml.jackson.databind.type.TypeFactory; + import io.swagger.models.Swagger; import mockit.Expectations; import mockit.Injectable; @@ -123,13 +125,13 @@ public class TestSchemaMetaCodecRestTemplate { ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); values = responseSerializer.serialize(user); ResponseRootDeserializer<Object> responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); - User decodedUser = (User) responseDeserializer.deserialize(values); + User decodedUser = (User) responseDeserializer.deserialize(values, TypeFactory.defaultInstance().constructType(User.class)); Assert.assertEquals(user.name, decodedUser.name); Assert.assertEquals(user.friends.get(0).name, decodedUser.friends.get(0).name); user.friends = new ArrayList<>(); values = responseSerializer.serialize(user); - decodedUser = (User) responseDeserializer.deserialize(values); + decodedUser = (User) responseDeserializer.deserialize(values, TypeFactory.defaultInstance().constructType(User.class)); Assert.assertEquals(user.name, decodedUser.name); // proto buffer encode and decode empty list to be null Assert.assertEquals(null, decodedUser.friends); @@ -213,7 +215,7 @@ public class TestSchemaMetaCodecRestTemplate { ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); values = responseSerializer.serialize(30); ResponseRootDeserializer<Object> responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); - Object decodedValue = responseDeserializer.deserialize(values); + Object decodedValue = responseDeserializer.deserialize(values, TypeFactory.defaultInstance().constructType(int.class)); Assert.assertEquals(30, (int) decodedValue); } } diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestWeakPojo.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestWeakPojo.java index 62bc6a3..a28c71f 100644 --- a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestWeakPojo.java +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestWeakPojo.java @@ -87,6 +87,10 @@ interface GenericsModelInf { GenericsModel genericParamsModel(int code, GenericsModel model); } +interface ObjectInf { + GenericsModel obj(GenericsModel obj); +} + @Component public class TestWeakPojo implements CategorizedTestCase { @RpcReference(microserviceName = "pojo", schemaId = "WeakPojo") @@ -101,16 +105,40 @@ public class TestWeakPojo implements CategorizedTestCase { @RpcReference(microserviceName = "pojo", schemaId = "WeakPojo") private GenericsModelInf genericsModelInf; + @RpcReference(microserviceName = "pojo", schemaId = "WeakPojo") + private ObjectInf objectInf; + @Override public void testAllTransport() throws Exception { - getDiffName(); + testDiffName(); testGenerics(); - getGenericsModel(); + testGenericsModel(); + + testObject(); + } + + private void testObject() throws JsonProcessingException { + GenericsModel model = new GenericsModel(); + model.setName("model"); + List<List<String>> namesList = new ArrayList<>(); + List<String> names = new ArrayList<>(); + names.add("hello"); + namesList.add(names); + model.setNameList(namesList); + List<List<List<Object>>> objectLists = new ArrayList<>(); + List<List<Object>> objectList = new ArrayList<>(); + List<Object> objects = new ArrayList<>(); + objects.add("object"); + objectList.add(objects); + objectLists.add(objectList); + model.setObjectLists(objectLists); + GenericsModel result = objectInf.obj(model); + TestMgr.check(JsonUtils.writeValueAsString(model), JsonUtils.writeValueAsString(result)); } - private void getGenericsModel() throws JsonProcessingException { + private void testGenericsModel() throws JsonProcessingException { GenericsModel model = new GenericsModel(); model.setName("model"); List<List<String>> namesList = new ArrayList<>(); @@ -140,7 +168,7 @@ public class TestWeakPojo implements CategorizedTestCase { TestMgr.check("hello", nameListResult.get(0).get(0)); } - private void getDiffName() { + private void testDiffName() { TestMgr.check(7, diffNames.differentName(2, 3)); TestMgr.check(8, diffNames2.differentName(2, 3)); Map<String, Object> args = new HashMap<>(); diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java index e884229..fc82bf1 100644 --- a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java @@ -39,4 +39,8 @@ public class WeakPojo { public GenericsModel genericParamsModel(int code, GenericsModel model) { return model; } + + public Object obj(Object obj) { + return obj; + } } 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 index 5e42db7..fe36b6b 100644 --- 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 @@ -18,7 +18,6 @@ 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; @@ -27,7 +26,6 @@ import javax.xml.ws.Holder; import org.apache.servicecomb.demo.EmptyObject; import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.foundation.test.scaffolding.model.Empty; import org.apache.servicecomb.provider.pojo.Invoker; import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate; import org.springframework.web.client.RestTemplate; @@ -58,7 +56,7 @@ public class TestObject { public void runAllTransport() { // TODO : WEAK not supported now in HIGHWAY -// testObject(); + testObject(); // testListObject(); // testHolderObject(); } @@ -149,31 +147,34 @@ public class TestObject { // emptyObject result = intf.testObject(new EmptyObject()); - TestMgr.check("{}", result); - TestMgr.check(LinkedHashMap.class, result.getClass()); + // result may not be an empty map in highway + // TestMgr.check("{}", result); + TestMgr.check(true, Map.class.isAssignableFrom(result.getClass())); result = restTemplate.postForObject(prefix + "/object", new EmptyObject(), EmptyObject.class); TestMgr.check(EmptyObject.class, result.getClass()); + result = restTemplate.postForObject(prefix + "/object", new EmptyObject(), EmptyObject.class); + TestMgr.check(EmptyObject.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()); + TestMgr.check(true, Map.class.isAssignableFrom(result.getClass())); result = restTemplate.postForObject(prefix + "/object", map, Map.class); TestMgr.check("{k=v}", result); - TestMgr.check(LinkedHashMap.class, result.getClass()); + TestMgr.check(true, Map.class.isAssignableFrom(result.getClass())); // list List<String> list = Collections.singletonList("v"); result = intf.testObject(list); TestMgr.check("[v]", result); - TestMgr.check(ArrayList.class, result.getClass()); + TestMgr.check(true, List.class.isAssignableFrom(result.getClass())); result = restTemplate.postForObject(prefix + "/object", list, List.class); TestMgr.check("[v]", result); - TestMgr.check(ArrayList.class, result.getClass()); + TestMgr.check(true, List.class.isAssignableFrom(result.getClass())); // generic Holder<String> holder = new Holder<>("v"); diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoUtils.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoUtils.java index 55fcd30..2d5c7e0 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoUtils.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoUtils.java @@ -33,6 +33,10 @@ public final class ProtoUtils { return protoField.getCanonicalName().equals(ProtoConst.EMPTY.getCanonicalName()); } + public static boolean isAnyMessage(Message protoField) { + return protoField.getCanonicalName().equals(ProtoConst.ANY.getCanonicalName()); + } + public static boolean isAnyField(Field protoField) { return protoField.getType().getCanonicalName().equals(ProtoConst.ANY.getCanonicalName()); } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntrySchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntrySchema.java index e371c7c..cd89bf9 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntrySchema.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntrySchema.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.any; import java.io.IOException; +import java.lang.reflect.Type; import java.util.Map; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; @@ -24,8 +25,10 @@ import org.apache.servicecomb.foundation.protobuf.ProtoMapper; import org.apache.servicecomb.foundation.protobuf.RootDeserializer; import org.apache.servicecomb.foundation.protobuf.RootSerializer; import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; import io.protostuff.InputEx; import io.protostuff.OutputEx; @@ -47,8 +50,11 @@ public class AnyEntrySchema implements SchemaEx<Object> { private final int valueTag = WireFormat.makeTag(2, WireFormat.WIRETYPE_LENGTH_DELIMITED); - public AnyEntrySchema(ProtoMapper protoMapper) { + private Type anyTargetType; + + public AnyEntrySchema(ProtoMapper protoMapper, Type type) { this.protoMapper = protoMapper; + this.anyTargetType = type; } @Override @@ -57,6 +63,11 @@ public class AnyEntrySchema implements SchemaEx<Object> { } @Override + public Object newMessage() { + return new PropertyWrapper<>(); + } + + @Override public void mergeFrom(InputEx input, Object message) throws IOException { input.readFieldNumber(); String typeUrl = input.readString(); @@ -66,12 +77,19 @@ public class AnyEntrySchema implements SchemaEx<Object> { input.readFieldNumber(); - AnyEntry anyEntry = (AnyEntry) message; - anyEntry.setTypeUrl(typeUrl); - anyEntry.setValue(bytes); + if (message instanceof PropertyWrapper) { + if (typeUrl.startsWith(ProtoConst.PACK_SCHEMA)) { + ((PropertyWrapper) message).setValue(standardUnpack(typeUrl, bytes)); + } else { + ((PropertyWrapper) message).setValue(jsonExtendMergeFrom(typeUrl, bytes)); + } + } else if (message instanceof AnyEntry) { + ((AnyEntry) message).setTypeUrl(typeUrl); + ((AnyEntry) message).setValue(bytes); + } } - public Object deseriaze(InputEx input) throws IOException { + public Object deserialize(InputEx input) throws IOException { AnyEntry anyEntry = new AnyEntry(); input.mergeObject(anyEntry, this); @@ -101,12 +119,27 @@ public class AnyEntrySchema implements SchemaEx<Object> { "can not find proto message to create deserializer, name=" + msgCanonicalName); } - JavaType javaType = protoMapper.getAnyTypes().getOrDefault(msgCanonicalName, ProtoConst.MAP_TYPE); + JavaType javaType = protoMapper.getAnyTypes() + .getOrDefault(msgCanonicalName, constructRuntimeType(ProtoConst.MAP_TYPE)); return protoMapper.createRootDeserializer(message, javaType); } protected Object jsonExtendMergeFrom(String typeUrl, byte[] bytes) throws IOException { - return protoMapper.getJsonMapper().readValue(bytes, Object.class); + try { + return protoMapper.getJsonMapper() + .readValue(bytes, Class.forName(typeUrl.substring(ProtoConst.JSON_SCHEMA.length()))); + } catch (ClassNotFoundException e) { + return protoMapper.getJsonMapper() + .readValue(bytes, constructRuntimeType(ProtoConst.OBJECT_TYPE)); + } + } + + private JavaType constructRuntimeType(JavaType defaultType) { + if (this.anyTargetType == null) { + return defaultType; + } else { + return TypeFactory.defaultInstance().constructType(anyTargetType); + } } protected String getInputActualTypeName(Object input) { diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnySchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnySchema.java index 41ba967..87cbba9 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnySchema.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnySchema.java @@ -38,14 +38,14 @@ public class AnySchema<T> extends FieldSchema<T> { public AnySchema(ProtoMapper protoMapper, Field protoField, PropertyDescriptor propertyDescriptor) { super(protoField, propertyDescriptor.getJavaType()); - this.anyEntrySchema = new AnyEntrySchema(protoMapper); + this.anyEntrySchema = new AnyEntrySchema(protoMapper, null); this.getter = propertyDescriptor.getGetter(); this.setter = propertyDescriptor.getSetter(); } @Override public final int mergeFrom(InputEx input, T message) throws IOException { - Object anyValue = anyEntrySchema.deseriaze(input); + Object anyValue = anyEntrySchema.deserialize(input); setter.set(message, anyValue); return input.readFieldNumber(); diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/DeserializerSchemaManager.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/DeserializerSchemaManager.java index 5757abd..8408c54 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/DeserializerSchemaManager.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/DeserializerSchemaManager.java @@ -23,6 +23,7 @@ import java.util.Map; import org.apache.servicecomb.foundation.protobuf.ProtoMapper; import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; @@ -99,6 +100,10 @@ public class DeserializerSchemaManager extends SchemaManager { } public <T> RootDeserializer<T> createRootDeserializer(Message message, Type type) { + if (ProtoUtils.isAnyMessage(message)) { + SchemaEx<Object> messageSchema = new AnyEntrySchema(protoMapper, type); + return new RootDeserializer(messageSchema); + } JavaType javaType = TypeFactory.defaultInstance().constructType(type); SchemaEx<T> messageSchema = getOrCreateMessageSchema(message, javaType); return new RootDeserializer<>(messageSchema); @@ -226,7 +231,7 @@ public class DeserializerSchemaManager extends SchemaManager { } if (ProtoUtils.isAnyField(protoField)) { - AnyEntrySchema anyEntrySchema = new AnyEntrySchema(protoMapper); + AnyEntrySchema anyEntrySchema = new AnyEntrySchema(protoMapper, null); return AnyRepeatedReadSchemas.create(protoField, propertyDescriptor, anyEntrySchema); } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/AnyRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/AnyRepeatedReadSchemas.java index 27251ba..cdfba2a 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/AnyRepeatedReadSchemas.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/AnyRepeatedReadSchemas.java @@ -31,7 +31,7 @@ public class AnyRepeatedReadSchemas { collectionReader = (input, collection) -> { while (true) { - Object value = anyEntrySchema.deseriaze(input); + Object value = anyEntrySchema.deserialize(input); collection.add(value); int fieldNumber = input.readFieldNumber(); diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/SerializerSchemaManager.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/SerializerSchemaManager.java index b71ddea..15734bf 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/SerializerSchemaManager.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/SerializerSchemaManager.java @@ -27,6 +27,7 @@ import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; import org.apache.servicecomb.foundation.protobuf.internal.schema.SchemaManager; +import org.apache.servicecomb.foundation.protobuf.internal.schema.any.AnyEntrySchema; import org.apache.servicecomb.foundation.protobuf.internal.schema.any.AnySchema; import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.AnyRepeatedWriteSchemas; import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.BytesRepeatedWriteSchemas; @@ -93,6 +94,10 @@ public class SerializerSchemaManager extends SchemaManager { } public RootSerializer createRootSerializer(Message message, Type type) { + if (ProtoUtils.isAnyMessage(message)) { + SchemaEx<Object> messageSchema = new AnyEntrySchema(protoMapper, type); + return new RootSerializer(messageSchema); + } JavaType javaType = TypeFactory.defaultInstance().constructType(type); SchemaEx<Object> messageSchema = getOrCreateMessageSchema(message, javaType); return new RootSerializer(messageSchema); diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestAnySchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestAnySchema.java index ebdc754..441bf2f 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestAnySchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestAnySchema.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.Map; import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot; import org.apache.servicecomb.foundation.protobuf.internal.model.Root; @@ -63,7 +64,7 @@ public class TestAnySchema extends TestSchemaBase { check(); Map<String, Object> map = new HashMap<>(); - map.put("@type", "User"); + map.put(ProtoConst.JSON_ID_NAME, "User"); map.put("name", "n1"); Root root = new Root(); root.setAny(map); diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/People.java similarity index 54% copy from demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java copy to foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/People.java index e884229..e5600ce 100644 --- a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/People.java @@ -15,28 +15,12 @@ * limitations under the License. */ -package org.apache.servicecomb.demo.pojo.server; +package org.apache.servicecomb.foundation.test.scaffolding.model; import java.util.List; -import org.apache.servicecomb.demo.server.GenericsModel; -import org.apache.servicecomb.provider.pojo.RpcSchema; +public class People { + public String name; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; - -@RpcSchema(schemaId = "WeakPojo") -public class WeakPojo { - @ApiOperation(value = "differentName", nickname = "differentName") - public int diffNames(@ApiParam(name = "x") int a, @ApiParam(name = "y") int b) { - return a * 2 + b; - } - - public List<List<String>> genericParams(int code, List<List<String>> names) { - return names; - } - - public GenericsModel genericParamsModel(int code, GenericsModel model) { - return model; - } + public List<People> friends; } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayCodec.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayCodec.java index 6d06e1c..fe6e026 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayCodec.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayCodec.java @@ -115,7 +115,7 @@ public final class HighwayCodec { } ResponseRootDeserializer<Object> bodySchema = operationProtobuf.findResponseRootDeserializer(header.getStatusCode()); - Object body = bodySchema.deserialize(tcpData.getBodyBuffer().getBytes()); + Object body = bodySchema.deserialize(tcpData.getBodyBuffer().getBytes(), invocation.findResponseType(header.getStatusCode())); Response response = Response.create(header.getStatusCode(), header.getReasonPhrase(), body); response.setHeaders(header.getHeaders());