diff --git a/msgpack-jackson/README.md b/msgpack-jackson/README.md index 7e859781..e91c6f8b 100644 --- a/msgpack-jackson/README.md +++ b/msgpack-jackson/README.md @@ -61,7 +61,13 @@ Only thing you need to do is to instantiate `MessagePackFactory` and pass it to Or more easily: ```java -ObjectMapper objectMapper = new MessagePackMapper(); + ObjectMapper objectMapper = new MessagePackMapper(); +``` + +We strongly recommend to call `MessagePackMapper#handleBigDecimalAsString()` if you serialize and/or deserialize BigDecimal values. See [Serialize and deserialize BigDecimal as str type internally in MessagePack format](#serialize-and-deserialize-bigdecimal-as-str-type-internally-in-messagepack-format) for details. + +```java + ObjectMapper objectMapper = new MessagePackMapper().handleBigDecimalAsString(); ``` ### Serialization/Deserialization of List @@ -226,26 +232,33 @@ When you want to use non-String value as a key of Map, use `MessagePackKeySerial ### Serialize and deserialize BigDecimal as str type internally in MessagePack format -`jackson-dataformat-msgpack` represents BigDecimal values as float type in MessagePack format by default. When you want to handle BigDeciaml values as str type with arbitrary precision in MessagePack format, you can use `com.fasterxml.jackson.databind.cfg.MutableConfigOverride#setFormat` like this: +`jackson-dataformat-msgpack` represents BigDecimal values as float type in MessagePack format by default for backward compatibility. But the default behavior could fail when handling too large value for `double` type. So we strongly recommend to call `MessagePackMapper#handleBigDecimalAsString()` to internally handle BigDecimal values as String. ```java - ObjectMapper mapper = new ObjectMapper(new MessagePackFactory()); - mapper.configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING)); + ObjectMapper objectMapper = new MessagePackMapper().handleBigDecimalAsString(); Pojo obj = new Pojo(); + // This value is too large to be serialized as double obj.value = new BigDecimal("1234567890.98765432100"); - byte[] converted = mapper.writeValueAsBytes(obj); + byte[] converted = objectMapper.writeValueAsBytes(obj); + + System.out.println(objectMapper.readValue(converted, Pojo.class)); // => Pojo{value=1234567890.98765432100} +``` +`MessagePackMapper#handleBigDecimalAsString()` is equivalent to the following configuration. - System.out.println(mapper.readValue(converted, Pojo.class)); // => Pojo{value=1234567890.98765432100} +```java + ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory()); + objectMapper.configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING)); ``` + ### Serialize and deserialize Instant instances as MessagePack extension type `timestamp` extension type is defined in MessagePack as type:-1. Registering `TimestampExtensionModule.INSTANCE` module enables automatic serialization and deserialization of java.time.Instant to/from the MessagePack extension type. ```java - ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory()) + ObjectMapper objectMapper = new MessagePackMapper() .registerModule(TimestampExtensionModule.INSTANCE); Pojo pojo = new Pojo(); // The type of `timestamp` variable is Instant @@ -287,8 +300,8 @@ When you want to use non-String value as a key of Map, use `MessagePackKeySerial return "Java"; } return "Not Java"; - } - ); + }); + ObjectMapper objectMapper = new ObjectMapper( new MessagePackFactory().setExtTypeCustomDesers(extTypeCustomDesers)); @@ -476,4 +489,3 @@ There are a few options to fix this issue, but they introduce performance degred ObjectMapper objectMapper = new ObjectMapper( new MessagePackFactory().setReuseResourceInGenerator(false)); ``` - diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackMapper.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackMapper.java index 3c3d228b..52af0372 100644 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackMapper.java +++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackMapper.java @@ -15,9 +15,12 @@ // package org.msgpack.jackson.dataformat; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.cfg.MapperBuilder; +import java.math.BigDecimal; + public class MessagePackMapper extends ObjectMapper { private static final long serialVersionUID = 3L; @@ -40,6 +43,12 @@ public MessagePackMapper(MessagePackFactory f) super(f); } + public MessagePackMapper handleBigDecimalAsString() + { + configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING)); + return this; + } + public static Builder builder() { return new Builder(new MessagePackMapper()); diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackMapperTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackMapperTest.java new file mode 100644 index 00000000..6dfd41cf --- /dev/null +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackMapperTest.java @@ -0,0 +1,44 @@ +// +// MessagePack for Java +// +// Licensed 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.msgpack.jackson.dataformat; + +import org.junit.Test; + +import java.io.IOException; +import java.math.BigDecimal; + +import static org.junit.Assert.assertEquals; + +public class MessagePackMapperTest +{ + static class Pojo + { + public BigDecimal value; + } + + @Test + public void handleBigDecimalAsString() throws IOException + { + MessagePackMapper mapper = new MessagePackMapper().handleBigDecimalAsString(); + Pojo obj = new Pojo(); + obj.value = new BigDecimal("1234567890.98765432100"); + + byte[] converted = mapper.writeValueAsBytes(obj); + + Pojo deserialized = mapper.readValue(converted, Pojo.class); + assertEquals(obj.value, deserialized.value); + } +}