Simon Tenbeitel
Simon Tenbeitel

Reputation: 877

Retrofit get unknown fields as Map

I currently struggle with retrieving an JSON object with retrofit. The problem is, that I don't know the names of the fields in advance. Normally I would map these fields as a Map, but how do I name this retrofit object?

That's how my JSON object looks like:

{
    "User{email='[email protected]', id='JDoe'}" : {
        "101" : 1,
        "102" : 2,
        "103" : 3,
        "104" : 2
     },
     "User{email='[email protected]', id='JDoe01'}" : {
         "101" : 3,
         "102" : 1,
         "103" : 1,
         "104" : 3
     }
}

The class for the retrofit object:

public static class UserSettings{
    public Map<String, Map<String, Integer>> settingsMap;
}

Now what I think happens is that retrofit tries to find a object called 'settingsMap'. But this map is the root element and therefore does not have a name, so the settingsMap is a null object.

Any help to solve this problem is appreciated!

Thanks in advance.

Upvotes: 0

Views: 2155

Answers (1)

Konrad Krakowiak
Konrad Krakowiak

Reputation: 12365

You have to implement your own deserialiser for UserSettings object. As is shown below:

As first create model for user setting data:

public class UserSettings {
        public Map<String, Map<String, Integer>> settingsMap;

    public  UserSettings(){
        settingsMap = new HashMap<>();
    }

    public void add(String key, Map<String, Integer> settingMap){
        settingsMap.put(key, settingMap);
    }
}

In the next step prepare API client for you object

public interface UserSettingApiClient {

    @GET("/yourEndpoint")
    UserSettings getUserSetting();
}

And now is the most important step. You have to create your own JsonDeserializer as is shown below:

public class UserDeserializer implements JsonDeserializer<UserSettings> {

    @Override
    public UserSettings deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        UserSettings userSettings = new UserSettings();
        JsonObject jsonObject = (JsonObject) json;
        for (Map.Entry<String, JsonElement> element : jsonObject.entrySet()){
            String key = element.getKey();
            JsonObject obj = jsonObject.getAsJsonObject(key);
            Map<String, Integer> settingMaps = new HashMap<>();
            for (Map.Entry<String, JsonElement> setting : obj.entrySet()){
                String settingKey = setting.getKey();
                Integer integer = obj.get(settingKey).getAsInt();
                settingMaps.put(settingKey, integer);
            }
            userSettings.add(key,settingMaps);
        }
        return userSettings;
    }
}

When you do this you have to register this deserialiser in your GsonConverter. The example below shows how to call complete request but you have to use this solution in the place where you create RestAdapter

new RestAdapter.Builder()
       .setEndpoint("http://your.apiaddress.com")
       .setLogLevel(RestAdapter.LogLevel.FULL)//this is not necessary 
       .setConverter(
              new GsonConverter(
                   new GsonBuilder()
                             .registerTypeAdapter(UserSettings.class, new UserDeserializer())
                   .create()))
      .build()
      .create(UserSettingApiClient.class)
      .getUserSetting();

Upvotes: 2

Related Questions