Skip to content

Commit b9a6afc

Browse files
authored
Merge pull request msgpack#450 from msgpack/update-msgpack-jackson-readme
Adding some advanced usages
2 parents c61597a + 40ac58a commit b9a6afc

File tree

1 file changed

+231
-17
lines changed

1 file changed

+231
-17
lines changed

msgpack-jackson/README.md

Lines changed: 231 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.msgpack/jackson-dataformat-msgpack/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.msgpack/jackson-dataformat-msgpack/)
44
[![Javadoc](https://javadoc-emblem.rhcloud.com/doc/org.msgpack/jackson-dataformat-msgpack/badge.svg)](http://www.javadoc.io/doc/org.msgpack/jackson-dataformat-msgpack)
55

6-
This Jackson extension library handles reading and writing of data encoded in [MessagePack](http://msgpack.org/) data format.
6+
This Jackson extension library is a component to easily read and write [MessagePack](http://msgpack.org/) encoded data through jackson-databind API.
7+
78
It extends standard Jackson streaming API (`JsonFactory`, `JsonParser`, `JsonGenerator`), and as such works seamlessly with all the higher level data abstractions (data binding, tree model, and pluggable extensions). For the details of Jackson-annotations, please see https://github.com/FasterXML/jackson-annotations.
89

10+
This library isn't compatibile with msgpack-java v0.6 or earlier by default in serialization/deserialization of POJO. See **Advanced usage** below for details.
11+
912
## Install
1013

1114
### Maven
@@ -36,23 +39,66 @@ dependencies {
3639
```
3740

3841

39-
## Usage
42+
## Basic usage
43+
44+
### Serialization/Deserialization of POJO
4045

41-
Only thing you need to do is to instantiate MessagePackFactory and pass it to the constructor of ObjectMapper.
46+
Only thing you need to do is to instantiate `MessagePackFactory` and pass it to the constructor of `com.fasterxml.jackson.databind.ObjectMapper`. And then, you can use it for MessagePack format data in the same way as jackson-databind.
4247

48+
```java
49+
// Instantiate ObjectMapper for MessagePack
50+
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
51+
52+
// Serialize a Java object to byte array
53+
ExamplePojo pojo = new ExamplePojo("komamitsu");
54+
byte[] bytes = objectMapper.writeValueAsBytes(pojo);
55+
56+
// Deserialize the byte array to a Java object
57+
ExamplePojo deserialized = objectMapper.readValue(bytes, ExamplePojo.class);
58+
System.out.println(deserialized.getName()); // => komamitsu
4359
```
60+
61+
### Serialization/Deserialization of List
62+
63+
```java
64+
// Instantiate ObjectMapper for MessagePack
4465
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
45-
ExamplePojo orig = new ExamplePojo("komamitsu");
46-
byte[] bytes = objectMapper.writeValueAsBytes(orig);
47-
ExamplePojo value = objectMapper.readValue(bytes, ExamplePojo.class);
48-
System.out.println(value.getName()); // => komamitsu
66+
67+
// Serialize a List to byte array
68+
List<Object> list = new ArrayList<>();
69+
list.add("Foo");
70+
list.add("Bar");
71+
list.add(42);
72+
byte[] bytes = objectMapper.writeValueAsBytes(list);
73+
74+
// Deserialize the byte array to a List
75+
List<Object> deserialized = objectMapper.readValue(bytes, new TypeReference<List<Object>>() {});
76+
System.out.println(deserialized); // => [Foo, Bar, 42]
4977
```
5078

51-
Also, you can exchange data among multiple languages.
79+
### Serialization/Deserialization of Map
80+
81+
```java
82+
// Instantiate ObjectMapper for MessagePack
83+
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
84+
85+
// Serialize a Map to byte array
86+
Map<String, Object> map = new HashMap<>();
87+
map.put("name", "komamitsu");
88+
map.put("age", 42);
89+
byte[] bytes = objectMapper.writeValueAsBytes(map);
90+
91+
// Deserialize the byte array to a Map
92+
Map<String, Object> deserialized = objectMapper.readValue(bytes, new TypeReference<Map<String, Object>>() {});
93+
System.out.println(deserialized); // => {name=komamitsu, age=42}
94+
95+
```
96+
97+
### Example of Serialization/Deserialization over multiple languages
5298

5399
Java
54100

55-
```
101+
```java
56102
// Serialize
57103
Map<String, Object> obj = new HashMap<String, Object>();
58104
obj.put("foo", "hello");
@@ -64,7 +110,7 @@ Java
64110

65111
Ruby
66112

67-
```
113+
```ruby
68114
require 'msgpack'
69115

70116
# Deserialize
@@ -80,7 +126,7 @@ Ruby
80126

81127
Java
82128

83-
```
129+
```java
84130
// Deserialize
85131
bs = new byte[] {(byte) 148, (byte) 164, 122, 101, 114, 111, 1,
86132
(byte) 203, 64, 0, 0, 0, 0, 0, 0, 0, (byte) 192};
@@ -89,15 +135,183 @@ Java
89135
// xs => [zero, 1, 2.0, null]
90136
```
91137

92-
### Serialization format
138+
## Advanced usage
93139

94-
By default, the serialization format is object, which means it includes the schema of the serialized entity (POJO).
95-
To serialize an entity without the schema, only as array, you can add the annotation `@JsonFormat(shape=JsonFormat.Shape.ARRAY)` to the entity definition.
96-
Also, it's possible to set the serialization format for the object mapper instance to be array by changing the annotation inspector of object mapper to `JsonArrayFormat`:
140+
### Serialize/Deserialize POJO as MessagePack array type to keep compatibility with msgpack-java:0.6
97141

98-
```
142+
In msgpack-java:0.6 or earlier, a POJO was serliazed and deserialized as an array of values in MessagePack format. The order of values depended on an internal order of Java class's variables and it was a naive way and caused some issues since Java class's variables order isn't guaranteed over Java implementations.
143+
144+
On the other hand, jackson-databind serializes and deserializes a POJO as a key-value object. So this `jackson-dataformat-msgpack` also handles POJOs in the same way. As a result, it isn't compatible with msgpack-java:0.6 or earlier in serialization and deserialization of POJOs.
145+
146+
But if you want to make this library handle POJOs in the same way as msgpack-java:0.6 or earlier, you can use `JsonArrayFormat` like this:
147+
148+
```java
99149
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
100150
objectMapper.setAnnotationIntrospector(new JsonArrayFormat());
101151
```
102152

103-
This format provides compatibility with msgpack-java 0.6.x serialization api.
153+
### Serialize multiple values without closing an output stream
154+
155+
`com.fasterxml.jackson.databind.ObjectMapper` closes an output stream by default after it writes a value. If you want to serialize multiple values in a row without closing an output stream, set `JsonGenerator.Feature.AUTO_CLOSE_TARGET` to false.
156+
157+
```java
158+
OutputStream out = new FileOutputStream(tempFile);
159+
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
160+
objectMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
161+
162+
objectMapper.writeValue(out, 1);
163+
objectMapper.writeValue(out, "two");
164+
objectMapper.writeValue(out, 3.14);
165+
out.close();
166+
167+
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(new FileInputStream(tempFile));
168+
System.out.println(unpacker.unpackInt()); // => 1
169+
System.out.println(unpacker.unpackString()); // => two
170+
System.out.println(unpacker.unpackFloat()); // => 3.14
171+
```
172+
173+
### Deserialize multiple values without closing an input stream
174+
175+
`com.fasterxml.jackson.databind.ObjectMapper` closes an input stream by default after it reads a value. If you want to deserialize multiple values in a row without closing an output stream, set `JsonParser.Feature.AUTO_CLOSE_SOURCE` to false.
176+
177+
```java
178+
MessagePacker packer = MessagePack.newDefaultPacker(new FileOutputStream(tempFile));
179+
packer.packInt(42);
180+
packer.packString("Hello");
181+
packer.close();
182+
183+
FileInputStream in = new FileInputStream(tempFile);
184+
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
185+
objectMapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
186+
System.out.println(objectMapper.readValue(in, Integer.class));
187+
System.out.println(objectMapper.readValue(in, String.class));
188+
in.close();
189+
```
190+
191+
### Serialize not using str8 type
192+
193+
Old msgpack-java (e.g 0.6.7) doesn't support MessagePack str8 type. When your application needs to comunicate with such an old MessagePack library, you can disable the data type like this:
194+
195+
```java
196+
MessagePack.PackerConfig config = new MessagePack.PackerConfig().withStr8FormatSupport(false);
197+
ObjectMapper mapperWithConfig = new ObjectMapper(new MessagePackFactory(config));
198+
// This string is serialized as bin8 type
199+
byte[] resultWithoutStr8Format = mapperWithConfig.writeValueAsBytes(str8LengthString);
200+
```
201+
202+
### Serialize using non-String as a key of Map
203+
204+
When you want to use non-String value as a key of Map, use `MessagePackKeySerializer` for key serialization.
205+
206+
```java
207+
@JsonSerialize(keyUsing = MessagePackKeySerializer.class)
208+
private Map<Integer, String> intMap = new HashMap<>();
209+
210+
:
211+
{
212+
intMap.put(42, "Hello");
213+
214+
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
215+
byte[] bytes = objectMapper.writeValueAsBytes(intMap);
216+
217+
Map<Integer, String> deserialized = objectMapper.readValue(bytes, new TypeReference<Map<Integer, String>>() {});
218+
System.out.println(deserialized); // => {42=Hello}
219+
}
220+
```
221+
222+
### Deserialize extension types with ExtensionTypeCustomDeserializers
223+
224+
`ExtensionTypeCustomDeserializers` helps you to deserialize extension types easily.
225+
226+
#### With target Java class
227+
228+
```java
229+
NestedListComplexPojo parent = new NestedListComplexPojo();
230+
parent.children = Arrays.asList(new TinyPojo("Foo"), new TinyPojo("Bar"));
231+
232+
// In this application, extension type 17 is used for NestedListComplexPojo
233+
byte[] bytes;
234+
{
235+
// This ObjectMapper is just for temporary serialization
236+
ObjectMapper tempObjectMapper = new ObjectMapper(new MessagePackFactory());
237+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
238+
MessagePacker packer = MessagePack.newDefaultPacker(outputStream);
239+
240+
byte[] extBytes = tempObjectMapper.writeValueAsBytes(parent);
241+
packer.packExtensionTypeHeader((byte) 17, extBytes.length);
242+
packer.addPayload(extBytes);
243+
packer.close();
244+
245+
bytes = outputStream.toByteArray();
246+
}
247+
248+
// Register the type and the class to ExtensionTypeCustomDeserializers
249+
ExtensionTypeCustomDeserializers extTypeCustomDesers = new ExtensionTypeCustomDeserializers();
250+
extTypeCustomDesers.addTargetClass((byte) 17, NestedListComplexPojo.class);
251+
ObjectMapper objectMapper = new ObjectMapper(
252+
new MessagePackFactory().setExtTypeCustomDesers(extTypeCustomDesers));
253+
254+
System.out.println(objectMapper.readValue(bytes, Object.class));
255+
// => NestedListComplexPojo{children=[TinyPojo{name='Foo'}, TinyPojo{name='Bar'}]}
256+
```
257+
258+
#### With type reference
259+
260+
```java
261+
Map<String, Integer> map = new HashMap<>();
262+
map.put("one", 1);
263+
map.put("two", 2);
264+
265+
// In this application, extension type 31 is used for Map<String, Integer>
266+
byte[] bytes;
267+
{
268+
// Same as above
269+
:
270+
packer.packExtensionTypeHeader((byte) 31, extBytes.length);
271+
:
272+
}
273+
274+
// Register the type and the type reference to ExtensionTypeCustomDeserializers
275+
ExtensionTypeCustomDeserializers extTypeCustomDesers = new ExtensionTypeCustomDeserializers();
276+
extTypeCustomDesers.addTargetTypeReference((byte) 31,
277+
new TypeReference<Map<String, Integer>>() {});
278+
ObjectMapper objectMapper = new ObjectMapper(
279+
new MessagePackFactory().setExtTypeCustomDesers(extTypeCustomDesers));
280+
281+
System.out.println(objectMapper.readValue(bytes, Object.class));
282+
// => {one=1, two=2}
283+
```
284+
285+
#### With custom deserializer
286+
287+
```java
288+
// In this application, extension type 59 is used for byte[]
289+
byte[] bytes;
290+
{
291+
// This ObjectMapper is just for temporary serialization
292+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
293+
MessagePacker packer = MessagePack.newDefaultPacker(outputStream);
294+
295+
packer.packExtensionTypeHeader((byte) 59, hexspeak.length);
296+
packer.addPayload(hexspeak);
297+
packer.close();
298+
299+
bytes = outputStream.toByteArray();
300+
}
301+
302+
// Register the type and a deserializer to ExtensionTypeCustomDeserializers
303+
ExtensionTypeCustomDeserializers extTypeCustomDesers = new ExtensionTypeCustomDeserializers();
304+
extTypeCustomDesers.addCustomDeser((byte) 59, data -> {
305+
if (Arrays.equals(data,
306+
new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE})) {
307+
return "Java";
308+
}
309+
return "Not Java";
310+
}
311+
);
312+
ObjectMapper objectMapper = new ObjectMapper(
313+
new MessagePackFactory().setExtTypeCustomDesers(extTypeCustomDesers));
314+
315+
System.out.println(objectMapper.readValue(bytes, Object.class));
316+
// => Java
317+
```

0 commit comments

Comments
 (0)