Using Realm with Gson
Asked Answered
D

2

6

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)?

Donahue answered 10/2, 2016 at 9:1 Comment(0)
P
4

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

Paterfamilias answered 10/2, 2016 at 10:23 Comment(1)
thanks Christian. IMHO priority must be changed to normal :)Donahue
R
15

Why writing all these custom serializers when you can make Gson and Realm work together with just ONE LINE OF CODE?

IMO, setting an exclusive strategy to every model we want to serialize is not the best approach. As you have realized, this approach requires writing a lot of boiler-plate code which is error prone and the worst of all, kills what Gson is about (which is writting less code).

And since we're working-around incompatibilities, why don't you just make sure to pass an unmanged RealmObject to your Gson serializer?

Simplest solution ever (IMO)

Found here. Get a copy in memory of the managed RealmObject and pass it to Gson

new Gson().toJson(realm.copyFromRealm(managedModel));

And that's it! No more code to write!

Other good solutions and explanations are posted here.

Robespierre answered 4/2, 2017 at 19:21 Comment(0)
P
4

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

Paterfamilias answered 10/2, 2016 at 10:23 Comment(1)
thanks Christian. IMHO priority must be changed to normal :)Donahue

© 2022 - 2024 — McMap. All rights reserved.