10

I need help.

I have an endpoint that takes a parameter. Depending on this parameter, the JSON returned will be completely different.

Is it possible for RetroFit to handle this?

For example:

http://myserver.com/all/<parameter>

where parameter is BUS or BICYCLE, as well as adding others later.

An example BUS request will return:

"stops": [{
    "Lat": "....",
    "Lng": "....",
    "Name": "Main Street",
    "Route": "",
    "StopNumber": "2"
}]

The BICYCLE endpoint will return:

"stops": [{
    "address": "Town Centre",
    "lat": "....",
    "lng": "....",
    "number": "63",
    "open": "1"
}]

Depending on which section of my Android app that the user is in, I would like to send a different parameter, and be able to handle it using the same call.

I was thinking of using a parent class called AllTypes that each of the other classes extend, and then setting my Retrofit call signature to:

@GET("/all/{type}")
void getAll(@Path("type") String type, Callback<AllTypes> callback);

But I'm not sure if Retrofit can automatically pick the correct child class for AllTypes based on the returned JSON, or even the passed parameter type.

Does anyone know how to do this? If not, I'll just have to create multiple different methods with different Callback types.

Thanks.

eoinzy
  • 2,152
  • 4
  • 36
  • 67
  • 1
    Better to merge up both `JSON` in one and set parameter for particular Type – M D Feb 13 '16 at 15:36
  • Do you mean have one big class with all the fields from all the different `JSON` responses? That may be inefficient. – eoinzy Feb 13 '16 at 15:37
  • I mean make one General `JSON` class both types use that one – M D Feb 13 '16 at 15:38
  • There will be more than 2 types. At least 4. – eoinzy Feb 15 '16 at 17:40
  • I just thought of an idea. I can probably just return a `JSONObject` and use `GSON` to convert to my preferred option myself. I'll know which type I'll need when I call the endpoint, so that might make more sense. – eoinzy Feb 18 '16 at 11:35

4 Answers4

10

Just to close this off.

You can get the raw JSON back from RetroFit and use GSON to manually serialise to the class type you want.

For example:

RestClient.get().getDataFromServer(params, new Callback<JSONObject>() {
    @Override
    public void success(JSONObject json, Response response) {
        if(isTypeA) {
            //Use GSON to serialise to TypeA        
        } else {
            //Use GSON to serialise to TypeB
        }
    }
});
Kishan Vaghela
  • 7,678
  • 5
  • 42
  • 67
eoinzy
  • 2,152
  • 4
  • 36
  • 67
2

you can use JsonElement in such as follow : in ApiInterface.java :

@GET("web api url")
Call<JsonElement> GetAllMyClass();

than in MyActivity :

ApiInterface client = ApiClient.getClient().create(ApiInterface.class);

    Call<JsonElement> call = client.GetAllMyClass();
    call.enqueue(new Callback<JsonElement>() {
       @Override
       public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
                if (response.isSuccessful()) {
                     JsonElement questions = response.body();

 // if response type is array
                     List<MyClass> response_array = new Gson().fromJson(((JsonArray)questions), new TypeToken<List<MyClass>>(){}.getType());

 // if response type is object
                     MyClass response_one = new Gson().fromJson(questions.getAsJsonObject(), MyClass.class);
                 } else {
                      Log.d("MyClassCallback", "Code: " + response.code() + " Message: " + response.message());
                        }
                    }

      @Override
      public void onFailure(Call<JsonElement> call, Throwable t) {
               t.printStackTrace();
       }
    });
HamidReza
  • 1,726
  • 20
  • 15
1

I know it's a bit late, but probably my tip will be useful for someone.

If a returned JSON content depends on an endpoint parameter "type"(for example) one can use PolymorphicJsonAdapterFactory from Moshi for decoding to certain class. Please note the returned JSON must contain type information.

0

In this response, since it is only change in the fields but not the structure like array or object. In that case just define all the fields in the java object, the values that will be returned in that specific call will be mapped and the others will be null. Put a logic on your end to check null checks.