2017-03-01 1 views
4

경우는 null 전부는 아니지만 그들 중 일부 분야를 제외 : null가 아닌 경우에만GSON 직렬화하십시오 POJO를 감안할 때

class Person { 
    @Expose 
    String name; 
    @Expose 
    String phone; 
    @Expose 
    String fax; 
} 

나는 항상 직렬화 할 "전화"하지만, "팩스"를 원한다.

현재 : 그래서 전화 또는 팩스를 가진 사람 "존"을 부여

{ "name": "John", "phone": null, "fax": null } 

내가 필요한 것 :

@Expose (serialize_if_null = false) 

과도 : 같은 것이

{ "name": "John", "phone": null } 

있는가 값이 있으면 직렬화되기를 원하기 때문에 작동하지 않습니다.

ExclusionStrategy를 사용하면 필드를 정의 할 수 있지만 값을 가져 오는 방법을 찾지 못하는 것 같습니다. ExclusionStrategy를 사용

덕분에

답변

1

, 나는 필드를 정의 할 수 있습니다,하지만 난 값을 얻을 수있는 방법을 찾을 수 없습니다.

예, 현재 필드 값을 결정하는 방법을 제공하지 않습니다. 이 때문에 GSON ReflectiveTypeAdapterFactory가 내부적으로 어떻게 작동하는지입니다합니다 (BoundField.serializedfinal이며, 한 번만 해결) :

@Override public boolean writeField(Object value) throws IOException, IllegalAccessException { 
    if (!serialized) return false; 
    Object fieldValue = field.get(value); 
    return fieldValue != value; // avoid recursion for example for Throwable.cause 
} 
for (BoundField boundField : boundFields.values()) { 
    if (boundField.writeField(value)) { 
    out.name(boundField.name); 
    boundField.write(out, value); 
    } 
} 

이 문제는 변경할 수 없습니다,하지만 난 그것을 응용 프로그램 개체와를 분리하는 좋은 디자인 선택의 여지 믿고 자신의 개념을 혼용하지 않고 응용 프로그램 구성 요소를 느슨하게 결합하지 않으려면 직렬화 된 표현 (Data Transfer Object 패턴 참조)을 사용하십시오 (언젠가 Gson에서 마이그레이션하는 경우 해당 DTO 클래스에 대해서만 수정이 필요함). phone을 보존하고 fax 필드 값에 따라 fax을 폐기 : 당신이 다음 두 시나리오에 대해 별도의 DTO 클래스를 만들 수 있습니다, 응용 프로그램에 소개 DTO들을 갖는 미세 경우

. 당신이 그 자체를 분리 DTO 개념을 소개하고 싶지 않은 경우

final Gson gson = new GsonBuilder() 
     .serializeNulls() 
     .create(); 
final Person person = new Person(); 
person.name = "John"; 
final PersonDto personDto = person.fax == null 
     ? new PersonDto(person) 
     : new PersonDtoWithFax(person); 
System.out.println(gson.toJson(personDto)); 

, 당신은 아마 사용자 정의를 구현 할 수 있습니다 :이 경우

class PersonDto { 
    @Expose String name; 
    @Expose String phone; 
    PersonDto(final Person person) { 
     name = person.name; 
     phone = person.phone; 
    } 
} 
class PersonDtoWithFax extends PersonDto { 
    @Expose String fax; 
    PersonDtoWithFax(final Person person) { 
     super(person); 
     fax = person.fax; 
    } 
} 

는 직렬화 솔직하다 serializer는 구현이 다소 복잡하고 속성 이름이 하드 코딩되기 때문에 다소 오류가 발생하기 쉽습니다 (물론 좋은 테스트를 할 수도 있고 java.lang.reflect.Field 인스턴스에서 이름을 추출 할 수도 있습니다).

final class SpecialJsonSerializer<T> 
     implements JsonSerializer<T> { 

    private final Gson gson; // Unfortunately, Gson does not provide much from JsonSerialiationContext, so we have to get it ourselves 
    private final Iterable<String> excludeIfNull; 

    private SpecialJsonSerializer(final Gson gson, final Iterable<String> excludeIfNull) { 
     this.gson = gson; 
     this.excludeIfNull = excludeIfNull; 
    } 

    static <T> JsonSerializer<T> getSpecialJsonSerializer(final Gson gson, final Iterable<String> excludeIfNull) { 
     return new SpecialJsonSerializer<>(gson, excludeIfNull); 
    } 

    @Override 
    public JsonElement serialize(final T object, final Type type, final JsonSerializationContext context) { 
     // context.serialize(person, type) cannot work due to infinite recursive serialization 
     // therefore the backing Gson instance is used 
     final JsonObject jsonObject = gson.toJsonTree(object, type).getAsJsonObject(); 
     for (final String propertyName : excludeIfNull) { 
      final JsonElement property = jsonObject.get(propertyName); 
      if (property != null && property.isJsonNull()) { 
       jsonObject.remove(propertyName); 
      } 
     } 
     return jsonObject; 
    } 

} 

난 정말 모르겠어요,하지만 난 DTO들을 사용하는 대신 직렬화 목적으로 JSON 트리를 만드는 것은 (적어도 때문에 더 복잡 JsonElement 구조)보기의 메모리 소비 지점에서 약간 더 비쌀 수 있다는 생각 .

// Both Gson instances must have serializeNulls() 
final Gson gson = new GsonBuilder() 
     .serializeNulls() 
     .create(); 
final Gson gsonWrapper = new GsonBuilder() 
     .serializeNulls() 
     .registerTypeAdapter(Person.class, getSpecialJsonSerializer(gson, singletonList("fax"))) 
     .create(); 
final Person person = new Person(); 
person.name = "John"; 
System.out.println(gsonWrapper.toJson(person)); 

두 솔루션 출력 :

{ "이름": "존", "전화"널 (null)} upvoted

+0

. "Person"객체는 단순화 된 예일 뿐이므로 DTO 스타일 솔루션이 가장 깨끗한 방법이 아닐 수도 있습니다 ... 아마도 personbuilder(). withfax(). build() something ?? – sikidhart

+0

@sikidhart 글쎄, 달려있어, 나는 DTOs와 함께 오류가 쉽게 발생하지 않도록 할 것이다. 위의 트릭을 참고하십시오 : Gson은'toJson' 메소드를 호출 할 때 객체 실제 타입에 대해'PersonDto'와'PersonDtoWithFax'를 구별 할 수 있습니다. 언급 한 빌더 패턴은 DTO를 작성하는 또 다른 방법 일뿐입니다 (응답 단순화를 위해 생성자를 사용했습니다). 빌더를 사용하고 싶다면 모두 다 당신에게 달렸고,'withFax (...)'로 PersonDtoWithFaxBuilder' 인스턴스를 돌려 자신의 빌더를 쉽게 만들 수 있습니다. 그러나 빌더를 도입하는 것은 대개 다소 복잡합니다. 당신이 결정합니다. –