简体   繁体   中英

Retrofit2 handle JSON response that contains two models data

I'm using retrofit2 to handle http request after calling from API. Let me explain this.

I have 2 java class(POJO) created to handle user and lecturer data which is User.java and Lecturer.java respectively. For the response data such as :

{
  "users": [
    {
      "user_id": "28",
      "user_email": "john@abc.com",
      "user_password": "123"
    }
  ]
}

i can use User.java class to handle this response. Nothing complex in this file, only contains getter and setter method. Same goes to lecturer data, here is the example of lecturer data :

{
  "lecturers": [
    {
      "lecturer_id": "3",
      "user_id": "28",
      "lecturer_name": "johny2"
    }
  ]
}

i can handle it by using Lecturer.java class.

But the problem is, if the response contains both user and lecturer data on a single json, how to handle it?? . Here is the example of request :

{
  "users": [
    {
      "user_id": "28",
      "user_email": "john@abc.com",
      "user_password": "123",
      "lecturer_id": "3",
      "lecturer_name": "johny2"
    }
  ]
}

To solve this problem, i think i need to create another java class that contains both User and Lecturer class on it, unfortunately at here i'm stuck.

This is new file, that i tried to create (Userlecturer.java) :

public class UserLecturer {

  User user;
  Lecturer lecturer;

  // how to implement on this part
}

Here is UserLecturer interface :

public interface UserLecturerInterface {

  @GET ( "api/endpoint/here" )
  Call<UserLecturer> getLecturerByUserId (@Path( "userId" ) String userId );

}

Appreciated for any helps. Ask me for more inputs if above use case did't clear enough. Thanks

I think the POJO should be:

public class Users {
    String userId;
    String userEmail;
    String userPassword;
    String lecturerId;
    String lecturerName;
}

Even though there are 2 models inside the JSON, you only need 1 model for Retrofit.


If you really want to split the 1 JSON response into 2 models, I think you have to implement custom JSON converter.

Gson gson = new GsonBuilder()
            .registerTypeAdapter(UserLecture.class, new JsonDeserializer<UserLecture>() {
                public UserLecture deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                    JsonArray usersJsonArray = json.getAsJsonObject().getAsJsonArray("users");
                    JsonObject userJsonObject = usersJsonArray.getAsJsonArray().get(0).getAsJsonObject();
                    User user = new User();
                    user.setUserId(userJsonObject.get("user_id").getAsString());
                    user.setUserEmail(userJsonObject.get("user_email").getAsString());
                    user.setUserPassword(userJsonObject.get("user_password").getAsString());
                    Lecturer lecturer = new Lecturer();
                    lecturer.setLecturerId(userJsonObject.get("lecturer_id").getAsString());
                    lecturer.setLecturerName(userJsonObject.get("lecturer_name").getAsString());
                    return new UserLecture(lecturer, user);
                }
            })
            .create();

Retrofit retrofit = new Retrofit.Builder()
.baseUrl([YOUR_BASE_URL])
.addConverterFactory(GsonFactoryConverter.create(gson))
.build();

This is some code I use to convert longs to Java Date objects. Presumably, you can do the same thing for your UserLecture object. You should be able to extract the individual json objects for User and Lecture, create a new UserLecture object and let User and Lecture as objects in it.

Gson gson = new GsonBuilder().registerTypeAdapter(UserLecture.class, new JsonDeserializer<UserLecture>() {
            public UserLecture deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                JsonObject user = json.getAsJsonObject().getAsJsonObject("user");
                JsonObject lecture = json.getAsJsonObject().getAsJsonObject("lecture");
                return new UserLecture(user, lecture);
            }
        }).create();

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonFactoryConverter.create(gson))
    .build();

Then inside UserLecture :

public UserLecture(JsonObject userJson, JsonObject lectureJson) {
   this.user = new User();
   this.user.setUserId(userJson.get("user_id").getAsInt());
   this.user.serUserEmail(userJson.get("user_email").getAsString());
   //so on.
}

At first let me say that the JSON you need to process here is broken by design so you should urge the guy / department / company to fix it.

Secondly, JSON processors like Jackson allow to parse polymorphic data structures like this easily, but they require some kind of type flag to distinguish one of another type (ie type: "user" and type: "lecturer" ). There is also a way to do this without such type flags, but there is a lot more hand work involved. The last example here shows how to do it.

Yes, it is one possible solution. Gson ignores all fields, which names doesnt match @SerializedName annotation. So, you may try another solution without creating any more pojo classes- return result as String, and try to parse this string as both classes. If one result is empty- then you have another. But, if both kbjects isnt empty- then original response contain fields from both pojos

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM