1

I'm having a bit of an issue with my custom serializers working with Retrofit, Realm and Gson. Here I am registering type adapters for my three classes:

GsonBuilder builder = new GsonBuilder();
        // Register type adapters to modify outgoing json according to server requirements.
        try {
            builder
                    .registerTypeAdapter(Class.forName("io.realm.UserProxy"), new UserSerializer())
                    .registerTypeAdapter(Class.forName("io.realm.FavoriteSongProxy"), new FavoriteSongSerializer())
                    .registerTypeAdapter(Class.forName("io.realm.ArtistProxy"), new ArtistSerializer())
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }

        Gson gson = builder.create();

        return new Retrofit.Builder()
                .baseUrl("http://10.0.3.2:8080/myUrl/rest/v1/")
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(httpClient.build())
                .build();

A user has a FavoriteSong, and a FavoriteSong has an Artist. My serializers are set up very similar, here is an example for the FavoriteSongSerializer.

public class FavoriteSongSerializer implements JsonSerializer<FavoriteSong> {
    @Override
    public JsonElement serialize(FavoriteSong src, Type typeOfSrc, JsonSerializationContext context) {
        Log.v("qwer", "serializingFavoriteSong");
        final JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("id", src.getId());
        jsonObject.add("song", context.serialize(src.getSong()));
        return jsonObject;
    }

}

Here is the User serializer:

public class UserSerializer implements JsonSerializer<User> {
    @Override
    public JsonElement serialize(User src, Type typeOfSrc, JsonSerializationContext context) {
        Log.v("qwer", "serializingUser");
        final JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("id", src.getId());
        jsonObject.add("favoriteSong", context.serialize(src.getFavoriteSong()));
        return jsonObject;
    }
}

The weird part is, both the FavoriteSong and Song serializers are called when I send my request (I can see the log statements), but the UserSerializer is not. Anyone know why this might be happening, or how I might troubleshoot?

/** Edit **/

So as a test I created a TestModel that just contains an id, created a serializer for it, registered a type adapter, and added it to my User model. And it also fails to call the TestModelSerializer (even though it serializes according to the default method).

jwBurnside
  • 849
  • 4
  • 31
  • 66
  • I am not familiar with Realm but the problem might be that e.g. UserSerializer requieres a User while you register the adapter for the class io.realm.UserProxy – Damian Jäger Feb 16 '17 at 21:02
  • 4
    Have you checked [this answer](http://stackoverflow.com/a/42044320/3503855)? It provides a **much easier** way to workaround Gson+Realm incompatibility. – Anis LOUNIS aka AnixPasBesoin Feb 18 '17 at 00:10
  • That's unfortunately not going to help my specific problem (I figured out a solution below), but definitely good to point that post out for anyone Retrofit-Gson issues, I dealt with the same scenario a few weeks ago and it took a while to figure out what's going on. – jwBurnside Feb 20 '17 at 17:36

2 Answers2

0

Try with registerTypeHierarchyAdapter instead of registerTypeAdapter:

.registerTypeHierarchyAdapter(Class.forName("io.realm.UserProxy"), new UserSerializer())

EDIT:

 builder
     .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.UserProxy"), new UserSerializer())
     .registerTypeAdapter(Class.forName("io.realm.FavoriteSongProxy"), new FavoriteSongSerializer())
     .registerTypeAdapter(Class.forName("io.realm.ArtistProxy"), new ArtistSerializer())
Matias Elorriaga
  • 8,880
  • 5
  • 40
  • 58
  • I attempted that with the same results. – jwBurnside Feb 16 '17 at 19:31
  • if you only register UserSerializer, it works? please add the code for that serializer – Matias Elorriaga Feb 16 '17 at 19:43
  • I have added the User serializer. I cannot test registering "only" the User serializer because gson with throw a fit due to the FavoriteSong and Song references. – jwBurnside Feb 16 '17 at 19:55
  • try inverting the order of the .registerTypeAdapter calls, first register song and artist, and then register user. – Matias Elorriaga Feb 16 '17 at 20:04
  • Yeah I tried that already as well, the order in which I register the type adapters does not seem to matter. I'm going to update a couple of troubleshooting steps in the question that I did, one sec. – jwBurnside Feb 16 '17 at 20:07
0

So if register my User type adapter as:

registerTypeAdapter(User.class, new UserSerializer())

instead of:

.registerTypeAdapter(Class.forName("io.realm.UserProxy"), new UserSerializer())

the User serializer is called. I still have no idea why, but it works.

jwBurnside
  • 849
  • 4
  • 31
  • 66