我尝试使用任意对象序列化/反序列化Map<?, ?>
作为Jackson版本2.8的密钥。 JSON对应应该是一对夫妇,即给定
public class Foo {
public String foo;
public Foo(String foo) {
this.foo = foo;
}
}
public class Bar {
public String bar;
public Bar(String bar) {
this.bar = bar;
}
}
然后
Map<Foo, Bar> map;
map.put(new Foo("foo1"), new Bar("bar1"));
map.put(new Foo("foo2"), new Bar("bar2"));
应该由此JSON
表示[
[ { "foo": "foo1" }, { "bar": "bar1" } ],
[ { "foo": "foo2" }, { "bar": "bar2" } ]
]
所以我把序列化器部分作为
public class MapToArraySerializer extends JsonSerializer<Map<?, ?>> {
@Override
public void serialize(Map<?, ?> value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeStartArray();
for (Map.Entry<?, ?> entry : value.entrySet()) {
gen.writeStartArray();
gen.writeObject(entry.getKey());
gen.writeObject(entry.getValue());
gen.writeEndArray();
}
gen.writeEndArray();
}
}
但我不知道如何编写JsonDeserializer
来完成反向工作。有什么建议吗?
注意:我需要[ [ "key1", "value1" ], [ "key2", "value2" ] ]
表示法才能在JavaScript new Map( ... )
中使用该JSON,而JSON.stringify(map)
也会产生该表示法(请参阅https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map)。< / p>
为了澄清,这样的地图将是其他类的字段,例如
public class Baz {
@JsonSerialize(using = MapToArraySerializer.class)
@JsonDeserialize(using = ArrayToMapDeserializer.class, keyAs = Foo.class, contentAs = Bar.class)
Map<Foo, Bar> map;
}
和ArrayToMapDeserializer extends JsonDeserializer<Map<?, ?>>
是我寻求帮助的地方。
答案 0 :(得分:4)
我提出了这个解决方案:
public class ArrayToMapDeserializer extends JsonDeserializer<SortedMap<Object, Object>>
implements ContextualDeserializer {
private Class<?> keyAs;
private Class<?> contentAs;
@Override
public Map<Object, Object> deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
return this.deserialize(p, ctxt, new HashMap<>());
}
@Override
public Map<Object, Object> deserialize(JsonParser p, DeserializationContext ctxt,
Map<Object, Object> intoValue) throws IOException, JsonProcessingException {
JsonNode node = p.readValueAsTree();
ObjectCodec codec = p.getCodec();
if (node.isArray()) {
node.forEach(entry -> {
try {
JsonNode keyNode = entry.get(0);
JsonNode valueNode = entry.get(1);
intoValue.put(keyNode.traverse(codec).readValueAs(this.keyAs),
valueNode.traverse(codec).readValueAs(this.contentAs));
} catch (NullPointerException | IOException e) {
// skip entry
}
});
}
return intoValue;
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
throws JsonMappingException {
JsonDeserialize jsonDeserialize = property.getAnnotation(JsonDeserialize.class);
this.keyAs = jsonDeserialize.keyAs();
this.contentAs = jsonDeserialize.contentAs();
return this;
}
}
可以这样使用:
public class Baz {
@JsonSerialize(using = MapToArraySerializer.class)
@JsonDeserialize(using = ArrayToMapDeserializer.class,
keyAs = Foo.class, contentAs = Bar.class)
Map<Foo, Bar> map;
}
答案 1 :(得分:0)
这是反序列化:
@Override
public Map<?, ?> deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
Map map = new LinkedHashMap();
ObjectCodec oc = p.getCodec();
JsonNode anode = oc.readTree(p);
for (int i = 0; i < anode.size(); i++) {
JsonNode node = anode.get(i);
map.put(node.get(0), node.get(1));
}
return map;
}
我在原始解决方案中添加了一些带有新Oson实现的测试用例,其中我使用oson进行转换,但是使用了不同的对象:映射到json:{key1:value1,key2:value2, ...},所以json输出变为:
{
{
"foo": "foo1"
}: {
"bar": "bar1"
},
{
"foo": "foo2"
}: {
"bar": "bar2"
}
}
您可以查看source code!