Skip to content

Commit 9586366

Browse files
authored
Add MessagePackMapper#handleBigDecimalAsString (#745)
1 parent 4b38954 commit 9586366

File tree

3 files changed

+75
-10
lines changed

3 files changed

+75
-10
lines changed

msgpack-jackson/README.md

+22-10
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,13 @@ Only thing you need to do is to instantiate `MessagePackFactory` and pass it to
6161
Or more easily:
6262

6363
```java
64-
ObjectMapper objectMapper = new MessagePackMapper();
64+
ObjectMapper objectMapper = new MessagePackMapper();
65+
```
66+
67+
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.
68+
69+
```java
70+
ObjectMapper objectMapper = new MessagePackMapper().handleBigDecimalAsString();
6571
```
6672

6773
### Serialization/Deserialization of List
@@ -226,26 +232,33 @@ When you want to use non-String value as a key of Map, use `MessagePackKeySerial
226232

227233
### Serialize and deserialize BigDecimal as str type internally in MessagePack format
228234

229-
`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:
235+
`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.
230236

231237
```java
232-
ObjectMapper mapper = new ObjectMapper(new MessagePackFactory());
233-
mapper.configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));
238+
ObjectMapper objectMapper = new MessagePackMapper().handleBigDecimalAsString();
234239

235240
Pojo obj = new Pojo();
241+
// This value is too large to be serialized as double
236242
obj.value = new BigDecimal("1234567890.98765432100");
237243

238-
byte[] converted = mapper.writeValueAsBytes(obj);
244+
byte[] converted = objectMapper.writeValueAsBytes(obj);
245+
246+
System.out.println(objectMapper.readValue(converted, Pojo.class)); // => Pojo{value=1234567890.98765432100}
247+
```
248+
`MessagePackMapper#handleBigDecimalAsString()` is equivalent to the following configuration.
239249

240-
System.out.println(mapper.readValue(converted, Pojo.class)); // => Pojo{value=1234567890.98765432100}
250+
```java
251+
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
252+
objectMapper.configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));
241253
```
242254

255+
243256
### Serialize and deserialize Instant instances as MessagePack extension type
244257

245258
`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.
246259

247260
```java
248-
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory())
261+
ObjectMapper objectMapper = new MessagePackMapper()
249262
.registerModule(TimestampExtensionModule.INSTANCE);
250263
Pojo pojo = new Pojo();
251264
// 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
287300
return "Java";
288301
}
289302
return "Not Java";
290-
}
291-
);
303+
});
304+
292305
ObjectMapper objectMapper = new ObjectMapper(
293306
new MessagePackFactory().setExtTypeCustomDesers(extTypeCustomDesers));
294307

@@ -476,4 +489,3 @@ There are a few options to fix this issue, but they introduce performance degred
476489
ObjectMapper objectMapper = new ObjectMapper(
477490
new MessagePackFactory().setReuseResourceInGenerator(false));
478491
```
479-

msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackMapper.java

+9
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
//
1616
package org.msgpack.jackson.dataformat;
1717

18+
import com.fasterxml.jackson.annotation.JsonFormat;
1819
import com.fasterxml.jackson.databind.ObjectMapper;
1920
import com.fasterxml.jackson.databind.cfg.MapperBuilder;
2021

22+
import java.math.BigDecimal;
23+
2124
public class MessagePackMapper extends ObjectMapper
2225
{
2326
private static final long serialVersionUID = 3L;
@@ -40,6 +43,12 @@ public MessagePackMapper(MessagePackFactory f)
4043
super(f);
4144
}
4245

46+
public MessagePackMapper handleBigDecimalAsString()
47+
{
48+
configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));
49+
return this;
50+
}
51+
4352
public static Builder builder()
4453
{
4554
return new Builder(new MessagePackMapper());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// MessagePack for Java
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
package org.msgpack.jackson.dataformat;
17+
18+
import org.junit.Test;
19+
20+
import java.io.IOException;
21+
import java.math.BigDecimal;
22+
23+
import static org.junit.Assert.assertEquals;
24+
25+
public class MessagePackMapperTest
26+
{
27+
static class Pojo
28+
{
29+
public BigDecimal value;
30+
}
31+
32+
@Test
33+
public void handleBigDecimalAsString() throws IOException
34+
{
35+
MessagePackMapper mapper = new MessagePackMapper().handleBigDecimalAsString();
36+
Pojo obj = new Pojo();
37+
obj.value = new BigDecimal("1234567890.98765432100");
38+
39+
byte[] converted = mapper.writeValueAsBytes(obj);
40+
41+
Pojo deserialized = mapper.readValue(converted, Pojo.class);
42+
assertEquals(obj.value, deserialized.value);
43+
}
44+
}

0 commit comments

Comments
 (0)