Skip to content

Instantly share code, notes, and snippets.

@cmelchior
Last active September 20, 2022 04:30
Show Gist options
  • Star 73 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save cmelchior/ddac8efd018123a1e53a to your computer and use it in GitHub Desktop.
Save cmelchior/ddac8efd018123a1e53a to your computer and use it in GitHub Desktop.
Serialize Realm objects to JSON using GSON
// GSON can parse the data.
//
// Deserialization:
// Note there is a bug in GSON 2.3.1 that can cause it to StackOverflow when working with RealmObjects.
// To work around this, use the ExclusionStrategy below or downgrade to 1.7.1
// See more here: https://code.google.com/p/google-gson/issues/detail?id=440
//
// Serialization:
// <Type>RealmProxy objects are created by the Realm annotation processor. They are used to control
// access to the actual data instead of storing them in fields and it is therefore them we need to register a
// TypeAdapter for.
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;
}
})
.registerTypeAdapter(Class.forName("io.realm.PersonRealmProxy"), new PersonSerializer())
.registerTypeAdapter(Class.forName("io.realm.DogRealmProxy"), new DogSerializer())
.create();
// Serialize a Realm object to a JSON string
String json = gson.toJson(realm.where(Person.class).findFirst());
package io.realm.example;
import io.realm.RealmObject;
public class Dog extends RealmObject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package io.realm.examples;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import io.realm.examples.realmgridview.Dog;
public class DogSerializer implements JsonSerializer<Dog> {
@Override
public JsonElement serialize(Dog src, Type typeOfSrc, JsonSerializationContext context) {
final JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", src.getName());
return jsonObject;
}
}
package io.realm.example;
import io.realm.RealmList;
import io.realm.RealmObject;
public class Person extends RealmObject {
private String name;
private int age;
private Dog favoriteDog;
private RealmList<Dog> dogs;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Dog getFavoriteDog() {
return favoriteDog;
}
public void setFavoriteDog(Dog favoriteDog) {
this.favoriteDog = favoriteDog;
}
public RealmList<Dog> getDogs() {
return dogs;
}
public void setDogs(RealmList<Dog> dogs) {
this.dogs = dogs;
}
}
package io.realm.example;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
public class PersonSerializer implements JsonSerializer<Person> {
@Override
public JsonElement serialize(Person src, Type typeOfSrc, JsonSerializationContext context) {
final JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", src.getName());
jsonObject.addProperty("age", src.getAge());
jsonObject.add("favoriteDog", context.serialize(src.getFavoriteDog()));
jsonObject.add("dogs", context.serialize(src.getDogs()));
return jsonObject;
}
}
@jakoss
Copy link

jakoss commented Apr 18, 2016

gsonBuilder.registerTypeAdapter(DogRealmProxy.class, new DogSerializer());
gsonBuilder.registerTypeAdapter(PersonRealmProxy.class, new PersonSerializer())

Works just fine

@zoopolitic
Copy link

zoopolitic commented May 31, 2016

For those who still has troubles with serialization:

Your model:

public class User extends RealmObject {
@PrimaryKey
    private String id;
    private String name;
    private String email;

    // getters and setters
}

Your UserSerializer:

public class UserSerializer implements JsonSerializer<User> {

    @Override
    public JsonElement serialize(User src, Type typeOfSrc, JsonSerializationContext context) {
        final JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("id", src.getId());
        jsonObject.addProperty("email", src.getEmail());
        jsonObject.addProperty("name", src.getName());
    }
}

Your method where you call e.g. retrofit interface:

...
    private UserApi api;
...
    @Override
    public void updateUser(String name, String info, String photoUrl) {
        User user = realm.copyFromRealm(current); // make copy of the model from realm
        user.setName(name);
        user.setInfo(info);
        user.setPhoto(photoUrl);
        api.updateUser(user);
        ...
}

Your Gson configuration:

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;
                    }
                })
                .registerTypeAdapter(User.class, new UserSerializer())
                .create();

profit.

@ArthurSav
Copy link

The more i use realm, the more reasons i keep finding not to use it.
Yes, you don't have to write boilerplate SQL but you introduce new boilerplate and workarounds.

@jemshit
Copy link

jemshit commented Jul 14, 2016

@cmelchior this doesn't work with Realm-1.1.0 and Retrofit2-2.1.0. Not sure if to create issue for realm or retrofit

@biajoeknee
Copy link

biajoeknee commented Aug 21, 2016

@cmelchior also experiencing this issue...

Update:
this is in fact working with realm 1.1.1; exactly as it is demonstrated. i was using my model class when registering the adapter instead of realm's proxy class for the model.

@Zhuinden
Copy link

Zhuinden commented Aug 30, 2016

@ArthurSav meh, to serialize with GSON, just call gson.toJson(realm.copyFromRealm(realmObject));

@bvisonl
Copy link

bvisonl commented Dec 31, 2016

@ArthurSav I find it incredibly creepy that I was thinking exactly the same thing right before reading your comment.....

@felixeduardo15
Copy link

gson.toJson(realm.copyFromRealm(realmObject)); return a JsonObject? How i can do that? @Zhuinden

@HsiangLeekwok
Copy link

@felixeduardo15

copyFromRealm will return a unmanaged object/objects, so you can use it directly with no realm exception.
gson.toJson(realm.copyFromRealm(realmObject/realmObjects)); is a lazy function but it worked.

@midoalone
Copy link

I am using this and it actually works with me:

Gson gson = new Gson();
String listString = gson.toJson(
    items,
    new TypeToken<ArrayList<Item>>() {}.getType());
try {
    JSONArray jsonArray =  new JSONArray(listString);
    System.out.println(jsonArray.toString());
} catch (JSONException e) {
    e.printStackTrace();
}

@TechNov
Copy link

TechNov commented Dec 17, 2021

After tow days of bug resolve, i found this SIMPLE solution.

YourRealmObject realmObj = realm.where(YourRealmObject.class).findFirst(); if(realmObj != null) { realmObj = realm.copyFromRealm(realmObj); //detach from Realm, copy values to fields String json = gson.toJson(realmObj); }

@zihadrizkyef
Copy link

if there's 100 model, then i have to make 100 type adapter.....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment