Skip to content

Commit

Permalink
Add MessagePackMapper#handleBigIntegerAndBigDecimalAsString (#768)
Browse files Browse the repository at this point in the history
* Add MessagePackMapper#handleBigIntegerAndBigDecimalAsString

* Rename unit test method names
  • Loading branch information
komamitsu authored Oct 1, 2023
1 parent ce4410d commit 8d514ba
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 12 deletions.
11 changes: 6 additions & 5 deletions msgpack-jackson/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ Or more easily:
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.
We strongly recommend to call `MessagePackMapper#handleBigIntegerAndBigDecimalAsString()` if you serialize and/or deserialize BigInteger/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();
ObjectMapper objectMapper = new MessagePackMapper().handleBigIntegerAndBigDecimalAsString();
```

### Serialization/Deserialization of List
Expand Down Expand Up @@ -232,10 +232,10 @@ 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 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.
`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#handleBigIntegerAndBigDecimalAsString()` to internally handle BigDecimal values as String.

```java
ObjectMapper objectMapper = new MessagePackMapper().handleBigDecimalAsString();
ObjectMapper objectMapper = new MessagePackMapper().handleBigIntegerAndBigDecimalAsString();

Pojo obj = new Pojo();
// This value is too large to be serialized as double
Expand All @@ -245,10 +245,11 @@ When you want to use non-String value as a key of Map, use `MessagePackKeySerial

System.out.println(objectMapper.readValue(converted, Pojo.class)); // => Pojo{value=1234567890.98765432100}
```
`MessagePackMapper#handleBigDecimalAsString()` is equivalent to the following configuration.
`MessagePackMapper#handleBigIntegerAndDecimalAsString()` is equivalent to the following configuration.

```java
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
objectMapper.configOverride(BigInteger.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));
objectMapper.configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.fasterxml.jackson.databind.cfg.MapperBuilder;

import java.math.BigDecimal;
import java.math.BigInteger;

public class MessagePackMapper extends ObjectMapper
{
Expand All @@ -43,12 +44,23 @@ public MessagePackMapper(MessagePackFactory f)
super(f);
}

public MessagePackMapper handleBigIntegerAsString()
{
configOverride(BigInteger.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));
return this;
}

public MessagePackMapper handleBigDecimalAsString()
{
configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));
return this;
}

public MessagePackMapper handleBigIntegerAndBigDecimalAsString()
{
return handleBigIntegerAsString().handleBigDecimalAsString();
}

public static Builder builder()
{
return new Builder(new MessagePackMapper());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,97 @@
//
package org.msgpack.jackson.dataformat;

import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.Test;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

public class MessagePackMapperTest
{
static class Pojo
static class PojoWithBigInteger
{
public BigInteger value;
}

static class PojoWithBigDecimal
{
public BigDecimal value;
}

@Test
public void handleBigDecimalAsString() throws IOException
private void shouldFailToHandleBigInteger(MessagePackMapper messagePackMapper) throws JsonProcessingException
{
PojoWithBigInteger obj = new PojoWithBigInteger();
obj.value = BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.valueOf(10));

try {
messagePackMapper.writeValueAsBytes(obj);
fail();
}
catch (IllegalArgumentException e) {
// Expected
}
}

private void shouldSuccessToHandleBigInteger(MessagePackMapper messagePackMapper) throws IOException
{
MessagePackMapper mapper = new MessagePackMapper().handleBigDecimalAsString();
Pojo obj = new Pojo();
PojoWithBigInteger obj = new PojoWithBigInteger();
obj.value = BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.valueOf(10));

byte[] converted = messagePackMapper.writeValueAsBytes(obj);

PojoWithBigInteger deserialized = messagePackMapper.readValue(converted, PojoWithBigInteger.class);
assertEquals(obj.value, deserialized.value);
}

private void shouldFailToHandleBigDecimal(MessagePackMapper messagePackMapper) throws JsonProcessingException
{
PojoWithBigDecimal obj = new PojoWithBigDecimal();
obj.value = new BigDecimal("1234567890.98765432100");

byte[] converted = mapper.writeValueAsBytes(obj);
try {
messagePackMapper.writeValueAsBytes(obj);
fail();
}
catch (IllegalArgumentException e) {
// Expected
}
}

Pojo deserialized = mapper.readValue(converted, Pojo.class);
private void shouldSuccessToHandleBigDecimal(MessagePackMapper messagePackMapper) throws IOException
{
PojoWithBigDecimal obj = new PojoWithBigDecimal();
obj.value = new BigDecimal("1234567890.98765432100");

byte[] converted = messagePackMapper.writeValueAsBytes(obj);

PojoWithBigDecimal deserialized = messagePackMapper.readValue(converted, PojoWithBigDecimal.class);
assertEquals(obj.value, deserialized.value);
}

@Test
public void handleBigIntegerAsString() throws IOException
{
shouldFailToHandleBigInteger(new MessagePackMapper());
shouldSuccessToHandleBigInteger(new MessagePackMapper().handleBigIntegerAsString());
}

@Test
public void handleBigDecimalAsString() throws IOException
{
shouldFailToHandleBigDecimal(new MessagePackMapper());
shouldSuccessToHandleBigDecimal(new MessagePackMapper().handleBigDecimalAsString());
}

@Test
public void handleBigIntegerAndBigDecimalAsString() throws IOException
{
MessagePackMapper messagePackMapper = new MessagePackMapper().handleBigIntegerAndBigDecimalAsString();
shouldSuccessToHandleBigInteger(messagePackMapper);
shouldSuccessToHandleBigDecimal(messagePackMapper);
}
}

0 comments on commit 8d514ba

Please sign in to comment.