Gson将List<String>反序列化为realmList<RealmString>

Gson deserialization of List<String> into realmList<RealmString>

我正在使用 gson 改造将我的 json 反序列化为领域对象。这在大多数情况下都非常有效。处理

时出现问题

RealmList(String(or any other basic data type))

由于 Realm 不支持 RealmList,其中 E 不扩展 Realm 对象,我将 String 包装在 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: Expected a string but was NAME at line 1 column 3 path $.

我之前尝试过 RealmList、RealmString 适配器,但无济于事。 到目前为止我设法找到的唯一解决方法是 https://github.com/realm/realm-java/issues/620#issuecomment-66640786 还有更好的选择吗?

我的 gson typeAdapter 是罪魁祸首。 上面的错误是因为我没有正确地将 json 反序列化为 RealmPerson,第一个字段不是字符串,因此

in.nextString()

很无聊。

我看了一些示例代码,它击中了我,我不必使用

in.beginObject() and 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;
}

}

希望这对某人有所帮助。

错误消息“Expected a string but was NAME”可以通过在实际 json 对象(这是一个String 在你的情况下)。

你可以看看Android documentation for JsonReader。它有详细的解释和代码片段。您还可以查看文档中示例代码片段中的 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;
}

如果有帮助请告诉我。

It is better to use JsonSerializer and JsonDeserializer rather than TypeAdapter 为您的 RealmObject,因为 2 个原因:

  1. 它们允许您将 RealmObject 的(反)序列化委托给默认的 Gson(反)序列化器,这意味着 您不需要编写样板自己.

  2. a weird bug in Gson 2.3.1 可能会在反序列化期间导致 WhosebugError(我自己尝试了 TypeAdapter 方法并遇到了这个错误)。

方法如下(将 Tag 替换为您的 RealmObject class):

(注意 下面的 context.serializecontext.deserialize 等同于 gson.toJsongson.fromJson, 这意味着我们 不需要自己解析Tagclass。)

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

}

标签class:

@RealmClass
public class Tag extends RealmObject {
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

然后用 Gson 注册你的转换器 class:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(new TypeToken<RealmList<Tag>>() {}.getType(),
                new TagRealmListConverter())
        .create();

我需要一个用于将 Arraylist 转换为 RealmList 的 jackson 序列化器和反序列化器