Skip to content

Commit 4112c0e

Browse files
committed
Add MessagePackExtensionType.TypeBasedDeserializer
1 parent a4b0f3f commit 4112c0e

File tree

4 files changed

+209
-43
lines changed

4 files changed

+209
-43
lines changed

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

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
package org.msgpack.jackson.dataformat;
22

33
import com.fasterxml.jackson.core.JsonGenerator;
4+
import com.fasterxml.jackson.core.JsonParser;
45
import com.fasterxml.jackson.core.JsonProcessingException;
6+
import com.fasterxml.jackson.core.type.TypeReference;
7+
import com.fasterxml.jackson.databind.DeserializationContext;
58
import com.fasterxml.jackson.databind.JsonSerializer;
9+
import com.fasterxml.jackson.databind.ObjectMapper;
610
import com.fasterxml.jackson.databind.SerializerProvider;
711
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
12+
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
813

914
import java.io.IOException;
1015
import java.util.Arrays;
16+
import java.util.Map;
17+
import java.util.concurrent.ConcurrentHashMap;
1118

1219
@JsonSerialize(using = MessagePackExtensionType.Serializer.class)
1320
public class MessagePackExtensionType
@@ -72,4 +79,83 @@ public void serialize(MessagePackExtensionType value, JsonGenerator gen, Seriali
7279
}
7380
}
7481
}
82+
83+
public interface Deser
84+
{
85+
Object deserialize(byte[] data)
86+
throws IOException;
87+
}
88+
89+
public static class TypeBasedDeserializer
90+
extends UntypedObjectDeserializer.Vanilla
91+
{
92+
private final ObjectMapper objectMapper;
93+
private Map<Byte, Deser> deserTable = new ConcurrentHashMap<Byte, Deser>();
94+
95+
public TypeBasedDeserializer()
96+
{
97+
MessagePackFactory messagePackFactory = new MessagePackFactory();
98+
messagePackFactory.setReuseResourceInParser(false);
99+
objectMapper = new ObjectMapper(messagePackFactory);
100+
}
101+
102+
public <T> void addTargetClass(byte type, final Class<T> klass)
103+
{
104+
deserTable.put(type, new Deser() {
105+
@Override
106+
public Object deserialize(byte[] data)
107+
throws IOException
108+
{
109+
return objectMapper.readValue(data, klass);
110+
}
111+
});
112+
}
113+
114+
public void addTargetTypeReference(byte type, final TypeReference typeReference)
115+
{
116+
deserTable.put(type, new Deser() {
117+
@Override
118+
public Object deserialize(byte[] data)
119+
throws IOException
120+
{
121+
return objectMapper.readValue(data, typeReference);
122+
}
123+
});
124+
}
125+
126+
public void addCustomDeser(byte type, final Deser deser)
127+
{
128+
deserTable.put(type, new Deser() {
129+
@Override
130+
public Object deserialize(byte[] data)
131+
throws IOException
132+
{
133+
return deser.deserialize(data);
134+
}
135+
});
136+
}
137+
138+
public void clearEntries()
139+
{
140+
deserTable.clear();
141+
}
142+
143+
@Override
144+
public Object deserialize(JsonParser p, DeserializationContext ctxt)
145+
throws IOException
146+
{
147+
Object obj = super.deserialize(p, ctxt);
148+
if (! (obj instanceof MessagePackExtensionType)) {
149+
return obj;
150+
}
151+
152+
MessagePackExtensionType ext = (MessagePackExtensionType) obj;
153+
Deser deser = deserTable.get(ext.getType());
154+
if (deser == null) {
155+
return obj;
156+
}
157+
158+
return deser.deserialize(ext.getData());
159+
}
160+
}
75161
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class MessagePackFactory
3838

3939
private final MessagePack.PackerConfig packerConfig;
4040
private boolean reuseResourceInGenerator = true;
41+
private boolean reuseResourceInParser = true;
4142

4243
public MessagePackFactory()
4344
{
@@ -54,6 +55,11 @@ public void setReuseResourceInGenerator(boolean reuseResourceInGenerator)
5455
this.reuseResourceInGenerator = reuseResourceInGenerator;
5556
}
5657

58+
public void setReuseResourceInParser(boolean reuseResourceInParser)
59+
{
60+
this.reuseResourceInParser = reuseResourceInParser;
61+
}
62+
5763
@Override
5864
public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc)
5965
throws IOException
@@ -95,7 +101,7 @@ public JsonParser createParser(InputStream in)
95101
protected MessagePackParser _createParser(InputStream in, IOContext ctxt)
96102
throws IOException
97103
{
98-
MessagePackParser parser = new MessagePackParser(ctxt, _parserFeatures, _objectCodec, in);
104+
MessagePackParser parser = new MessagePackParser(ctxt, _parserFeatures, _objectCodec, in, reuseResourceInParser);
99105
return parser;
100106
}
101107

@@ -106,7 +112,7 @@ protected JsonParser _createParser(byte[] data, int offset, int len, IOContext c
106112
if (offset != 0 || len != data.length) {
107113
data = Arrays.copyOfRange(data, offset, offset + len);
108114
}
109-
MessagePackParser parser = new MessagePackParser(ctxt, _parserFeatures, _objectCodec, data);
115+
MessagePackParser parser = new MessagePackParser(ctxt, _parserFeatures, _objectCodec, data, reuseResourceInParser);
110116
return parser;
111117
}
112118
}

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

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class MessagePackParser
4949
{
5050
private static final ThreadLocal<Tuple<Object, MessageUnpacker>> messageUnpackerHolder =
5151
new ThreadLocal<Tuple<Object, MessageUnpacker>>();
52+
private final MessageUnpacker messageUnpacker;
5253

5354
private static final BigInteger LONG_MIN = BigInteger.valueOf((long) Long.MIN_VALUE);
5455
private static final BigInteger LONG_MAX = BigInteger.valueOf((long) Long.MAX_VALUE);
@@ -74,6 +75,7 @@ private enum Type
7475
private String stringValue;
7576
private BigInteger biValue;
7677
private MessagePackExtensionType extensionTypeValue;
78+
private boolean reuseResourceInParser;
7779

7880
private abstract static class StackItem
7981
{
@@ -116,16 +118,43 @@ private static class StackItemForArray
116118
public MessagePackParser(IOContext ctxt, int features, ObjectCodec objectCodec, InputStream in)
117119
throws IOException
118120
{
119-
this(ctxt, features, new InputStreamBufferInput(in), objectCodec, in);
121+
this(ctxt, features, objectCodec, in, true);
122+
}
123+
124+
public MessagePackParser(
125+
IOContext ctxt,
126+
int features,
127+
ObjectCodec objectCodec,
128+
InputStream in,
129+
boolean reuseResourceInParser)
130+
throws IOException
131+
{
132+
this(ctxt, features, new InputStreamBufferInput(in), objectCodec, in, reuseResourceInParser);
120133
}
121134

122135
public MessagePackParser(IOContext ctxt, int features, ObjectCodec objectCodec, byte[] bytes)
123136
throws IOException
124137
{
125-
this(ctxt, features, new ArrayBufferInput(bytes), objectCodec, bytes);
138+
this(ctxt, features, objectCodec, bytes, true);
126139
}
127140

128-
private MessagePackParser(IOContext ctxt, int features, MessageBufferInput input, ObjectCodec objectCodec, Object src)
141+
public MessagePackParser(
142+
IOContext ctxt,
143+
int features,
144+
ObjectCodec objectCodec,
145+
byte[] bytes,
146+
boolean reuseResourceInParser)
147+
throws IOException
148+
{
149+
this(ctxt, features, new ArrayBufferInput(bytes), objectCodec, bytes, reuseResourceInParser);
150+
}
151+
152+
private MessagePackParser(IOContext ctxt,
153+
int features,
154+
MessageBufferInput input,
155+
ObjectCodec objectCodec,
156+
Object src,
157+
boolean reuseResourceInParser)
129158
throws IOException
130159
{
131160
super(features);
@@ -135,6 +164,14 @@ private MessagePackParser(IOContext ctxt, int features, MessageBufferInput input
135164
DupDetector dups = Feature.STRICT_DUPLICATE_DETECTION.enabledIn(features)
136165
? DupDetector.rootDetector(this) : null;
137166
parsingContext = JsonReadContext.createRootContext(dups);
167+
this.reuseResourceInParser = reuseResourceInParser;
168+
if (!reuseResourceInParser) {
169+
this.messageUnpacker = MessagePack.newDefaultUnpacker(input);
170+
return;
171+
}
172+
else {
173+
this.messageUnpacker = null;
174+
}
138175

139176
MessageUnpacker messageUnpacker;
140177
Tuple<Object, MessageUnpacker> messageUnpackerTuple = messageUnpackerHolder.get();
@@ -607,6 +644,10 @@ public String getCurrentName()
607644

608645
private MessageUnpacker getMessageUnpacker()
609646
{
647+
if (!reuseResourceInParser) {
648+
return this.messageUnpacker;
649+
}
650+
610651
Tuple<Object, MessageUnpacker> messageUnpackerTuple = messageUnpackerHolder.get();
611652
if (messageUnpackerTuple == null) {
612653
throw new IllegalStateException("messageUnpacker is null");

msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import com.fasterxml.jackson.databind.DeserializationFeature;
2424
import com.fasterxml.jackson.databind.KeyDeserializer;
2525
import com.fasterxml.jackson.databind.ObjectMapper;
26-
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
2726
import com.fasterxml.jackson.databind.module.SimpleModule;
2827
import org.junit.Test;
2928
import org.msgpack.core.MessagePack;
@@ -40,6 +39,7 @@
4039
import java.math.BigInteger;
4140
import java.util.ArrayList;
4241
import java.util.Arrays;
42+
import java.util.HashMap;
4343
import java.util.List;
4444
import java.util.Map;
4545

@@ -677,54 +677,87 @@ public Object deserializeKey(String key, DeserializationContext ctxt)
677677
assertEquals((Integer) 3, map.get(false));
678678
}
679679

680-
public static class MyExtTypeDeserializer extends UntypedObjectDeserializer.Vanilla
681-
{
682-
@Override
683-
public Object deserialize(JsonParser p, DeserializationContext ctxt)
684-
throws IOException
685-
{
686-
Object obj = super.deserialize(p, ctxt);
687-
if (obj instanceof MessagePackExtensionType) {
688-
MessagePackExtensionType ext = (MessagePackExtensionType) obj;
689-
if (ext.getType() == 31) {
690-
if (Arrays.equals(ext.getData(), new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE})) {
691-
return "Java";
692-
}
693-
return "Not Java";
694-
}
695-
}
696-
return obj;
697-
}
698-
}
699-
700680
@Test
701-
public void customDeserializationForExtType()
681+
public void typeBasedDeserialize()
702682
throws IOException
703683
{
704684
ByteArrayOutputStream out = new ByteArrayOutputStream();
705685
MessagePacker packer = MessagePack.newDefaultPacker(out);
706-
packer.packArrayHeader(4);
707-
packer.packString("foo bar");
708-
packer.packExtensionTypeHeader((byte) 31, 4);
709-
packer.addPayload(new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE});
710-
packer.packArrayHeader(1);
686+
packer.packArrayHeader(5);
687+
// 0: Integer
711688
packer.packInt(42);
712-
packer.packExtensionTypeHeader((byte) 32, 2);
713-
packer.addPayload(new byte[] {(byte) 0xAB, (byte) 0xCD});
689+
// 1: String
690+
packer.packString("foo bar");
691+
// 2: ExtensionType(class desr)
692+
{
693+
TinyPojo t0 = new TinyPojo();
694+
t0.t = "t0";
695+
TinyPojo t1 = new TinyPojo();
696+
t1.t = "t1";
697+
NestedListComplexPojo parent = new NestedListComplexPojo();
698+
parent.s = "parent";
699+
parent.foos = Arrays.asList(t0, t1);
700+
byte[] bytes = objectMapper.writeValueAsBytes(parent);
701+
packer.packExtensionTypeHeader((byte) 17, bytes.length);
702+
packer.addPayload(bytes);
703+
}
704+
// 3: ExtensionType(type reference deser)
705+
{
706+
Map<String, Integer> map = new HashMap<String, Integer>();
707+
map.put("one", 1);
708+
map.put("two", 2);
709+
byte[] bytes = objectMapper.writeValueAsBytes(map);
710+
packer.packExtensionTypeHeader((byte) 99, bytes.length);
711+
packer.addPayload(bytes);
712+
}
713+
// 4: ExtensionType(custom deser)
714+
{
715+
packer.packExtensionTypeHeader((byte) 31, 4);
716+
packer.addPayload(new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE});
717+
}
714718
packer.close();
715719

716720
ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
717-
SimpleModule module = new SimpleModule("MyModule").addDeserializer(Object.class, new MyExtTypeDeserializer());
721+
MessagePackExtensionType.TypeBasedDeserializer typeBasedDeserializer
722+
= new MessagePackExtensionType.TypeBasedDeserializer();
723+
typeBasedDeserializer.addTargetClass((byte) 17, NestedListComplexPojo.class);
724+
typeBasedDeserializer.addTargetTypeReference((byte) 99, new TypeReference<Map<String, Integer>>() {});
725+
typeBasedDeserializer.addCustomDeser((byte) 31, new MessagePackExtensionType.Deser() {
726+
@Override
727+
public Object deserialize(byte[] data)
728+
throws IOException
729+
{
730+
if (Arrays.equals(data, new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE})) {
731+
return "Java";
732+
}
733+
return "Not Java";
734+
}
735+
}
736+
);
737+
SimpleModule module = new SimpleModule("MyModule").addDeserializer(Object.class, typeBasedDeserializer);
718738
objectMapper.registerModule(module);
719739

720740
List<Object> values = objectMapper.readValue(new ByteArrayInputStream(out.toByteArray()), new TypeReference<List<Object>>() {});
721-
assertThat(values.size(), is(4));
722-
assertThat((String) values.get(0), is("foo bar"));
723-
assertThat((String) values.get(1), is("Java"));
724-
assertThat(values.get(2), is(instanceOf(List.class)));
725-
List<Object> nested = (List<Object>) values.get(2);
726-
assertThat(nested.size(), is(1));
727-
assertThat((Integer) nested.get(0), is(42));
728-
assertThat((MessagePackExtensionType) values.get(3), is(new MessagePackExtensionType((byte) 32, new byte[] {(byte) 0xAB, (byte) 0xCD})));
741+
assertThat(values.size(), is(5));
742+
assertThat((Integer) values.get(0), is(42));
743+
assertThat((String) values.get(1), is("foo bar"));
744+
{
745+
Object v = values.get(2);
746+
assertThat(v, is(instanceOf(NestedListComplexPojo.class)));
747+
NestedListComplexPojo pojo = (NestedListComplexPojo) v;
748+
assertThat(pojo.s, is("parent"));
749+
assertThat(pojo.foos.size(), is(2));
750+
assertThat(pojo.foos.get(0).t, is("t0"));
751+
assertThat(pojo.foos.get(1).t, is("t1"));
752+
}
753+
{
754+
Object v = values.get(3);
755+
assertThat(v, is(instanceOf(Map.class)));
756+
Map<String, Integer> map = (Map<String, Integer>) v;
757+
assertThat(map.size(), is(2));
758+
assertThat(map.get("one"), is(1));
759+
assertThat(map.get("two"), is(2));
760+
}
761+
assertThat((String) values.get(4), is("Java"));
729762
}
730763
}

0 commit comments

Comments
 (0)