Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

I'm using retrofit with gson to deserialize my json into realm objects. This works very well for the most part. Trouble arises when dealing with

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

Since Realm doesnt support RealmList where E doesnt extend Realm object, I wrapped String in a RealmObject.

public class RealmString extends RealmObject {   private String val;    public String getValue() {     return val;   }    public void setValue(String value) {     this.val = value;   } } 

My realm Object is as below

    public class RealmPerson extends RealmObject {     @PrimaryKey     private String userId;     ...     private RealmList<RealmString> stringStuff;     private RealmList<SimpleRealmObj> otherStuff;      <setters and getters>    } 

SimpleRealmObj works fine as it only has String elements

    public class SimpleRealmObj extends RealmObject {     private String foo;     private String bar;        ...     } 

How can I deserialize stringStuff? I tried using a 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;     } 

However I still hit the 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 $.

I tried RealmList, RealmString adapter earlier to no avail. The only workaround I managed to find so far is https://github.com/realm/realm-java/issues/620#issuecomment-66640786 Any better options?

like image 881
avid Avatar asked Feb 26 '15 01:02

avid


1 Answers

It is better to use JsonSerializer and JsonDeserializer rather than TypeAdapter for your RealmObject, because of 2 reasons:

  1. They allow you to delegate (de)serialization for your RealmObject to the default Gson (de)serializer, which means you don't need to write the boilerplate yourself.

  2. There's a weird bug in Gson 2.3.1 that might cause a StackOverflowError during deserialization (I tried the TypeAdapter approach myself and encountered this bug).

Here's how (replace Tag with your RealmObject class):

(NOTE that context.serialize and context.deserialize below are equivalent to gson.toJson and gson.fromJson, which means we don't need to parse the Tag class ourselves.)

Parser + serializer for 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;     }  } 

Tag class:

@RealmClass public class Tag extends RealmObject {     private String value;      public String getValue() {         return value;     }      public void setValue(String value) {         this.value = value;     } } 

Then register your converter class with Gson:

Gson gson = new GsonBuilder()         .registerTypeAdapter(new TypeToken<RealmList<Tag>>() {}.getType(),                 new TagRealmListConverter())         .create(); 
like image 143
Vicky Chijwani Avatar answered Sep 20 '22 14:09

Vicky Chijwani