web-dev-qa-db-ja.com

List <String>からrealmList <RealmString>へのGsonデシリアライゼーション

私は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 より良いオプションですか?

25
avid

エラーメッセージ「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;
}

これが役立つかどうか教えてください。

5
iRuth

それが良い 使用すること JsonSerializerJsonDeserializer ではなく、 TypeAdapter は、RealmObjectに対して、2つの理由から:

  1. RealmObjectのシリアル化をデフォルトのGson(デ)シリアライザーに委任(デ)できます。つまり、ボイラープレートを自分で記述する必要はありませんです。

  2. Gson 2.3.1の奇妙なバグ があり、これはデシリアライズ中にStackOverflowErrorを引き起こす可能性があります(私はTypeAdapterアプローチを自分で試したところ、このバグに遭遇しました)。

方法は次のとおりです(TagRealmObjectクラスに置き換えてください):

[〜#〜] note [〜#〜]以下のcontext.serializeおよびcontext.deserializegson.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();
32
Vicky Chijwani

私の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;
}

}

これが誰かを助けることを願っています。

4
avid

arraylistをRealmListに変換するには、ジャクソンシリアライザーとデシリアライザーが必要です。

0
avez raj