2016-09-15 80 views
1

我试图用任意对象作为序列化/反序列化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" ] ]符号能够消耗该JSON在JavaScript中new Map(...)JSON.stringify(map)会产生过多的符号(见https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map)。为了澄清,这样的地图将是其他类的地域,例如,

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

我认为你是在复杂的。你的JSON不是地图。你为什么使用'Map'来表示它? 'Foo'和'Bar'有任何使它们不同的属性吗? –

+0

在实际使用情况下,'Foo'和'Bar'是复杂的对象,具有'Foo'作为键类型的映射可能是另一个对象的字段。我需要将这个Java地图移植到JavaScript中,JavaScript有它自己的'Map',它以这种形式序列化(请参阅问题中的MDN链接)。 –

+0

是的,它们可能是完全不同的对象(任何Java对象)。我已经更新了这个问题来说明问题。 –

回答

3

我想出了这个解决方案:

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; 

} 
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做转换,但使用不同的convension:地图JSON:{键:值1,键2:值2,...},所以JSON输出变为:

{ 
    { 
    "foo": "foo1" 
    }: { 
    "bar": "bar1" 
    }, 
    { 
    "foo": "foo2" 
    }: { 
    "bar": "bar2" 
    } 
} 

您可以检查出source code

+0

我问杰克逊和一个具体的输出,你提供了一个不同的工具和不同的输出。请检查:http:// stackoverflow。com/help/how-to-answer –

+0

没有正确的配置,jackson得到这个:{“[email protected]”:{“bar”:“bar1”},“ca.oson.json。 [email protected]“:{”bar“:”bar2“}} –

+0

ArrayToMapDeserializer不应该太难实现,当我有晚上的时间我会为你尝试一个 –