Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
20 changes: 19 additions & 1 deletion 20 msgpack-jackson/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,27 @@ When you want to use non-String value as a key of Map, use `MessagePackKeySerial
System.out.println(mapper.readValue(converted, Pojo.class)); // => Pojo{value=1234567890.98765432100}
```

### 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())
.registerModule(TimestampExtensionModule.INSTANCE);
Pojo pojo = new Pojo();
// The type of `timestamp` variable is Instant
pojo.timestamp = Instant.now();
byte[] bytes = objectMapper.writeValueAsBytes(pojo);

// The Instant instance is serialized as MessagePack extension type (type: -1)

Pojo deserialized = objectMapper.readValue(bytes, Pojo.class);
System.out.println(deserialized); // "2022-09-14T08:47:24.922Z"
```

### Deserialize extension types with ExtensionTypeCustomDeserializers

`ExtensionTypeCustomDeserializers` helps you to deserialize extension types easily.
`ExtensionTypeCustomDeserializers` helps you to deserialize your own custom extension types easily.

#### Deserialize extension type value directly

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.msgpack.jackson.dataformat;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.msgpack.core.ExtensionTypeHeader;
import org.msgpack.core.MessagePack;
import org.msgpack.core.MessagePacker;
import org.msgpack.core.MessageUnpacker;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.Instant;

public class TimestampExtensionModule
{
public static final byte EXT_TYPE = -1;
public static final SimpleModule INSTANCE = new SimpleModule("msgpack-ext-timestamp");

static {
INSTANCE.addSerializer(Instant.class, new InstantSerializer(Instant.class));
INSTANCE.addDeserializer(Instant.class, new InstantDeserializer(Instant.class));
}

private static class InstantSerializer extends StdSerializer<Instant>
{
protected InstantSerializer(Class<Instant> t)
{
super(t);
}

@Override
public void serialize(Instant value, JsonGenerator gen, SerializerProvider provider)
throws IOException
{
ByteArrayOutputStream os = new ByteArrayOutputStream();
// MEMO: Reusing these MessagePacker and MessageUnpacker instances would improve the performance
try (MessagePacker packer = MessagePack.newDefaultPacker(os)) {
packer.packTimestamp(value);
}
try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(os.toByteArray())) {
ExtensionTypeHeader header = unpacker.unpackExtensionTypeHeader();
byte[] bytes = unpacker.readPayload(header.getLength());

MessagePackExtensionType extensionType = new MessagePackExtensionType(EXT_TYPE, bytes);
gen.writeObject(extensionType);
}
}
}

private static class InstantDeserializer extends StdDeserializer<Instant>
{
protected InstantDeserializer(Class<?> vc)
{
super(vc);
}

@Override
public Instant deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException
{
MessagePackExtensionType ext = p.readValueAs(MessagePackExtensionType.class);
if (ext.getType() != EXT_TYPE) {
throw new RuntimeException(
String.format("Unexpected extension type (0x%X) for Instant object", ext.getType()));
}

// MEMO: Reusing this MessageUnpacker instance would improve the performance
try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(ext.getData())) {
return unpacker.unpackTimestamp(new ExtensionTypeHeader(EXT_TYPE, ext.getData().length));
}
}
}

private TimestampExtensionModule()
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
//
// 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 com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.msgpack.core.MessagePack;
import org.msgpack.core.MessagePacker;
import org.msgpack.core.MessageUnpacker;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.Instant;

import static org.junit.Assert.assertEquals;

public class TimestampExtensionModuleTest
{
private final ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
private final SingleInstant singleInstant = new SingleInstant();
private final TripleInstants tripleInstants = new TripleInstants();

private static class SingleInstant
{
public Instant instant;
}

private static class TripleInstants
{
public Instant a;
public Instant b;
public Instant c;
}

@Before
public void setUp()
throws Exception
{
objectMapper.registerModule(TimestampExtensionModule.INSTANCE);
}

@Test
public void testSingleInstantPojo()
throws IOException
{
singleInstant.instant = Instant.now();
byte[] bytes = objectMapper.writeValueAsBytes(singleInstant);
SingleInstant deserialized = objectMapper.readValue(bytes, SingleInstant.class);
assertEquals(singleInstant.instant, deserialized.instant);
}

@Test
public void testTripleInstantsPojo()
throws IOException
{
Instant now = Instant.now();
tripleInstants.a = now.minusSeconds(1);
tripleInstants.b = now;
tripleInstants.c = now.plusSeconds(1);
byte[] bytes = objectMapper.writeValueAsBytes(tripleInstants);
TripleInstants deserialized = objectMapper.readValue(bytes, TripleInstants.class);
assertEquals(now.minusSeconds(1), deserialized.a);
assertEquals(now, deserialized.b);
assertEquals(now.plusSeconds(1), deserialized.c);
}

@Test
public void serialize32BitFormat()
throws IOException
{
singleInstant.instant = Instant.ofEpochSecond(Instant.now().getEpochSecond());

byte[] bytes = objectMapper.writeValueAsBytes(singleInstant);

// Check the size of serialized data first
try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
unpacker.unpackMapHeader();
assertEquals("instant", unpacker.unpackString());
assertEquals(4, unpacker.unpackExtensionTypeHeader().getLength());
}

try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
unpacker.unpackMapHeader();
unpacker.unpackString();
assertEquals(singleInstant.instant, unpacker.unpackTimestamp());
}
}

@Test
public void serialize64BitFormat()
throws IOException
{
singleInstant.instant = Instant.ofEpochSecond(Instant.now().getEpochSecond(), 1234);

byte[] bytes = objectMapper.writeValueAsBytes(singleInstant);

// Check the size of serialized data first
try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
unpacker.unpackMapHeader();
assertEquals("instant", unpacker.unpackString());
assertEquals(8, unpacker.unpackExtensionTypeHeader().getLength());
}

try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
unpacker.unpackMapHeader();
unpacker.unpackString();
assertEquals(singleInstant.instant, unpacker.unpackTimestamp());
}
}

@Test
public void serialize96BitFormat()
throws IOException
{
singleInstant.instant = Instant.ofEpochSecond(19880866800L /* 2600-01-01 */, 1234);

byte[] bytes = objectMapper.writeValueAsBytes(singleInstant);

// Check the size of serialized data first
try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
unpacker.unpackMapHeader();
assertEquals("instant", unpacker.unpackString());
assertEquals(12, unpacker.unpackExtensionTypeHeader().getLength());
}

try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
unpacker.unpackMapHeader();
unpacker.unpackString();
assertEquals(singleInstant.instant, unpacker.unpackTimestamp());
}
}

@Test
public void deserialize32BitFormat()
throws IOException
{
Instant instant = Instant.ofEpochSecond(Instant.now().getEpochSecond());

ByteArrayOutputStream os = new ByteArrayOutputStream();
try (MessagePacker packer = MessagePack.newDefaultPacker(os)) {
packer.packMapHeader(1)
.packString("instant")
.packTimestamp(instant);
}

byte[] bytes = os.toByteArray();
try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
unpacker.unpackMapHeader();
unpacker.unpackString();
assertEquals(4, unpacker.unpackExtensionTypeHeader().getLength());
}

SingleInstant deserialized = objectMapper.readValue(bytes, SingleInstant.class);
assertEquals(instant, deserialized.instant);
}

@Test
public void deserialize64BitFormat()
throws IOException
{
Instant instant = Instant.ofEpochSecond(Instant.now().getEpochSecond(), 1234);

ByteArrayOutputStream os = new ByteArrayOutputStream();
try (MessagePacker packer = MessagePack.newDefaultPacker(os)) {
packer.packMapHeader(1)
.packString("instant")
.packTimestamp(instant);
}

byte[] bytes = os.toByteArray();
try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
unpacker.unpackMapHeader();
unpacker.unpackString();
assertEquals(8, unpacker.unpackExtensionTypeHeader().getLength());
}

SingleInstant deserialized = objectMapper.readValue(bytes, SingleInstant.class);
assertEquals(instant, deserialized.instant);
}

@Test
public void deserialize96BitFormat()
throws IOException
{
Instant instant = Instant.ofEpochSecond(19880866800L /* 2600-01-01 */, 1234);

ByteArrayOutputStream os = new ByteArrayOutputStream();
try (MessagePacker packer = MessagePack.newDefaultPacker(os)) {
packer.packMapHeader(1)
.packString("instant")
.packTimestamp(instant);
}

byte[] bytes = os.toByteArray();
try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes)) {
unpacker.unpackMapHeader();
unpacker.unpackString();
assertEquals(12, unpacker.unpackExtensionTypeHeader().getLength());
}

SingleInstant deserialized = objectMapper.readValue(bytes, SingleInstant.class);
assertEquals(instant, deserialized.instant);
}
}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.