読者です 読者をやめる 読者になる 読者になる

PlayFramework 別のモデルと関連があるモデルにGsonのtoJsonが使えないとき

Gsonを使うとモデルをそのままJSON形式に変換したい時に、こんな形で一発変換できます。

Gson g = new Gson();
Person p = Person.findById(myId);
g.toJson(p); // {"name": "Taro Yamada", "birthday": "1920/06/30"}

ただ、Personが別のモデルとManyToOneとかOneToManyなど、何らかの関連があるときには「gson circular reference error」でJSON形式に変換できません。最初はモデルを一度Hashに変換してからJSON形式に変換していたのですが、なにか違うのかもしれないと思い、回避する方法を探してみたところ、Exposeアノテーションを使う方法と、ExclusionStrategyを実装する方法の2つ方法がありました。

@Exposeを使う方法
http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/annotations/Expose.html

モデルでJSON形式として含めたいプロパティだけにExposeアノテーションを付けます。
この場合はsecretだけtoJSONしても出てきません。

@Expose public String name;
@Expose public String address;
@OneToMany(mappedBy="person", cascade=CascadeType.ALL)
public List<Hoge> secrets;

モデルの設定が終わったらGsonBuilderでexcludeFieldsWithoutExposeAnnotationを使ってGsonインスタンスを生成します。

	Gson g = new GsonBuilder()
        .excludeFieldsWithoutExposeAnnotation()  
        .create();
	Person p = Person.findById(id);
	renderJSON(g.toJson(p));

うまくいったと思ったのですが、idが出力されないので使えません。。
いろいろごにょごにょした結果、最終的にもうひとつの方法を使いました。
http://stackoverflow.com/questions/4802887/gson-how-to-exclude-specific-fields-from-serialization-without-annotations

ExclusionStrategyを実装します。
さきほどと同じく他のモデルと関連があるsecretsを対象から外します。

package models;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

public class PersonExclusionStrategy implements ExclusionStrategy {

    public boolean shouldSkipClass(Class<?> arg0) {
        return false;
    }

    public boolean shouldSkipField(FieldAttributes f) {
        return (f.getDeclaringClass() == Person.class && f.getName().equals("secrets"));
    }

}

でGsonをインスタンス化するときにこのExclusionStrategyを使うように指定します。

	Gson g = new GsonBuilder()
	.setExclusionStrategies(new PersonExclusionStrategy())
       .create();
       Person p = Contact.findById(id);
	renderJSON(g.toJson(p));

無事に変換できました。

その他ソース:
http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/GsonBuilder.html#excludeFieldsWithoutExposeAnnotation()
https://sites.google.com/site/gson/gson-user-guide