avid avid - 6 months ago 436
Java Question

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

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?

Answer

The error message "Expected a string but was NAME" can be solved by retrieving the name of the json object in the JsonReader before the actual json object (which is a String in your case).

You can take a look at the Android documentation for JsonReader. It has detailed explanation and code snippet. You can also take a look at the readMessage method in the sample code snippet in the documentation.

I have modified your read method to what I think it should be. NOTE: I didn't test the code, so there may be some minor errors in it.

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

Let me know if this helps.