2017-09-13 3 views
3

json 필드가 null, 결석 또는 존재할 수있는 경우를 나타 내기 위해 POJO에서 Optional을 사용하려고합니다. 내 문제는 잭슨이 Optional.empty()null을 같은 것으로 취급하지 않도록 설정하는 방법을 이해할 수 없다는 것입니다. empty()의 경우 필드를 무시하고 싶습니다. JsonInclude 값 중 아무 것도이를 수행하지 않는 것입니다. Jdk8Module#configureAbsentsAsNulls()는 유망 해 보이지만 내 테스트 결과는 변경되지 않습니다. 이것을 할 수있는 방법이 있습니까?Jackson 선택적 필드 empty() vs null

TL; DR null 직렬화, Optional.empty() 직렬화되지 않아야한다.

다음은 내가 달성하려고하는 동작을 보여주는 몇 가지 테스트입니다.

class POJO { 
    public Optional<String> content; 
} 

private ObjectMapper getMapper() { 
    return new ObjectMapper().registerModule(new Jdk8Module()); 
} 

@org.junit.Test 
public void testAbsent() throws JsonProcessingException { 
    ObjectMapper mapper = getMapper(); 

    POJO pojo = new POJO(); 
    pojo.content = Optional.empty(); 

    String result = mapper.writeValueAsString(pojo); 

    assertEquals("{}", result); 
} 

@org.junit.Test 
public void testNull() throws JsonProcessingException { 
    ObjectMapper mapper = getMapper(); 

    POJO pojo = new POJO(); 
    pojo.content = null; 

    String result = mapper.writeValueAsString(pojo); 

    assertEquals("{\"content\":null}", result); 
} 

@org.junit.Test 
public void testPresent() throws JsonProcessingException { 
    ObjectMapper mapper = getMapper(); 

    POJO pojo = new POJO(); 
    pojo.content = Optional.of("Hello"); 

    String result = mapper.writeValueAsString(pojo); 

    assertEquals("{\"content\":\"Hello\"}", result); 
} 
+0

당신은 최소한의 예를 게시시겠습니까 테스트 케이스는 통과하지만 실패 할 것입니다 (예 : 매퍼 구성, 필드를 비우기, 직렬화, 출력 표시)? – chrylis

+0

몇 가지 테스트를 추가했습니다. 미안 그들은 거기에서 시작하지 않았다. – Panda

+0

원래 질문에서 (그리고 테스트에 표시된대로) null을 serialize해야하며 empty()는 안됩니다. 이것은 모듈의 기본 동작이 아닙니다. 이 질문은이 행동을 성취하는 방법에 대한 대답이 아닙니다. – Panda

답변

0

당신이 무시하거나 필드의 값을 기준으로 직렬화해야 필드를 지정하는 데 사용됩니다 @JsonInclude 주석 here에 대한 잭슨의 문서를 확인하면 매개 변수 (NON_ABSENTNON_EMPTY 몇이 있음을 볼 수있다)은 Optional.empty 값을 무시하는 데 사용할 수 있지만 null 값과 함께 사용되므로 사용자의 경우에는 작동하지 않습니다.

필드의 값을 확인하고 Optional.empty 인 경우이를 무시하기 위해 할 수있는 것은 JsonFilter입니다. 이 null 또는 Optional.empty 이외의 경우

PropertyFilter optionalFilter = new SimpleBeanPropertyFilter() { 

    @Override 
    public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception { 
     // get the field using the writer's name (field name) 
     Field field = pojo.getClass().getDeclaredField(writer.getFullName().toString()); 

     // get the value of the field, by making it accessible and then reverting 
     boolean defaultAccess = field.isAccessible(); 
     field.setAccessible(true); 
     Object value = field.get(pojo); 
     field.setAccessible(defaultAccess); 

     // serialize if null or it is not Optional.empty 
     if (value == null || value.equals(Optional.empty()) == false) { 
      writer.serializeAsField(pojo, jgen, provider); 
     } 
    } 
}; 

이 그것을 클래스의 각 필드를 확인하고 직렬화됩니다. 메인 클래스의

사용을 :

FilterProvider filters = new SimpleFilterProvider().addFilter("optionalFilter", optionalFilter); 

// note that you need the `Jdk8Module` module to get the value of the optional 
ObjectMapper mapper = new ObjectMapper().registerModule(new Jdk8Module()); 

POJO pojo = new POJO(); 
pojo.setContent(Optional.empty()); 

System.out.println(mapper.writer(filters).writeValueAsString(pojo)); 

pojo = new POJO(); 
pojo.setContent(null); 

System.out.println(mapper.writer(filters).writeValueAsString(pojo)); 

pojo = new POJO(); 
pojo.setContent(Optional.of("Hello")); 

System.out.println(mapper.writer(filters).writeValueAsString(pojo)); 

은 또한 필터 클래스에 주석을 가지고

@JsonFilter("optionalFilter") 
class POJO { 

} 

출력 :

{} 
{"content":null} 
{"content":"Hello"}