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

Posted

技术标签:

【中文标题】Gson 将 List<String> 反序列化为 realmList<RealmString>【英文标题】:Gson deserialization of List<String> into 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 有更好的选择吗?

【问题讨论】:

【参考方案1】:

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

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

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

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

(注意下面的context.serializecontext.deserialize等价于gson.toJsongson.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 STRINGtags.add((RealmString) context.deserialize(je, RealmString.class)); 行中 @HenriquedeSousa 该错误意味着您收到的 JSON 在某种程度上与您的代码不匹配。您的RealmString 类的定义方式与@avid 的原始问题完全相同吗?还有你的 JSON 是什么样的? @VickyChijwani 我发布了另一个问题,如果你愿意,可以帮助我,谢谢:***.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 对象,设置一个排除策略,如下所示:***.com/questions/32434377/…,然后实现了这个 RealmString TypeAdapter,一切正常!谢谢【参考方案4】:

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

【讨论】:

以上是关于Gson 将 List<String> 反序列化为 realmList<RealmString>的主要内容,如果未能解决你的问题,请参考以下文章

gson的特殊用法

使用Gson解析报错

当从共享prefs获取时,GSON将先前存储的List转换为LinkedTreeMaps的ArrayList

在 Java 中将 JSON 转换为 List<List<String>>

Android ---------List 数组转成 json格式的字符串

如何使用 GSON 将 List 转换为 JSON 对象?