Search code examples
javaandroidjsonrealmrealm-java

Using Realm with Gson


I have json with field _id

 String json = "{ _id : 1, name : 'Alex', role: 'admin' }"

In my Realm model I use @SerializedName attribute:

public class User extends RealmObject {

    @SerializedName("_id")  
    @PrimaryKey
    private int id;
    private String name;
    private String comment;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

}  

If try save the json:

realm.createOrUpdateObjectFromJson(User.class, json)

field _id can't parsed and in database created record with id = 0

In docs using @SerializedName attribute

  Gson gson = new GsonBuilder()
            .setExclusionStrategies(new ExclusionStrategy() {
                @Override
                public boolean shouldSkipField(FieldAttributes f) {
                    return f.getDeclaringClass().equals(RealmObject.class);
                }

                @Override
                public boolean shouldSkipClass(Class<?> clazz) {
                    return false;
                }
            }).create();


User user = gson.fromJson(json, User.class);
realm.beginTransaction();
realm.copyToRealmOrUpdate(user);

In this case json = "{ _id : 1, role: 'user' }" just remove user name from database, because default value for String is null.

So, probably I incorrectly using the attribute. How to consider the attribute when dealing with the methods of conservation of json (createOrUpdateObjectFromJson, etc)?


Solution

  • You probably need a hybrid solution in order to make this work. The reason is that @SerializedName is a GSON annotation and not one that Realm knows about. So this means you have two choices as you already discovered:

    1) Use GSON, which means the end result is an object with null as the default for name.

    2) Use createOrUpdateObjectFromJson which means that _id will be ignored because Realm's JSON parser require a 1:1 mapping.

    As neither solution will work correctly you can modify them in the following way:

    1) With GSON, instead of doing copyToRealmOrUpdate you can manually search for the object and update the role:

    realm.beginTransaction();
    realm.where(User.class).equalTo("id", user.getId()).findFirst().setRole(user.getRole());
    realm.commitTransaction();
    

    2) Using just the pure JSON you can modify to match the expected format:

    JSONObject obj = new JSONObject(json);
    obj.put("id", obj.getString("_id"));
    obj.remove("_id");
    

    Realm has an issue tracking the request for custom mappings, but it has a low priority as that feature is usually better covered by frameworks such as GSON, Jacokson, etc. : https://github.com/realm/realm-java/issues/1470