2017-09-25 2 views
0

JsonArray를 부울 값으로 비 직렬화해야합니다. 배열이 존재하고 비어 있지 않으면 값을 "true"로 설정해야합니다. 문제는 내 사용자 지정 디시리얼라이저가 기능을 수행하는 동안 나머지 필드의 비 직렬화를 깨뜨리는 것입니다. 즉, 이들은 null로 설정됩니다.잭슨 사용자 지정 디시리얼라이저가 다른 필드의 비 직렬화를 중단 함

대상 :

private static class TestObject { 
    private String name; 

    @JsonProperty("arr") 
    @JsonDeserialize(using = Deserializer.class) 
    private Boolean exists = null; 

    private Integer logins; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public Boolean getExists() { 
     return exists; 
    } 

    public void setExists(boolean exists) { 
     this.exists = exists; 
    } 

    public Integer getLogins() { 
     return logins; 
    } 

    public void setLogins(Integer logins) { 
     this.logins = logins; 
    } 

    @Override 
    public String toString() { 
     return "TestObject{" + 
       "name='" + name + '\'' + 
       ", exists=" + exists + 
       ", logins=" + logins + 
       '}'; 
    } 
} 

디시리얼라이저 :

public class Deserializer extends JsonDeserializer<Boolean> { 
    @Override 
    public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException { 
     if (jp.getCurrentToken() == JsonToken.START_ARRAY) { 
      return true; 
     } 
     return false; 
    } 
} 

테스트

@Test 
public void test() throws JsonParseException, IOException { 
    Boolean result = deserialize(); 
} 

private Boolean deserialize() throws IOException, JsonParseException, 
     JsonProcessingException { 
    TestObject testObject = mapper.readValue("{\n" + 
        " \"arr\": [\n" + 
        "  {\"value\": \"New\"}\n" + 
        " ],\n" + 
        " \"name\": \"name\",\n" + 
        " \"logins\": 36" + 
        "}", 
        TestObject.class); 

    System.out.println(testObject.toString()); 

    return testObject.getExists(); 
} 

나는 "도착"배열을 제거하거나 JSON, 하단 모두의 벌금을 이동하는 경우 . 내가 상단에두면 - TestObject{name='null', exists=true, logins=null}.

비슷한 질문 (Jackson Custom Deserializer breaks default ones)이 있었지만 불행히도 대답이 없습니다. Json을 재정렬 할 때 코드가 제대로 작동하므로 사용자 지정 deserializer가 모든 필드에 사용되는 것처럼 보이지 않습니다. Jackson은 사용자 지정 디시리얼라이저를 실행할 때 deserialization을 중지합니다.

+1

내 제안은 배열을 부울로 역 직렬화하지 않는 것입니다. 배열을 배열 /리스트/집합으로 비 직렬화하고'getExists'가'arr! = null' 또는 일부를 반환하도록하십시오. – Paul

+0

@ 폴 이것은 실제로 작동합니다. 아이디어 덕분에, 어떻게 든 생각하지 않았습니다. 문제는 그것이 약간 못 생기고 가려 보이지만 다른 방법이 없다면 그렇게 할 것입니다. –

+0

때로는 두 가지 추악한 솔루션으로 더 예쁘게 선택해야합니다 :) 제가 도와 드릴 수있어서 기쁩니다 ... 제 대답에 답을 할 것입니다. – Paul

답변

1

파서에서 읽기 표시를 계속 가져와야합니다.

@Override 
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException { 
    JsonNode node = jp.getCodec().readTree(jp); 
    return node.size() != 0; 
} 

컬렉션의 크기에 아닌 수집의 존재에서에 결정 :

당신은 컬렉션의 크기에 따라 한 번에 arr의 값을 읽고 결정할 수 문자열화 된 객체에 arr이 포함되거나 Deserializer.deserialize()이 실행되지 않기 때문에 모두 필요합니다. 이 경우 exist 속성은 null입니다. 따라서 을 표현할 수있는 유일한 의미는 존재하지 않습니다.은 빈 모음입니다.

필자는 호기심에 따라 파서를 추적하기 위해 두 번째로 더 명확한 방법을 시도했다. 실제 사용을 위해서는 위의 버전이 좋습니다.그것을 할 수있는 세 번째 방법은 실제로있다

@Override 
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException { 
    if (jp.currentToken() == JsonToken.START_ARRAY) { 
     jp.nextToken(); 
     int recursionLevel = 1; 
     while(recursionLevel > 0) { 
      switch (jp.currentToken()) { 
       case START_ARRAY: 
        // just in case of nested arrays 
        recursionLevel++; 
        break; 
       case END_ARRAY: 
        recursionLevel--; 
        break; 
      } 
      jp.nextToken(); 
     } 
     return true; 
    } 
    return false; 
} 
+0

이것은 적절한 해결책입니다. 'JsonDeserializer' javadoc에서는, 디시리얼라이저에서 돌아 오기 전에 읽기 마크를 다음 요소로 이동 시켜서 Jackson이 다음 요소에서 작업을 시작할 수 있다고 언급했습니다. 제 경우에는 배열이기 때문에 한번 시도한 것처럼 충분히 움직이지 않았습니다. 결국 END_ARRAY에 도달하기까지 여러 번 이동해야합니다. 'readTree'는 javadoc에서 알 수있는 한 전체 배열을 읽고 트리를 만들고 읽기 마커를 하나의 패키지로 전진시킵니다. –

1

내 제안은 배열을 부울로 역 직렬화하지 않는 것입니다. 배열을 배열 /리스트/집합으로 비 직렬화하고 getExists을 반환하려면 arr != null 또는 그와 같은 것이 필요합니다. 예를 들어

의 JSON 경우는 다음과 같습니다 직렬화 복원하고 있습니다 :

{ 
    "arr": [{"value": "New"}], 
    "name": "name", 
    "logins": 36 
} 

은 다음과 같이 당신의 실체를 쓰기 :

귀하의 디시리얼라이저는 배열의 내용에 관심이있을 수 없습니다
private static class TestObject 
{ 
    private List<Map<String, String>> arr; 

    // other getters/setters removed for brevity 

    public boolean getExists() 
    { 
    return arr !=null && !arr.isEmpty(); 
    } 
} 
0

, 그건 내 경우에 맞는 - JsonArray는 항상 그래서 내가 필요한 모든 true을 반환 한 후 제대로 읽기 마커를 전진하는 것입니다, 실종 아니에요 적어도 하나 개의 요소를 포함합니다 : 당신은 몇 가지 추가 작업을 위해 배열의 내용을 필요로하지 않는 한

if (jp.getCurrentToken().equals(JsonToken.START_ARRAY)) { 
    while (!jp.getCurrentToken().equals(JsonToken.END_ARRAY)){ 
     jp.nextToken(); 
    } 
} 
return true; 

, 그냥 마커를 이동하는 몇 밀리 초 빠른 readTree보다.