(2/7更新)
(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);
JSON文字列のモデルへの変換:
- M jsonToModel(String json);
- M jsonToModel(String json, int maxDepth);
- M[] jsonToModels(String json);
- M[] jsonToModels(String json, int maxDepth);
例えばTestModelというモデルに対してJSON変換機能を使用するコードは、次のようになります。
1 | TestModel m = new TestModel(); |
3 | String json = TestModelMeta.get().modelToJson(m); |
4 | System.out.println(json); |
5 | TestModel m2 = TestModelMeta.get().jsonToModel(json); |
6 | 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入出力のカスタマイズを行うことができます(後述)。 |
例えばプロパティを無視したり、エイリアスを設定したりする場合、以下のように記述します。
5 | private String ignoredValue; |
対応する値型
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引数で制限できます。
以下にコード例を示します。
4 | @Json (coder=Expanded. class ) |
5 | private ModelRef<TestModel> ref = new ModelRef<TestModel>(TestModel. class ); |
8 | TestModel m = new TestModel(); |
9 | TestModelMeta.get().modelToJson(m, 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の入出力をサポートするクラスの例を示します。
01 | class CustomCoder extends org.slim3.datastore.json.Default{ |
02 | public void encode(JsonWriter writer, Object value){ |
03 | if (value instanceof java.awt.Point){ |
04 | java.awt.Point pt = (java.awt.Point)value; |
06 | writer.writeValueProperty( "x" , pt.x); |
07 | writer.writeValueProperty( "y" , pt.y); |
10 | super .encode(writer, value); |
12 | public <T> T decode(JsonReader reader, T defaultValue, Class<T> clazz){ |
13 | if (java.awt.Point.isAssignableFrom(clazz)){ |
15 | int x = Integer.parseInt(reader.readProperty( "x" ); |
16 | int y = Integer.parseInt(reader.readProperty( "y" ); |
17 | return clazz.cast( new Point(x, y)); |
18 | } catch (NumberFormatException e){ |
java.awt.PointクラスのフィールドをJSON入出力の対象にするには、上記のCustomCoderをcoderパラメータに指定します。
09 | public void setKey(Key key){ |
13 | public Point getPoint(){ |
17 | public void setPoint(Point point){ |
21 | @Attribute (primariKey= true ) |
24 | @Attribute (persistent= false ) |
25 | @Json (coder=CustomCoder. class ) |
上記のように指定すると、java.awt.Point型のpointフィールドのJSON入出力がおこなえるようになります。
1 | TestModel m = new TestModel(); |
2 | m.setPoint( new Point( 10 , 20 )); |
3 | String json = TestModelMeta.get().modelToJson(m); |
4 | TestModel m2 = TestModelMeta.get().jsonToModel(json); |
5 | Assert.assertEquals(m.x, m2.x); |
6 | Assert.assertEquals(m.y, m2.y); |
0 件のコメント:
コメントを投稿