2017-10-19 31 views
1

我有一個嵌套Map<StructureNode, Map<String, String>>我需要一個自定義鍵序列化器&解串器(StructureNode包含對其他對象的引用,這些對象需要作爲此映射的鍵)。我用這個下面的方法:JSon - 嵌套地圖的自定義鍵序列化

Jackson Modules for Map Serialization

給出以下結果。自定義序列:

public class StructureNodeKeySerializer extends JsonSerializer<StructureNode> { 

    private static final ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public void serialize(StructureNode value, JsonGenerator gen, SerializerProvider serializers) throws IOException { 
     StringWriter writer = new StringWriter(); 
     mapper.writeValue(writer, value.copyUpwards()); 
     gen.writeFieldName(writer.toString()); 
    } 
} 

自定義解串器:

public class StructureNodeKeyDeserializer extends KeyDeserializer { 

    private static final ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException { 
     return mapper.readValue(key, StructureNode.class); 
    } 
} 

用法:

@JsonDeserialize(keyUsing = StructureNodeKeyDeserializer.class) @JsonSerialize(keyUsing = StructureNodeKeySerializer.class) 
private Map<StructureNode, String> structureIds; 
@JsonDeserialize(keyUsing = StructureNodeKeyDeserializer.class) @JsonSerialize(keyUsing = StructureNodeKeySerializer.class) 
private Map<StructureNode, Map<String, String>> metadata; 

這正確串行化一個Map<StructureNode, String>,但應用到嵌套Map<StructureNode, Map<String, String>>,它提供了以下錯誤:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: java.lang.String cannot be cast to structure.StructureNode 

Jackson似乎對「子地圖」使用相同的自定義序列化方法。有沒有一種很好的方法來解決這個問題,而不用另一個定製(非Map)對象替換「子地圖」?

+0

你不應該在你的序列化器和反序列化器中使用私有的'ObjectMapper'。 – teppic

+0

@teppic你爲什麼這麼說?我在我提到的另一篇文章中關注了這個例子,但很高興能夠改進它。但無論如何,這並不能解決我得到的例外。 – tb189

+0

因爲它與客戶端代碼正在使用的(並且可能已被檢測到)是分開的。 – teppic

回答

1

您可以

public static class Bean{ 
    @JsonSerialize(using = MapStructureNodeKeySerializer.class) 
    public Map<StructureNode, Map<String, String>> metadata; 
} 

解決這個問題並執行不同的串行一點點:

public static class MapStructureNodeKeySerializer 
     extends JsonSerializer<Map<StructureNode, Object>> { 

    private static final ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public void serialize(Map<StructureNode, Object> value, JsonGenerator gen, 
          SerializerProvider serializers) throws IOException { 
     gen.writeStartObject(); 

     for(Map.Entry<StructureNode, Object> val: value.entrySet()){ 
      // your custom serialization code here 
      StringWriter writer = new StringWriter(); 
      mapper.writeValue(writer, val.getKey().copyUpwards()); 

      gen.writeObjectField(writer.toString(), val.getValue()); 
     } 

     gen.writeEndObject(); 
    } 
} 

或者,如果你想保持keyUsing = StructureNodeKeySerializer.class

public static class Bean{ 
    @JsonSerialize(keyUsing = StructureNodeKeySerializer.class) 
    public Map<StructureNode, Map<String, String>> metadata; 
} 

你可以實現它就像:

public static class StructureNodeKeySerializer extends JsonSerializer { 

    private static final ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public void serialize(Object value, JsonGenerator gen, 
          SerializerProvider serializers) throws IOException { 

     if (value instanceof StructureNode){ // <= type of 1-st level Map key 
      // your custom serialization code here 
      StringWriter writer = new StringWriter(); 
      mapper.writeValue(writer, ((StructureNode)value).copyUpwards()); 
      gen.writeFieldName(writer.toString()); 
     }else if(value instanceof String){ // <= type of 2-nd level Map key 
      gen.writeFieldName((String) value); 
     } 
    } 
}