はじめに
GSON という JSON プロセッサは、@Expose アノテーションが付けられたフィールドのみをシリアライズ・デシリアライズの対象とする機能を提供しています。一方、逆のことをおこなう機能、すなわち、何らかのアノテーションが付けられたフィールドのみをシリアライズ・デシリアライズの対象から外す機能は提供されていません。そこで、その機能を実装してみます。
デフォルト動作
まずは、特別なアノテーションを付けない場合の GSON のデフォルト動作を確認します。
テスト用のデータ構造として DataPlain クラスを用意します。このクラスには key と value というプライベートフィールドを持たせ、何もアノテーションを付けずにおきます。また、これらのフィールドに簡単に初期値を設定できるよう、それらの初期値を取るコンストラクタを用意しておきます。テスト用のデータ構造なので、getter や setter の実装は省略します。
public class DataPlain
{
private String key;
private String value;
DataPlain(String key, String value)
{
this.key = key;
this.value = value;
}
}
このデータ構造にデータをセットし、それを GSON を用いて JSON に変換して出力するテストプログラム TestPlain.java を書きます。
import com.google.gson.Gson;
public class TestPlain
{
public static void main(String[] args)
{
// key="plain", value="secret" のデータを用意する。
DataPlain data = new DataPlain("plain", "secret");
// デフォルト動作をおこなう GSON インスタンスを作成する。
Gson gson = new Gson();
// data の内容を JSON に変換して出力する。
// {"key":"plain","value":"secret"} と出力される。
System.out.println(gson.toJson(data));
}
}
このテストコードをコンパイル・実行すると、
java -cp gson.jar TestPlain.java
次の JSON が出力されます。プライベートフィールドの key と value が両方ともシリアライズされて出力されていることを確認できます。
{"key":"plain","value":"secret"}
Expose の動作
@Expose アノテーションの動作を確認するため、DataExpose クラスを用意し、key フィールドに @Expose アノテーションを付けます。
import com.google.gson.annotations.Expose;
public class DataExpose
{
@Expose private String key;
private String value;
DataExpose(String key, String value)
{
this.key = key;
this.value = value;
}
}
このデータ構造にデータをセットし、それを GSON を用いて JSON に変換して出力するテストプログラム TestExpose.java を書きます。@Expose アノテーション機能を有効にするため、Gson インスタンスを作成する際、GsonBuilder の excludeFieldsWithoutExposeAnnotation() メソッドを呼んでいる点に注目してください。
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class TestExpose
{
public static void main(String[] args)
{
// key="expose", value="secret" のデータを用意する。
DataExpose data = new DataExpose("expose", "secret");
// @Expose アノテーションが付いているフィールドのみを処理対象とする
// GSON インスタンスを作成する。
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
// data の内容を JSON に変換して出力する。
// {"key":"expose"} と出力される。
System.out.println(gson.toJson(data));
}
}
このプログラムを実行すると、
java -cp gson.jar TestExpose.java
次の JSON が出力されます。@Expose アノテーションが付けられている key フィールドは出力に含まれるものの、@Expose アノテーションが付けられていない value フィールドは出力に含まれていないことを確認できます。
{"key":"expose"}
Unexpose の実装
GSON には ExclusionStrategy というインターフェースが用意されています。このインタフェースを実装するクラスを GsonBuilder の次のメソッドに渡すことにより、シリアライズ・デシリアライズの対象から外すか否かのロジックを組み込むことができます。
setExclusionStrategies(ExclusionStrategy...)addDeserializationExclusionStrategy(ExclusionStrategy)addSerializationExclusionStrategy(ExclusionStrategy)
この ExlusionStrategy インターフェースを使い、機能を実装してみます。
まず、@Expose アノテーションと逆の機能を提供するアノテーションを @Uexpose と名付け、次のように実装します。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Unexpose
{
}
次に、「@Unexpose アノテーションが付いているフィールドをスキップする」というロジックを持つ ExlusionStrategy インターフェースの実装を UnexposeExclusionStrategy と名付け、次のように実装します。
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
public final class UnexposeExclusionStrategy implements ExclusionStrategy
{
public static final UnexposeExclusionStrategy INSTANCE = new UnexposeExclusionStrategy();
@Override
public boolean shouldSkipField(FieldAttributes field)
{
// Unexpose アノテーションが付けられたフィールドを無視する。
return field.getAnnotation(Unexpose.class) != null;
}
@Override
public boolean shouldSkipClass(Class<?> clazz)
{
return false;
}
}
Unexpose の動作
@Unexpose アノテーションの動作を確認するため、DataUnexpose クラスを用意し、value フィールドに @Unexpose アノテーションを付けます。
public class DataUnexpose
{
private String key;
@Unexpose private String value;
DataUnexpose(String key, String value)
{
this.key = key;
this.value = value;
}
}
このデータ構造にデータをセットし、それを GSON を用いて JSON に変換して出力するテストプログラム TestUnexpose.java を書きます。@Unexpose アノテーション機能を有効にするため、Gson インスタンスを作成する際、GsonBuilder の setExclusionStrategies メソッドに UnexposeExclusionStrategy のインスタンスを渡している点に注目してください。
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class TestUnexpose
{
public static void main(String[] args)
{
// key="unexpose", value="secret" のデータを用意する。
DataUnexpose data = new DataUnexpose("unexpose", "secret");
// @Unexpose アノテーションが付いているフィールドを処理対象外とする
// GSON インスタンスを作成する。
Gson gson = new GsonBuilder()
.setExclusionStrategies(UnexposeExclusionStrategy.INSTANCE)
.create();
// data の内容を JSON に変換して出力する。
// {"key":"unexpose"} と出力される。
System.out.println(gson.toJson(data));
}
}
このプログラムを実行すると、
java -cp gson.jar TestUnexpose.java
次の JSON が出力されます。@Unexpose アノテーションが付いていない key フィールドは出力に含まれるものの、@Unexpose アノテーションが付いている value フィールドは出力に含まれていないことを確認できます。
{"key":"unexpose"}
おわりに
多くの JSON プロセッサを使った経験から、個人的には GSON が一番使い勝手が良いと感じています。ただ、GSON は JSON Pointer (RFC 6901) や JSON Patch (RFC 6902) をサポートしていないので、これらを扱う際は他の JSON プロセッサを利用しています。
余談ですが、多重配列を処理できないという不具合 (Bug 389815) を始め、MOXy には散々苦しめられました。この MOXy、いまだに Eclipse Jersey のデフォルト JSON プロセッサなのかな...
Takahiko Kawasaki CLA 2016-04-16 11:33:20 EDT Comment 3
This bug is a deal breaker...