メモ。あとで書き足す(予定)。
問題
Realm Javaではjsonファイルを読み込んでそのままRealmのオブジェクトをすることができます。しかし、intやstringといったプリミティブ型配列の場合にはそのままダイレクトにRealmに格納することができません。
JSON APIは数値や文字列型のようなプリミティブ型(オブジェクト型ではない)の配列を含むことがあります。そのような配列を表現することは現時点のRealmではサポートされていません。
JSON APIを変更するのが不可能な場合、カスタムTypeAdapterを用いて、JSONのプリミティブ型をRealmオブジェクトに自動でマッピングするようにカスタマイズすることができます。
Realm Java 3.3.0
Realm JavaでnullableなInt配列のjsonファイルを読み込んでみました。対象となるフォーマットは、例えば下記のような場合です。
{ "contents": [ { "code": 1, "weapons": null, }, { "code": 9, "weapons": [26], } ], "updated": "2016-07-19T19:00:00+09:00" }
過去に似たような件でハマっていたことはあったのですが、フィールドがnot-nullableなこともあり"weapons": null
や"weapons": [26]
が入り混じることはありませんでした。
このファイルを読み込ませるとgsonに怒られ、例外が吐かれました。
W/System.err: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was NULL at line 1 column 126 path $[0].weapons W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:224) W/System.err: at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) W/System.err: at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) W/System.err: at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
解決
IntObject.java
public class IntObject extends RealmObject { private int value; public IntObject() { } public IntObject(int value) { this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } }
IntObjectTypeAdapter.java
配列として処理をし始める前にJsonToken.NULL
かどうか確かめる処理を追加しました。
public class IntObjectTypeAdapter extends TypeAdapter<RealmList<IntObject>> { @Override public void write(JsonWriter out, RealmList<IntObject> value) throws IOException { } @Override public RealmList<IntObject> read(JsonReader in) throws IOException { RealmList<IntObject> list = new RealmList<>(); if (in != null) { if (in.peek() == JsonToken.NULL) { in.nextNull(); return list; } in.beginArray(); while (in.hasNext()) { list.add(new IntObject(in.nextInt())); } in.endArray(); } return list; } }
Realmへのオブジェクトパース部分
final Type token = new TypeToken<RealmList<IntObject>>() { }.getType(); final Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { return f.getDeclaringClass().equals(RealmObject.class); } @Override public boolean shouldSkipClass(Class<?> clazz) { return false; } }).registerTypeAdapter(token, new IntObjectTypeAdapter()).create(); List<Weapon> objects = gson.fromJson(contents.toString(), new TypeToken<List<Weapon>>() { }.getType()); realm.copyToRealm(objects);