, 나는 필드를 정의 할 수 있습니다,하지만 난 값을 얻을 수있는 방법을 찾을 수 없습니다.
예, 현재 필드 값을 결정하는 방법을 제공하지 않습니다. 이 때문에 GSON ReflectiveTypeAdapterFactory
가 내부적으로 어떻게 작동하는지입니다합니다 (BoundField.serialized
는 final
이며, 한 번만 해결) :
@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
. "Person"객체는 단순화 된 예일 뿐이므로 DTO 스타일 솔루션이 가장 깨끗한 방법이 아닐 수도 있습니다 ... 아마도 personbuilder(). withfax(). build() something ?? – sikidhart
@sikidhart 글쎄, 달려있어, 나는 DTOs와 함께 오류가 쉽게 발생하지 않도록 할 것이다. 위의 트릭을 참고하십시오 : Gson은'toJson' 메소드를 호출 할 때 객체 실제 타입에 대해'PersonDto'와'PersonDtoWithFax'를 구별 할 수 있습니다. 언급 한 빌더 패턴은 DTO를 작성하는 또 다른 방법 일뿐입니다 (응답 단순화를 위해 생성자를 사용했습니다). 빌더를 사용하고 싶다면 모두 다 당신에게 달렸고,'withFax (...)'로 PersonDtoWithFaxBuilder' 인스턴스를 돌려 자신의 빌더를 쉽게 만들 수 있습니다. 그러나 빌더를 도입하는 것은 대개 다소 복잡합니다. 당신이 결정합니다. –