| # Overview |
| There are many existing protobuf codecs, but all of them are not suit for us. |
| ServiceComb data model is just POJO, not bind to any codec mechanism, so we had to create new one: |
| |
| | | ServiceComb | protobuf | protostuff | jackson | |
| | -------------------------------------------------------- | :-----------: | :------: | :------------: | :-----: | |
| | generate code | no need<br>just POJO | must<br>100+ lines IDL, generate 10000+ java code | no need<br>POJO with Annotation(eg:@Tag) | no need | |
| | support null element in repeated field | no | no | not compatible | no | |
| | support "oneOf" | no | yes | no | no | |
| | support "packed" | yes | yes | no | no | |
| | support "map" | yes | yes | not compatible | no | |
| | support "any" | yes | yes | not compatible | no | |
| | support "any" not defined in IDL | yes<br>extend based on "any" mechanism | no | not compatible | no | |
| | support field: `List<List<X>>` | yes | no | not compatible | no | |
| | support field: `List<Map<X, Y>>` | yes | no | not compatible | no | |
| | support field: `Map<X, List<Y>>` | yes | no | not compatible | no | |
| | support field: `Map<X, Map<Y, Z>>` | yes | no | not compatible | no | |
| | support field: array | yes | no | not compatible | no | |
| | support generic POJO type, eg:`CustomGeneric<User>` | yes | no | no | no | |
| | serialize/deserialize based on IDL | yes | no | no | yes | |
| | serialize not repeated number field ignore default value | yes | yes | no | no | |
| | serialize from map model | yes | no | no | no | |
| | deserialize to map model | yes | no | no | no | |
| |
| # Usage |
| ## Create factory |
| one factory instance globally is enough |
| ```java |
| ProtoMapperFactory factory = new ProtoMapperFactory(); |
| ``` |
| ## Load proto definition |
| create mapper instance for each proto definition |
| - load from classpath |
| ```java |
| ProtoMapper protoMapper = factory.createFromName("protobuf.proto"); |
| ``` |
| - load from proto content |
| ```java |
| ProtoMapper protoMapper = factory.createFromContent(protoContent); |
| ``` |
| ## Serialize |
| serializer is reusable and thread safe |
| Assuming you have a proto definition |
| ```proto |
| message User { |
| string name = 1; |
| } |
| ``` |
| and a POJO class |
| ```java |
| public class User { |
| private String name; |
| // getter and setter |
| } |
| ``` |
| RootSerializer serializer = protoMapper.createRootSerializer("User", User.class); |
| |
| User user = new User(); |
| user.setName("userName"); |
| byte[] pojoBytes= serializer.serialize(user); |
| |
| Map<String, Object> map = new HashMap<>(); |
| map.put("name", "userName"); |
| byte[] mapBytes = serializer.serialize(map); |
| ```java |
| |
| |
| // pojoBytes equals mapBytes |
| ``` |
| ## Deserialize |
| deserializer is reusable and thread safe |
| ```java |
| RootDeserializer<User> pojoDeserializer = protoMapper.createRootDeserializer("User", User.class); |
| RootDeserializer<Map<String, Object>> mapDeserializer = protoMapper.createRootDeserializer("User", Map.class); |
| |
| User user = pojoDeserializer.deserialize(bytes); |
| Map<String, Object> map = mapDeserializer.deserialize(bytes); |
| ``` |
| |
| # Performance |
| ``` |
| 1.protobuf |
| in our real scenes |
| business model never bind to transport, and can switch between different transports dynamically |
| that means if we choose standard protobuf, must build protobuf models from business models each time |
| so should be much slower than the test results |
| 2.protoStuff |
| some scenes, there is no field but have getter or setter, so we can not use unsafe to access field |
| so we disable protoStuff unsafe feature |
| |
| for repeated fields, protoStuff have better performance, but not compatible to protobuf |
| |
| 3.jackson |
| not support map/any/recursive, ignore related fields |
| 4.serialize result size |
| ScbStrong/ScbWeak/Protobuf have the same and smaller size, because skip all default/null value |
| |
| Empty: |
| Protostuff ScbStrong ScbWeak Protobuf Jackson |
| serialize time(ms) : 519 515 240 288 1242 |
| serialize len : 36 0 0 0 56 |
| deserialize time(ms): 161 69 10 516 486 |
| deserialize->serialize len: 36 0 0 0 56 |
| serialize+deserialize(ms) : 680 584 250 804 1728 |
| |
| Scalars: |
| Protostuff ScbStrong ScbWeak Protobuf Jackson |
| serialize time(ms) : 557 529 328 262 1357 |
| serialize len : 56 24 24 24 76 |
| deserialize time(ms): 181 141 115 527 504 |
| deserialize->serialize len: 56 24 24 24 76 |
| serialize+deserialize(ms) : 738 670 443 789 1861 |
| |
| Pojo: |
| Protostuff ScbStrong ScbWeak Protobuf Jackson |
| serialize time(ms) : 571 574 276 309 1304 |
| serialize len : 46 10 10 10 66 |
| deserialize time(ms): 230 69 112 668 537 |
| deserialize->serialize len: 46 10 10 10 66 |
| serialize+deserialize(ms) : 801 643 388 977 1841 |
| |
| SimpleList: |
| Protostuff ScbStrong ScbWeak Protobuf Jackson |
| serialize time(ms) : 590 609 296 637 1320 |
| serialize len : 68 32 32 32 88 |
| deserialize time(ms): 233 105 122 2226 541 |
| deserialize->serialize len: 68 32 32 32 88 |
| serialize+deserialize(ms) : 823 714 418 2863 1861 |
| |
| PojoList: |
| Protostuff ScbStrong ScbWeak Protobuf Jackson |
| serialize time(ms) : 609 632 319 2777 1407 |
| serialize len : 56 20 20 20 76 |
| deserialize time(ms): 244 134 173 2287 679 |
| deserialize->serialize len: 56 20 20 20 76 |
| serialize+deserialize(ms) : 853 766 492 5064 2086 |
| |
| Map: |
| Protostuff ScbStrong ScbWeak Protobuf Jackson |
| serialize time(ms) : 746 772 491 1079 1298 |
| serialize len : 92 54 54 54 56 |
| deserialize time(ms): 522 427 468 1031 422 |
| deserialize->serialize len: 92 54 54 54 56 |
| serialize+deserialize(ms) : 1268 1199 959 2110 1720 |
| |
| Mixed: |
| Protostuff ScbStrong ScbWeak Protobuf Jackson |
| serialize time(ms) : 1686 1999 2034 2112 2537 |
| serialize len : 479 505 505 505 489 |
| deserialize time(ms): 1969 2154 2923 2984 3316 |
| deserialize->serialize len: 479 505 505 505 489 |
| serialize+deserialize(ms) : 3655 4153 4957 5096 5853 |
| ``` |