2014-10-31 1 views
1

정확히 말하면 Jackson 2.2.3입니다.Jackson 2.2.x : 재귀 적 직렬화가 실패합니다. 이유가 무엇입니까?

역 직렬화 프로세스가 내가 역 직렬화 json으로 값, 클래스 변경의 종류에 따라하기 때문에 매우 복잡하다 :

  • 기본은, 추상 클래스는 JsonMergePatch이다;
  • JSON 값이 JSON 객체가 아닌 경우, 나는 NonObjectMergePatch으로 비 직렬화됩니다.
  • 그렇지 않으면 재귀 적으로 역 직렬화하여 ObjectMergePatch이됩니다.

    @JsonDeserialize(using = JsonMergePatchDeserializer.class) 
    public abstract class JsonMergePatch 
        implements JsonSerializable 
    { 
        public abstract JsonNode apply(final JsonNode input) 
         throws JsonPatchException; 
    } 
    

    NonObjectMergePatch :

    final class NonObjectMergePatch 
        extends JsonMergePatch 
    { 
        private final JsonNode node; 
    
        NonObjectMergePatch(@Nonnull final JsonNode node) 
        { 
         this.node = Preconditions.checkNotNull(node); 
        } 
    
        @Override 
        public JsonNode apply(final JsonNode input) 
         throws JsonPatchException 
        { 
         return null; // TODO! 
        } 
    
        @Override 
        public void serialize(final JsonGenerator jgen, 
         final SerializerProvider provider) 
         throws IOException, JsonProcessingException 
        { 
         jgen.writeTree(node); 
        } 
    
        @Override 
        public void serializeWithType(final JsonGenerator jgen, 
         final SerializerProvider provider, final TypeSerializer typeSer) 
         throws IOException, JsonProcessingException 
        { 
         serialize(jgen, provider); 
        } 
    } 
    

    ObjectMergePatch :

    final class ObjectMergePatch 
        extends JsonMergePatch 
    { 
        private final Set<String> removedMembers; 
        private final Map<String, JsonMergePatch> modifiedMembers; 
    
        ObjectMergePatch(final Set<String> removedMembers, 
         final Map<String, JsonMergePatch> modifiedMembers) 
        { 
         this.removedMembers = ImmutableSet.copyOf(removedMembers); 
         this.modifiedMembers = ImmutableMap.copyOf(modifiedMembers); 
        } 
    
        @Override 
        public JsonNode apply(final JsonNode input) 
         throws JsonPatchException 
        { 
         return null; 
        } 
    
        @Override 
        public void serialize(final JsonGenerator jgen, 
         final SerializerProvider provider) 
         throws IOException, JsonProcessingException 
        { 
         jgen.writeStartObject(); 
    
         /* 
         * Write removed members as JSON nulls 
         */ 
         for (final String member: removedMembers) 
          jgen.writeNullField(member); 
    
         /* 
         * Write modified members; delegate to serialization for writing values 
         */ 
         for (final Map.Entry<String, JsonMergePatch> entry: 
          modifiedMembers.entrySet()) { 
          jgen.writeFieldName(entry.getKey()); 
          entry.getValue().serialize(jgen, provider); 
         } 
    
         jgen.writeEndObject(); 
        } 
    
        @Override 
        public void serializeWithType(final JsonGenerator jgen, 
         final SerializerProvider provider, final TypeSerializer typeSer) 
         throws IOException, JsonProcessingException 
        { 
         serialize(jgen, provider); 
        } 
    } 
    

    마지막 JsonMergePatch 우선 여기서

코드 (수입 간략화 "생략) 인 , 주문 deserial izer :

final class JsonMergePatchDeserializer 
    extends JsonDeserializer<JsonMergePatch> 
{ 
    @Override 
    public JsonMergePatch deserialize(final JsonParser jp, 
     final DeserializationContext ctxt) 
     throws IOException, JsonProcessingException 
    { 
     /* FAILS HERE */ 
     final JsonNode node = jp.readValueAsTree(); 
     /* 
     * Not an object: the simple case 
     */ 
     if (!node.isObject()) 
      return new NonObjectMergePatch(node); 

     /* 
     * The complicated case... 
     * 
     * We have to build a set of removed members, plus a map of modified 
     * members. 
     */ 

     final Set<String> removedMembers = Sets.newHashSet(); 
     final Map<String, JsonMergePatch> modifiedMembers = Maps.newHashMap(); 
     final Iterator<Map.Entry<String, JsonNode>> iterator = node.fields(); 

     Map.Entry<String, JsonNode> entry; 

     while (iterator.hasNext()) { 
      entry = iterator.next(); 
      if (entry.getValue().isNull()) 
       removedMembers.add(entry.getKey()); 
      else { 
       final JsonMergePatch value 
        = deserialize(entry.getValue().traverse(), ctxt); 
       modifiedMembers.put(entry.getKey(), value); 
      }    
     } 

     return new ObjectMergePatch(removedMembers, modifiedMembers); 
    } 

    /* 
    * This method MUST be overriden... The default is to return null, which is 
    * not what we want. 
    */ 
    @Override 
    public JsonMergePatch getNullValue() 
    { 
     return new NonObjectMergePatch(NullNode.getInstance()); 
    } 
} 

역 직렬화 할 JSON이 객체가 아닌 한 제대로 작동하는 테스트를 코딩했습니다. 그것이 객체이면, I 재귀이 예외 (상기 /* FAILS HERE */ 표시)가 실패 대상 부재 값을 역 직렬화하는 deserialize() 메소드를 호출하지만 ... 파서로부터 값을 판독 :

java.lang.IllegalStateException: No ObjectCodec defined for the parser, can not deserialize JSON into JsonNode tree 
    at com.fasterxml.jackson.core.JsonParser.readValueAsTree(JsonParser.java:1352) 
    at com.github.fge.jsonpatch.rfc7386.JsonMergePatchDeserializer.deserialize(JsonMergePatchDeserializer.java:67) 
    at com.github.fge.jsonpatch.rfc7386.JsonMergePatchDeserializer.deserialize(JsonMergePatchDeserializer.java:92) 
    at com.github.fge.jsonpatch.rfc7386.JsonMergePatchDeserializer.deserialize(JsonMergePatchDeserializer.java:36) 
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888) 
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034) 
    at com.github.fge.jsonpatch.rfc7386.SerializationTest.objectSerDeserWorksCorrectly(SerializationTest.java:102) 

왜? 이 문제를 어떻게 해결할 수 있습니까?

답변

0

어휴, 인터넷 검색 때 a previous question of mine을 우연히 만나 대답을 생각해 냈습니다. 하지만 내 말은 못생긴 ...

예외로 언급하면 ​​JsonParser 인스턴스에는 연결된 ObjectCodec이없는 것이 문제입니다. 그래서 우리는 그것을 하나로 먹여야합니다.

// JacksonUtils is a class of mine; the method returns an ObjectMapper, 
// which extends ObjectCodec 
private static final ObjectCodec CODEC = JacksonUtils.newMapper(); 

.deserialize() 방법

, 내가 할 :이 자동으로 수행되지 않는 이유 여기서 문제는 사용자 정의 디시리얼라이저, 나는 같은 새로운 ObjectCodec 선언 ... 그래서

입니다

jp.setCodec(CODEC); 

입니다.

하지만보기 흉합니다. 그것은 빤다. 끔찍하다. 나는 더 나은 해결책을 원한다 :/

+0

추악 할 것이므로 이것은 필수적이지 않아야한다. 데이터 바인딩 코드는 버퍼 토큰을위한 임시 파서를 생성해야하는 경우'codec' 인스턴스를 전파해야합니다. 어딘가에 버그처럼 들립니다. 반대로 사용자 정의 디시리얼라이저가 버퍼링을 사용하면'TokenBuffer '에'JsonParser'를 전달해야합니다. – StaxMan

+0

흠, 그래서 2.2.3을 사용합니다. 나는 2.2.4를 아직 사용하지 않았다. – fge

+0

아. 잘 될 수도 있습니다 - 비슷한 문제가 그 이후로 수정되었습니다. 가능한 경우 및 필요한 경우 최대 2.4.3을 사용하려고합니다.문제가 지속되면 최신 버전이 수정되었는지 확인하십시오). 2.4.3에는 내가 생각할 수있는 모든 관련 픽스가있다. – StaxMan