With persistence or network transmission, we need a serialization framework.
XML and JSON are readable, but not so effective. Protobuf/thrift/avro has good performance, but there is a need to write IDL and import a heavy library.
Finally, I wrote one by myself, which I named Packable. Packable’s design and implementation take reference from Protobuf and Parcelable, but is different from both of them.
Packable has the following advantages:
- Fast encoding/decoding
- Compact coding and small size
- Easy to use, flexible
- The code is light
- Support multiple types
- Support multiple compression strategies
- Supports multiple languages and cross-platforms
Packable currently implements versions of Java, C++, C#, Objective-C, Go.
Example
static class Data implements Packable { String msg; Item[] items; @Override public void encode(PackEncoder encoder) { encoder.putString(0, msg) .putPackableArray(1, items); } public static final PackCreator<Data> CREATOR = decoder -> { Data data = new Data(); data.msg = decoder.getString(0); data.items = decoder.getPackableArray(1, Item.CREATOR); return data; }; } static class Item implements Packable { int a; long b; Item(int a, long b) { this.a = a; this.b = b; } @Override public void encode(PackEncoder encoder) { encoder.putInt(0, a); encoder.putLong(1, b); } static final PackArrayCreator<Item> CREATOR = new PackArrayCreator<Item>() { @Override public Item[] newArray(int size) { return new Item[size]; } @Override public Item decode(PackDecoder decoder) { return new Item( decoder.getInt(0), decoder.getLong(1) ); } }; } static void test() { Data data = new Data(); byte[] bytes = PackEncoder.marshal(data); Data data_2 = PackDecoder.unmarshal(bytes, Data.CREATOR); }
Serialization
- Implements the interface Packable.
- Implement the encode() method, to encode each field (PackEncoder provides various types of API).
- Call the PackEncoder.marshal() method, transfer the object, and get the byte array.
Deserialization
- Create a static object, which is an instance of PackCreator.
- Implement the decode() method, decode each field, and assign it to the object.
- Call PackDecoder.unmarshal(), transfer the byte array and PackCreator instance.
If you need to deserialize an array of objects, you need to create an instance of PackArrayCreator (Only Java version needs to do this; other platforms have no need to do this).
The example above is only one of the examples. It can be used flexibly.
- PackCreator does not have to be created in the class which implements Packable. It can also be created anywhere else.
- If you only need serialization (sender), you just need to implement Packable.
- You can also directly encode/decode the message.
static void test2() { String msg = "message"; int a = 100; int b = 200; PackEncoder encoder = new PackEncoder(); encoder.putString(0, msg) .putInt(1, a) .putInt(2, b); byte[] bytes = encoder.getBytes(); PackDecoder decoder = PackDecoder.newInstance(bytes); String dMsg = decoder.getString(0); int dA = decoder.getInt(1); int dB = decoder.getInt(2); decoder.recycle(); boolean equal = msg.equals(dMsg) && (a == dA) && (b == dB); Assert.assertTrue(equal); }
Benchmark
Space of serialization bytes:
Space (byte) | |
---|---|
packable | 2537191 (57%) |
protobuf | 2614001 (59%) |
gson | 4407901 (100%) |
Process time:
PC (Macbook Pro)
Serialization (ms) | Deserialization (ms) | |
---|---|---|
packable | 9 | 8 |
protobuf | 19 | 11 |
gson | 67 | 46 |
Phone (Huawei Honor 20S)
Serialization (ms) | Deserialization (ms) | |
---|---|---|
packable | 32 | 21 |
protobuf | 81 | 38 |
gson | 190 | 128 |
You are welcome to use it or join the project. The project has been published to Github: https://github.com/BillyWei001/Packable