は、私がフィールドを定義することができますが、私は値を取得する方法を見つけるように見えることはできません。
はい、現在のフィールド値を判断する方法はありません。これは、内部的に動作ReflectiveTypeAdapterFactory
方法Gson(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を有する微なら
。この場合
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;
}
}
直列化は単純明快です:
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));
あなたは、それ自体が分離さDTOの概念を導入したくない場合、あなたはおそらくカスタムを実装する場合がありますシリアライザは実装が多少複雑で、プロパティ名がハードコーディングされているために多少エラーが発生する可能性があります(もちろん、良いテストをしたり、名前を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さて、それは依存していますが、私はDTOを使ってエラーを起こしにくくします。このトリックに注意してください。Gsonは、 'toJson'メソッドを呼び出すときに、オブジェクトの実際の型に対して' PersonDto'と 'PersonDtoWithFax'を区別できます。あなたが言及したビルダーパターンはDTOを作成するもう一つの方法です(私は単純化のためにコンストラクタを使用しました)。もしあなたがビルダーを使いたいなら、それはあなた次第です。あなたはPersonDtoWithFaxBuilder'インスタンスを返す 'withFax(...)'を使って独自のビルダーを簡単に作ることができます。しかし、ビルダーを導入すると、通常はいくらか複雑になります。あなたが決める。 –