2014-06-13 74 views
3

我正在使用傑克遜fasterxml解編JSON。在我的對象中有兩種屬性:輸入屬性和計算屬性。在輸入JSON中,我只獲得輸入值。自定義傑克遜unmarshalling行爲

計算值實際上取決於輸入值。在對象被引用之前,我必須填充這些值。所以我只是檢查是否有任何傑克遜提供的鉤子,以便我可以在那裏做我的計算。例如JAXB提供afterUnmarshal方法來定製拆封行爲:

void afterUnmarshal(Unmarshaller u, Object parent) 

但我找不到任何關於傑克遜定製的類似信息。 Jackson是否提供了這種框架來定製解組行爲?

回答

5

我寧願建議通過使用constructor creators來保持模型對象不變。也就是說,所有的JSON值都被傳遞給一個將初始化其他計算屬性的構造函數。

無論如何,如果你想在反序列化後自定義一個對象(無需爲每種類型寫一個反序列化器),你可以用最後調用一個新構造實例的特殊方法的方式。這是一個適用於所有實現特殊接口的類的示例(可以考慮使用註釋來標記後構造方法)。

public class JacksonPostConstruct { 

    public static interface PostConstructor { 
     void postConstruct(); 
    } 

    public static class Bean implements PostConstructor { 
     private final String field; 

     @JsonCreator 
     public Bean(@JsonProperty("field") String field) { 
      this.field = field; 
     } 

     public void postConstruct() { 
      System.out.println("Post construct: " + toString()); 
     } 

     @Override 
     public String toString() { 
      return "Bean{" + 
        "field='" + field + '\'' + 
        '}'; 
     } 
    } 

    private static class PostConstructDeserializer extends DelegatingDeserializer { 
     private final JsonDeserializer<?> deserializer; 

     public PostConstructDeserializer(JsonDeserializer<?> deserializer) { 
      super(deserializer); 
      this.deserializer = deserializer; 
     } 

     @Override 
     protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) { 
      return deserializer; 
     } 

     @Override 
     public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { 
      Object result = _delegatee.deserialize(jp, ctxt); 
      if (result instanceof PostConstructor) { 
       ((PostConstructor) result).postConstruct(); 
      } 
      return result; 
     } 
    } 

    public static void main(String[] args) throws IOException { 
     ObjectMapper mapper = new ObjectMapper(); 
     SimpleModule module = new SimpleModule(); 
     module.setDeserializerModifier(new BeanDeserializerModifier() { 
      @Override 
      public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, 
                  BeanDescription beanDesc, 
                  final JsonDeserializer<?> deserializer) { 
       return new PostConstructDeserializer(deserializer); 
      } 
     }); 
     mapper.registerModule(module); 
     String json = "{\"field\":\"value\"}"; 
     System.out.println(mapper.readValue(json, Bean.class)); 
    } 

} 

輸出:

Post construct: Bean{field='value'} 
Bean{field='value'} 
2

讓我們假設你的JSON看起來是這樣的:

{ 
    "input1" : "Input value", 
    "input2" : 3 
} 

而且你POJO類看起來是這樣的:

class Entity { 

    private String input1; 
    private int input2; 
    private String calculated1; 
    private long calculated2; 

    ... 
} 

在這種情況下,你可以寫一個自定義解串器爲您Entity類:

class EntityJsonDeserializer extends JsonDeserializer<Entity> { 

    @Override 
    public Entity deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, 
      JsonProcessingException { 
     InnerEntity innerEntity = jp.readValueAs(InnerEntity.class); 

     Entity entity = new Entity(); 
     entity.setInput1(innerEntity.input1); 
     entity.setInput2(innerEntity.input2); 
     entity.recalculate(); 

     return entity; 
    } 

    public static class InnerEntity { 
     public String input1; 
     public int input2; 
    } 
} 

在上面的類,你可以看到,Entityrecalculate方法。它可能看起來像這樣:

public void recalculate() { 
    calculated1 = input1 + input2; 
    calculated2 = input1.length() + input2; 
} 

您也可以將此邏輯移動到您的反序列化器類。現在

,你必須告訴您要使用自定義解串器Jackson

@JsonDeserialize(using = EntityJsonDeserializer.class) 
class Entity { 
... 
} 

下面的例子演示瞭如何使用這些類:

ObjectMapper mapper = new ObjectMapper(); 
System.out.println(mapper.readValue(json, Entity.class)); 

這個程序打印:

Entity [input1=Input value, input2=3, calculated1=Input value3, calculated2=14] 
+0

「InnerEntity」從哪裏來? –

+0

這是來自「EntityJsonDeserializer」的內部類,我們可以在其中反序列化輸入JSON。 –