【问题标题】:Gson deserialization of List<String> into realmList<RealmString>Gson 将 List<String> 反序列化为 realmList<RealmString>
【发布时间】:2015-04-28 06:33:50
【问题描述】:

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

RealmList(String(或任何其他基本数据类型))

由于 Realm 不支持 E 不扩展 Realm 对象的 RealmList,我将 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: 主要 com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: 应为字符串,但名称位于第 1 行第 3 列路径$。

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

【问题讨论】:

    标签: java android gson realm


    【解决方案1】:

    It is better 使用JsonSerializer 和JsonDeserializer 而不是TypeAdapter 作为您的RealmObject,原因有两个:

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

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

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

    (注意下面的context.serialize和context.deserialize等价于gson.toJson和gson.fromJson,这意味着我们不需要解析@ 987654340@自己上课。)

    RealmList&lt;Tag&gt; 的解析器 + 序列化器:

    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();
    

    【讨论】:

    • 你的解决方案是最好的!
    • 此解决方案效果最佳,无需其他解决方案中推荐的样板代码。
    • 这对我仍然不起作用:java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING 在tags.add((RealmString) context.deserialize(je, RealmString.class)); 行中
    • @HenriquedeSousa 该错误意味着您收到的 JSON 在某种程度上与您的代码不匹配。您的RealmString 类的定义方式与@avid 的原始问题完全相同吗?还有你的 JSON 是什么样的?
    • @VickyChijwani 我发布了另一个问题,如果你愿意,可以帮助我,谢谢:stackoverflow.com/questions/37727315/…
    【解决方案2】:

    错误消息“Expected a string but was NAME”可以通过在实际 json 对象(在您的情况下为 String)之前检索 JsonReader 中的 json 对象的名称来解决。

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

    如果这有帮助,请告诉我。

    【讨论】:

    • 谢谢@iRuth。这确实是反序列化 json blob 并回答原始问题的方法。我会将其标记为正确答案。对于只想反序列化领域字符串的其他人,请在下面查看我的答案。
    【解决方案3】:

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

    }

    希望这对某人有所帮助。

    【讨论】:

    • 这是缺少的链接!我将所有模型转换为使用原始类型和 RealmString 对象,设置一个排除策略,如下所示:stackoverflow.com/questions/32434377/…,然后实现了这个 RealmString TypeAdapter,一切正常!谢谢
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-22
      • 1970-01-01
      • 2014-02-08
      • 2018-01-09
      • 2017-01-15
      • 2020-05-06
      相关资源
      最近更新 更多