2017-06-13 51 views
0

我需要序列圖包含JSON列表和地圖。每個地圖實例都包含一個UUID字段。該圖可以包含具有相同UUID的多個Map實例。具有相同UUID的地圖被認爲是相同的。- 傑克遜如何更換序列化映射

在序列化,我想更換已先前已係列化僅他們的UUID地圖實例。

什麼是實現與傑克遜最好的方法是什麼?

謝謝

回答

0

您可以實現圖形類的自定義序列化程序。

必須擴展StdSerializer並覆蓋

@Override 
public void serialize(T value, JsonGenerator jgen, SerializerProvider provider) 
    throws IOException, JsonProcessingException 

你這麼做的時候,你需要讓傑克遜知道您的序列化。您可以通過使用@JsonSerialize(using = CustomSerializer.class)註釋您的圖表類來實現該目的,或者您可以註冊包含自定義序列化程序的新模塊。

0

下面是我想出了一個可行的解決方案。

然而,有一個更優雅的方式來獲得頂級連載電話(這是需要重新初始化的自定義序列化)一個生命週期掛鉤?

而且,我不相信,保持每個線程訪問對象,使用ThreadLocal的軌道,是最好的解決方案。任何建議?

感謝

public class IdentifiableSerializerTest { 

    public static void main(String[] args) throws JsonProcessingException { 
     ObjectMapper mapper = createObjectMapper(); 
     test(mapper); 
    } 

    interface Identifiable { 
     Long getId(); 
    } 

    public static ObjectMapper createObjectMapper() { 
     ObjectMapper mapper = new ObjectMapper(); 

     // disable quoting - for testing purpose 
     mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false); 
     mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 

     // register serializer for Identifiable type 
     SimpleModule module = new SimpleModule(); 
     module.addSerializer(Identifiable.class, new IdentifiableSerializer(mapper.writer())); 
     mapper.registerModule(module); 

     // lifecycle hook to re-init IdentifiableSerializer on root-level serialize calls 
     mapper.setSerializerProvider(new IdentifiableSerializerProvider()); 

     return mapper; 
    } 

    /** 
    * This class serves to intercept root-level serialize calls in order to 
    * clean the map of visited objects, see {@link IdentifiableSerializer#visited}. 
    * 
    * TODO: this seems lot of code just to get a hook on root-level serialize calls... 
    */ 
    public static class IdentifiableSerializerProvider extends DefaultSerializerProvider { 

     public IdentifiableSerializerProvider() { super(); } 

     protected IdentifiableSerializerProvider(SerializerProvider src, SerializationConfig config, SerializerFactory f) { 
      super(src, config, f); 
     } 

     @Override 
     public DefaultSerializerProvider createInstance(SerializationConfig config, SerializerFactory f) { 
      return new IdentifiableSerializerProvider(this, config, f); 
     } 

     @Override 
     public void serializeValue(JsonGenerator gen, Object value) throws IOException { 
      IdentifiableSerializer.reset(); 
      super.serializeValue(gen, value); 
     } 
    } 

    public static class IdentifiableSerializer extends JsonSerializer<Identifiable> { 

     private static ThreadLocal<Set> visited = new ThreadLocal<Set>() { 
      @Override 
      protected Set initialValue() { 
       return new HashSet(); 
      } 
     }; 

     public static void reset() { 
      visited.get().clear(); 
     } 

     private final ObjectWriter delegate; 

     public IdentifiableSerializer(ObjectWriter delegate) { 
      this.delegate = delegate; 
     } 

     @Override 
     public void serialize(Identifiable value, JsonGenerator jgen, SerializerProvider provider) throws IOException { 
      Long id = value.getId(); 
      Set seen = visited.get(); 
      if (seen.contains(id)) { 
       jgen.writeStartObject(); 
       jgen.writeNumberField("@REF", id); 
       jgen.writeEndObject(); 
      } 
      else { 
       seen.add(id); 
       delegate.writeValue(jgen, value); 
      } 
     } 
    } 

    static class IdentifiableMap extends HashMap implements Identifiable { 

     static long counter = 0; 

     Long id = counter++; 
     { 
      put("@ID", id); 
     } 

     @Override 
     public Long getId() { 
      return id; 
     } 
    } 


    public static void test(ObjectMapper mapper) throws JsonProcessingException { 
     Map myMap = new IdentifiableMap() {{ 
      put("key1", 1); 
      put("key2", 2); 
      put("key3", 3); 
     }}; 
     List<Map> myList = Arrays.asList(myMap, myMap); 

     String expected = "[{key1:1,key2:2,key3:3,@ID:0},{@REF:0}]"; 
     String actual = mapper.writeValueAsString(myList); 

     Assert.assertEquals(expected, actual); 
     System.out.println("SUCCESS"); 
    } 

}