(2/26更新)
(12/22更新 @Jsonはフィールド直接指定になりました)
Slim3 JSON機能のドキュメントを書き始めました。まだ非公式なものですが、ひと通り書き終わったら公式へのマージを提案する予定です。でも、公式は英語なんですよね。どうしたものか。まぁ、いきなり下手な英語で書くより、まずは日本語でちゃんと書いたほうが良いはず。
というわけで、下記ドキュメントの草案です。若干改行が変ですが、evernoteに書きなぐってexportしたものを貼っつけてるためだと思います。これにあとJSON入出力のカスタマイズ方法を書いて一段落とする予定です。(書きました!)
概要
Slim3のJSON機能は、モデル(@org.slim3.datastore.Modelアノテーションが付加されたクラス)のJSON変換機能を提供します。JSON変換は、org.slim3.datastore.ModelMeta<M>に定義される以下のメソッドを呼び出すことにより行われます。
モデルのJSON文字列への変換:
- String modelToJson(Object model);
- String modelToJson(Object model, int maxDepth);
- String modelsToJson(Object[] models);
- String modelsToJson(Object[] models, int maxDepth);
- M jsonToModel(String json);
- M jsonToModel(String json, int maxDepth);
- M[] jsonToModels(String json);
- M[] jsonToModels(String json, int maxDepth);
例えばTestModelというモデルに対してJSON変換機能を使用するコードは、次のようになります。
TestModel m = new TestModel(); m.setValue(1); String json = TestModelMeta.get().modelToJson(m); System.out.println(json); // {"value": 1} TestModel m2 = TestModelMeta.get().jsonToModel(json); Assert.assertEquals(m.getValue(), m2.getValue());
JSON変換の制御
フィールドにJSONアノテーション(@org.slim3.datastore.json.JSON)を指定することで、JSON変換の振る舞いを変更できます。以下にJSONアノテーションで指定できるパラメータを示します。
パラメータ名 | 型 | デフォルト | 説明 |
ignore | boolean | false | このアトリビュートを無視します。JSON出力に含まれず、JSON入力時にも読み込まれません。 |
ignoreNull | boolean | true | アトリビュートがnullの場合、何も出力しません。falseの場合は、"null"が出力されます。 |
alias | String | 空文字列 | アトリビュートのJSON文字列内での名前を指定します。 |
coder | Class<? extends JsonCoder> | Default.class | JSON入出力を行うJsonCoderのクラスを指定します。ここに独自のクラスを指定することで、JSON入出力のカスタマイズを行うことができます(後述)。 |
例えばプロパティを無視したり、エイリアスを設定したりする場合、以下のように記述します。
@Model class TestModel{ ... @Json(ignore=true) private String ignoredValue; @Json(alise="foo") private String bar; }
対応する値型
Slim3のJSON変換機能は、以下の値型に対応します。また、後述するカスタマイズを行えば、これ以外の型に対応したり、入出力方法を変更する事ができます。
Javaクラス | JSON表現 | 例 |
java.lang.String, com.google.appengine.api.datastore.Text | 文字列。cipher=trueの場合、JSON内では暗号化されます。 | "text":"hello" |
byte[], com.google.appengine.api.datastore.ShortBlob, com.google.appengine.api.datastore.Blob | バイト列のBase64文字列。 | "blob":"mMB4qZAgtBKJq0d1LBGTCA==" |
boolean, java.lang.Boolean | ブール値(true or false)。 | "value":true |
short, java.lang.Short, int, java.lang.Integer, long, java.lang.Long | 整数。 | "value":100 |
float, java.lang.Float, double, java.lang.Double | 小数。 | "value":1.0 |
java.util.Date | 整数(Date.getTime()が返す値)。 | "value":10233400 |
java.lang.Enum | 文字列(Enum.name()が返す値)。 | "value":"MONDAY" |
com.google.appengine.api.users.User | ネストしたJSON文字列(User.getEmail()等の値をJSONエンコード)。 | "user":{"authDomain":"authDomain","email":"user@test.com"} |
com.google.appengine.api.datastore.Key | 文字列(KeyFactory.keyToString(Key)の実行結果)。 | "key":"aglzbGltMy1nZW5yCwsSBHRlc3QY6AcM" |
com.google.appengine.api.datastore.Category | 文字列(Category.getCategory()の値)。 | "category":"partOfSpeech" |
com.google.appengine.api.datastore.Email | 文字列(Email.getEmail()の値)。 | "mail":"user@domain.tld" |
com.google.appengine.api.datastore.GeoPt | ネストしたJSON文字列(GeoPt.getLatitude()及びGeoPt.getLongitude()の値をJSONエンコード)。 | "geopt":{"latitude":10.0,"longitude":10.0} |
com.google.appengine.api.datastore.IMHandle | ネストしたJSON文字列(IMHandle.getAddress()及びIMHandle.getProtocol()の値をJSONエンコード)。 | "handle":{"address":"handle","protocol":"xmpp"} |
com.google.appengine.api.datastore.Link | 文字列(Link.getValue()の値)。 | "link":"linkValue" |
com.google.appengine.api.datastore.PhoneNumber | 文字列(PhoneNumber.getNumber()の値)。 | "phone":"000-000-000" |
com.google.appengine.api.datastore.PostalAddress | 文字列(PostalAddress.getAddress()の値)。 | "address":"Tokyo, Japan" |
com.google.appengine.api.datastore.Rating | 整数(Rating.getRating()の値)。 | "rating":100 |
com.google.appengine.api.blobstore.BlobKey | 文字列(BlobKey.getKeyString()の値)。 | "blobkey":"Q3PqkweYlb4iWpp0BVw" |
org.slim3.datastore.ModelRef<M> | 文字列(モデルのkeyに対してKeyFactory.keyToString(key)した結果)。 | "ref":{"key":"lskfo2ijalefkwejfwlke",value:100} |
また上記サポートする型のコレクションにも対応しています。対応するコレクションクラスはjava.util.List, java.util.Set, java.util.SortedSetで、JSON文字列からモデルを作成する際は、それぞれjava.util.ArrayList、java.util.HashSet、java.util.TreeSetをnewして要素を追加したものがセットされます。
ModelRef<M>の展開
デフォルトではJSONアノテーションのcoderパラメータにorg.slim3.datastore.json.Defaultが指定されたものとして扱われ、このクラスは、ModelRefを参照先のモデルのキーに変換します。参照先のモデルの内容を展開したい場合、org.slim3.datastore.json.Expandedを指定して下さい。このクラスは、参照先のモデルの内容を展開し、そのモデルがさらにModelRefを持っている場合も展開します。展開のネストの深さは、modelToJsonメソッドやjsonToModelメソッドの、maxDepth引数で制限できます。
以下にコード例を示します。
@Model class TestModel{ ... @Json(coder=Expanded.class) private ModelRef<TestModel> ref = new ModelRef<TestModel>(TestModel.class); } ... TestModel m = new TestModel(); TestModelMeta.get().modelToJson(m, 3); // 3階層まで展開
JSON入出力のカスタマイズ
JSONアノテーションのcoderパラメータにJSON入出力を行うクラスを指定することにより、JSON変換の振る舞いを変更することができます。デフォルトではorg.slim3.datastore.json.Defaultが指定されており、slim3が対応するデータ型のJSON入出力が行われます。slim3ではもう一つ、org.slim3.datastore.json.Expandedが用意されていて、これをModelRef<M>型のフィールドに対して使用すると、ModelRef<M>が参照しているオブジェクトも展開します。
slim3が対応していないデータ型を使う場合や入出力方法を変更したい場合は、org.slim3.datastore.json.Defaultから継承したクラスを作成し、encode/decodeメソッドをオーバーライドして下さい。
下記にjava.awt.Pointの入出力をサポートするクラスの例を示します。
class CustomCoder extends org.slim3.datastore.json.Default{ public void encode(JsonWriter writer, Object value){ if(value instanceof java.awt.Point){ java.awt.Point pt = (java.awt.Point)value; writer.beginObject(); writer.writeValueProperty("x", pt.x); writer.writeValueProperty("y", pt.y); writer.endObject(); } else{ super.encode(writer, value); } public <T> T decode(JsonReader reader, T defaultValue, Class<T> clazz){ if(java.awt.Point.isAssignableFrom(clazz)){ try{ int x = Integer.parseInt(reader.readProperty("x"); int y = Integer.parseInt(reader.readProperty("y"); return clazz.cast(new Point(x, y)); } catch(NumberFormatException e){ } } return defaultValue; } }
java.awt.PointクラスのフィールドをJSON入出力の対象にするには、上記のCustomCoderをcoderパラメータに指定します。
import java.awt.Point; @Model class TestModel{ public Key getKey(){ return key; } public void setKey(Key key){ this.key = key; } public Point getPoint(){ return point; } public void setPoint(Point point){ this.point = point; } @Attribute(primariKey=true) private Key key; @Attribute(persistent=false) @Json(coder=CustomCoder.class) private Point point; }
上記のように指定すると、java.awt.Point型のpointフィールドのJSON入出力がおこなえるようになります。
TestModel m = new TestModel(); m.setPoint(new Point(10, 20)); String json = TestModelMeta.get().modelToJson(m); // {"point":{"x":10,"y":20}} TestModel m2 = TestModelMeta.get().jsonToModel(json); Assert.assertEquals(m.x, m2.x); Assert.assertEquals(m.y, m2.y);
0 件のコメント:
コメントを投稿