私はjsonでレトロフィットを使用して、jsonをレルムオブジェクトにデシリアライズします。これはほとんどの部分で非常にうまく機能します。対処する際に問題が発生する
RealmList(String(またはその他の基本的なデータ型))
EはRealmオブジェクトを拡張しないRealmListをRealmがサポートしないため、文字列をRealmObjectにラップしました。
public class RealmString extends RealmObject {
private String val;
public String getValue() {
return val;
}
public void setValue(String value) {
this.val = value;
}
}
私のレルムオブジェクトは次のとおりです
public class RealmPerson extends RealmObject {
@PrimaryKey
private String userId;
...
private RealmList<RealmString> stringStuff;
private RealmList<SimpleRealmObj> otherStuff;
<setters and getters>
}
SimpleRealmObjは文字列要素のみを持っているため正常に動作します
public class SimpleRealmObj extends RealmObject {
private String foo;
private String bar;
...
}
StringStuffを逆シリアル化するにはどうすればよいですか? gson TypeAdapterを使用してみました
public class RealmPersonAdapter extends TypeAdapter<RealmPerson> {
@Override
public void write(JsonWriter out, RealmPerson value) throws IOException {
out.beginObject();
Log.e("DBG " + value.getLastName(), "");
out.endObject();
}
@Override
public RealmPerson read(JsonReader in) throws IOException {
QLRealmPerson rList = new RealmPerson();
in.beginObject();
while (in.hasNext()) {
Log.e("DBG " + in.nextString(), "");
}
in.endObject();
return rList;
}
しかし、まだIllegalStateExceptionが発生します
2334-2334/com.qualcomm.qlearn.app E // PersonService.Java:71:main com.google.gson.JsonSyntaxException:Java.lang.IllegalStateException:ストリングが必要ですが、行1列3パス$のNAMEでした。
RealmList、RealmStringアダプタを試してみましたが、役に立ちませんでした。私がこれまで見つけた唯一の回避策は https://github.com/realm/realm-Java/issues/620#issuecomment-66640786 より良いオプションですか?
エラーメッセージ「Expected a string but was NAME
"は、実際のjsonオブジェクトの前のJsonReader
(これはString
)のjsonオブジェクトの名前を取得することで解決できます。
JsonReaderのAndroidドキュメント をご覧ください。詳細な説明とコードスニペットがあります。ドキュメントのサンプルコードスニペットでreadMessage
メソッドを確認することもできます。
あなたのread
メソッドを私が思うに変更しました。 注:私はコードをテストしなかったので、いくつかの小さなエラーがあるかもしれません。
@Override
public RealmPerson read(JsonReader in) throws IOException {
RealmPerson rList = new RealmPerson();
in.beginObject();
String name = "";
while (in.hasNext()) {
name = in.nextName();
if (name.equals("userId")) {
String userId = in.nextString();
// update rList here
} else if (name.equals("otherStuff")) {
// since otherStuff is a RealmList of RealmStrings,
// your json data would be an array
// You would need to loop through the array to retrieve
// the json objects
in.beginArray();
while (in.hasNext()) {
// begin each object in the array
in.beginObject();
name = in.nextName();
// the RealmString object has just one property called "value"
// (according to the code snippet in your question)
if (name.equals("val")) {
String val = in.nextString();
// update rList here
} else {
in.skipValue();
}
in.endObject();
}
in.endArray();
} else {
in.skipValue();
}
}
in.endObject();
return rList;
}
これが役立つかどうか教えてください。
それが良い 使用すること JsonSerializer
と JsonDeserializer
ではなく、 TypeAdapter
は、RealmObject
に対して、2つの理由から:
RealmObject
のシリアル化をデフォルトのGson(デ)シリアライザーに委任(デ)できます。つまり、ボイラープレートを自分で記述する必要はありませんです。
Gson 2.3.1の奇妙なバグ があり、これはデシリアライズ中にStackOverflowError
を引き起こす可能性があります(私はTypeAdapter
アプローチを自分で試したところ、このバグに遭遇しました)。
方法は次のとおりです(Tag
をRealmObject
クラスに置き換えてください):
([〜#〜] note [〜#〜]以下のcontext.serialize
およびcontext.deserialize
はgson.toJson
およびgson.fromJson
と同等であるため、don 't自分でTag
クラスを解析する必要があります。)
RealmList<Tag>
のパーサー+シリアライザー:
public class TagRealmListConverter implements JsonSerializer<RealmList<Tag>>,
JsonDeserializer<RealmList<Tag>> {
@Override
public JsonElement serialize(RealmList<Tag> src, Type typeOfSrc,
JsonSerializationContext context) {
JsonArray ja = new JsonArray();
for (Tag tag : src) {
ja.add(context.serialize(tag));
}
return ja;
}
@Override
public RealmList<Tag> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
throws JsonParseException {
RealmList<Tag> tags = new RealmList<>();
JsonArray ja = json.getAsJsonArray();
for (JsonElement je : ja) {
tags.add((Tag) context.deserialize(je, Tag.class));
}
return tags;
}
}
タグクラス:
@RealmClass
public class Tag extends RealmObject {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
次に、コンバータークラスをGsonに登録します。
Gson gson = new GsonBuilder()
.registerTypeAdapter(new TypeToken<RealmList<Tag>>() {}.getType(),
new TagRealmListConverter())
.create();
私のgson typeAdapterは犯人でした。上記のエラーは、jsonをRealmPersonに正しくデシリアライズしなかったために見られました。最初のフィールドは文字列ではないため、
in.nextString()
退屈だった。
私はいくつかのサンプルコードを見て、それが私を襲った、私は使用する必要はありませんでした
in.beginObject()およびin.endObject()
文字列をデシリアライズします。以下のコードが機能します。
public class QLRealmStringAdapter extends TypeAdapter<QLRealmString> {
@Override
public void write(JsonWriter out, QLRealmString value) throws IOException {
Log.e("DBG " + value.getValue(), "");
out.value(value.getValue());
}
@Override
public RealmString read(JsonReader in) throws IOException {
RealmString rString = new RealmString();
if (in.hasNext()) {
String nextStr = in.nextString();
System.out.println("DBG " + nextStr);
rString.setValue(nextStr);
}
return rString;
}
}
これが誰かを助けることを願っています。
arraylistをRealmListに変換するには、ジャクソンシリアライザーとデシリアライザーが必要です。