Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RealmList serialization issues (Realm/Gson/Intent)

I use Retrofit, Gson and Realm in my project. I have this class Examplethat need to be Serializable. Without Realm I'd write it like that :

public class Example implements Serializable {
    @SerializationName("users")
    private List<String> users

    //... getters and setters
}

Realm comes into play and Example becomes (note that getters and setters are this way for compatibility reasons) :

public class Example extends RealmObject implement Serializable {

    @SerializedName("users")
    private RealmList<RealmString> users;

    public ArrayList<String> getUsers() {
        ArrayList<String> array = new ArrayList<>();
        for (RealmString rs : users) {
            array.add(rs.getValue());
        }
        return array;
    }

    public void setUsers(ArrayList<String> users) {
        RealmList<RealmString> array = new RealmList<>();
        for (String rs : users) {
            array.add(new RealmString(rs));
        }
        this.users = array;
    }

}

with RealmString being :

public class RealmString extends RealmObject implements Serializable {

    private String val;

    //Constructors, getter and setter
}

and add a custom Gson type converter for it to be deserialized correctly :

public class RealmStringRealmListConverter implements JsonSerializer<RealmList<RealmString>>,
        JsonDeserializer<RealmList<RealmString>> {

    @Override
    public JsonElement serialize(RealmList<RealmString> src, Type typeOfSrc,
                                 JsonSerializationContext context) {
        JsonArray ja = new JsonArray();
        for (RealmString tag : src) {
            ja.add(tag.getValue());
        }
        return ja;
    }

    @Override
    public RealmList<RealmString> deserialize(JsonElement json, Type typeOfT,
                                              JsonDeserializationContext context)
            throws JsonParseException {
        RealmList<RealmString> tags = new RealmList<>();
        JsonArray ja = json.getAsJsonArray();
        for (JsonElement je : ja) {
            if (je.isJsonPrimitive()) {
                tags.add(new RealmString(je.getAsString()));
            }
        }
        return tags;
    }

}

Ok so now we're starting to feel that Realm is starting to have to big of an impact over our code. But that's a side problem, the main issue is that Example is no longer Serializable : RealmList isn't.

so I tried to make the RealmList transient and have its pendent List that I can annotate with @Ignore, and recreate the RealmList after serialization. But transient is not accepted by Realm.

Now I feel a bit stuck, Example is passed through intents in numerous parts of my code (it's a member of a lot of classes). I don't want to use an id and query it everywhere.

My question would be :

How can I change ̀ Example` in a way that allows me to do new Bundle().putSerializable("test", new Example()); without crash.

Thanks for helping !

like image 799
Renaud Favier Avatar asked Aug 31 '16 12:08

Renaud Favier


1 Answers

Serializable won't work with RealmList, but you can use Parceler library and implement Parcelable to parcel RealmObjects (note: it will turn them into unmanaged copies!)

@Parcel(implementations = { UserRealmProxy.class },
        value = Parcel.Serialization.BEAN,
        analyze = { User.class })
public class User extends RealmObject {
    // ...
}

compile "org.parceler:parceler-api:1.0.3"
apt "org.parceler:parceler:1.0.3"

To parcel RealmList, use following code

/* Copyright 2016 Patrick Löwenstein
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

public class RealmListParcelConverter implements TypeRangeParcelConverter<RealmList<? extends RealmObject>, RealmList<? extends RealmObject>> {
  private static final int NULL = -1;

  @Override
  public void toParcel(RealmList<? extends RealmObject> input, Parcel parcel) {
    if (input == null) {
      parcel.writeInt(NULL);
    } else {
      parcel.writeInt(input.size());
      for (RealmObject item : input) {
        parcel.writeParcelable(Parcels.wrap(item), 0);
      }
    }
  }

  @Override
  public RealmList fromParcel(Parcel parcel) {
    int size = parcel.readInt();
    RealmList list = new RealmList();

    for (int i=0; i<size; i++) {
      Parcelable parcelable = parcel.readParcelable(getClass().getClassLoader());
      list.add((RealmObject) Parcels.unwrap(parcelable));
    }

    return list;
  }
}
like image 58
EpicPandaForce Avatar answered Oct 05 '22 17:10

EpicPandaForce