2014-06-13 3 views
3

JSON 비 정렬에 Jackson fasterxml을 사용하고 있습니다. 내 개체에는 두 가지 속성이 있습니다. 입력 속성과 계산 속성. 입력 JSON에서는 입력 값만 가져옵니다.잭슨 비 정렬 동작 사용자 정의

계산 된 값은 실제로 입력 값에 따라 다릅니다. 개체가 참조되기 전에이 값을 채워야합니다. 그래서 잭슨이 제공하는 후크가 있는지 확인하여 거기서 계산을 할 수 있습니다. 예를 들어, JAXB는 비 정렬 동작을 사용자 정의 할 수의 afterUnmarshal 방법 제공 :

void afterUnmarshal(Unmarshaller u, Object parent) 

을하지만 잭슨 사용자 정의에 대한 유사한 정보를 찾을 수 없습니다. 언 마샬링 동작을 사용자 정의하기 위해 Jackson이 제공 한 프레임 워크 훅이 있습니까?

답변

5

constructor creators을 사용하여 모델 개체를 불변으로 유지하는 것이 좋습니다. 즉, 모든 JSON 값은 다른 계산 된 속성을 초기화하는 생성자로 전달됩니다.

어쨌든 모든 형식에 대해 디시리얼라이저를 쓰지 않고 비 직렬화 후에 개체를 사용자 지정하려는 경우 modify the deserializer을 새로 작성한 인스턴스의 특수한 메서드를 호출하는 방식으로 호출 할 수 있습니다. 다음은 특수 인터페이스를 구현하는 모든 클래스에서 작동하는 예제입니다 (주석을 사용하여 post 생성 방법을 표시 할 수 있음).

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 클래스에 대한 사용자 지정 디시리얼라이저를 작성할 수 있습니다 위의 클래스에서 당신은 Entityrecalculate 방법을 가지고 있음을 알 수

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; 
    } 
} 

.

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

이 논리를 deserializer 클래스로 이동할 수도 있습니다.

지금, 당신은 당신이 당신의 사용자 정의 디시리얼라이저를 사용하려면 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

이것은 "JSON 입력"을 역 직렬화 할 수있는 "EntityJsonDeserializer"의 내부 클래스입니다. –