【问题标题】:Retrofit2 handle JSON response that contains two models dataRetrofit2 处理包含两个模型数据的 JSON 响应
【发布时间】:2016-06-27 06:44:10
【问题描述】:

从 API 调用后,我正在使用 retrofit2 处理 http 请求。让我解释一下。

我创建了 2 java 类(POJO)来处理用户和讲师数据,分别是 User.javaLecturer.java。对于响应数据,例如:

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

我可以使用User.java 类来处理这个响应。这个文件没什么复杂的,只包含gettersetter 方法。讲师数据也是如此,这里是讲师数据的示例:

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

我可以使用Lecturer.java 类来处理它。

但问题是,如果响应包含单个json上的用户和讲师数据,如何处理? .这是请求的示例:

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

为了解决这个问题,我想我需要创建另一个包含 UserLecturer 类的 java 类,不幸的是我在这里卡住了。

这是我尝试创建的新文件(Userlecturer.java)

public class UserLecturer {

  User user;
  Lecturer lecturer;

  // how to implement on this part
}

这里是UserLecturer接口:

public interface UserLecturerInterface {

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

}

感谢任何帮助。如果上述用例不够清楚,请向我询问更多信息。谢谢

【问题讨论】:

  • 我认为这是正确的解决方案。有没有发现什么问题?
  • @RaymondLukanta 的问题是,如何在UserLecturer 类中编写getterssetters 代码,以使这些getters 可以在retrofit2 的成功回调中调用
  • @NorlihazmeyGhazali 您可以扩展类 public class User extends Lecturer 并重新定义 API Call&lt;User&gt; getLecturerByUserId 。但要小心继承。
  • @b1izzard 这种情况下的继承部分不适合。因为稍后,用户数据可能有另一个实体混合在一起。目前,只有用户数据与讲师数据混合在一起。稍后可能会与其他数据混合。

标签: java android json retrofit2


【解决方案1】:

我认为 POJO 应该是:

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

即使 JSON 中有 2 个模型,您也只需要 1 个模型来进行改造。


如果您真的想将 1 个 JSON 响应拆分为 2 个模型,我认为您必须实现自定义 JSON 转换器。

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();

【讨论】:

  • 这个 POJO 与讲师的数据混合在一起。我已经分别拥有User Lecturer 的POJO。我认为这是没有想法的。从那以后,响应数据可能包含另一个数据,因为我正在加入数据库中的表以获取每个请求的结果。是的,如果只将讲师数据与用户相结合,那么您的想法很好用。
  • 如果JSON结构是这样的话,我认为你不能使用默认的Retrofit JSON Converter。
  • 那么,我没有办法创建另一个同时包含 User 和 Lecturer 的 POJO 类吗?
  • 你可以试试下面阿里的回答。我认为这会奏效。
  • 是的,正在尝试中。无论如何感谢您的回答
【解决方案2】:

这是我用来将 long 转换为 Java Date 对象的一些代码。 据推测,您可以为您的 UserLecture 对象做同样的事情。您应该能够为 User 和 Lecture 提取单独的 json 对象,创建一个新的 UserLecture 对象并将 User 和 Lecture 作为对象。

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();

然后在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.
}

【讨论】:

  • 对不起,我是新手。我应该在哪里实现上面的代码?
  • Retrofit 使用 Gson 或其他一些 JSON 库从 json 响应构建对象。查看此处的配置部分:square.github.io/retrofit 我假设您使用了 Gson,因为这是最常见的配置,因为它比 Jackson 更小且库。
  • 我已经更新了答案以阐明如何配置 Gson。请注意,我还没有尝试过,只是感觉应该可以。如果您将对象声明为 UserLecture 类型,则应调用此反序列化方法以对其进行反序列化。
  • 是的,我使用 gson 作为转换器,转换器自动成功解析所有单个响应。但如果响应与现有 POJO 不匹配,则会卡住。我知道它是如何实现的,但在这一行出现错误User user = json.getAsJsonObject().getAsJsonObject("user"); User lecture = json.getAsJsonObject().getAsJsonObject("lecture");
  • 似乎从getAsJsonObject("user"); 获得的值返回为 Json 对象而不是用户对象。
【解决方案3】:

首先我要说的是,您需要在此处处理的 JSON 被设计破坏了,因此您应该敦促该人/部门/公司修复它。

其次,像 Jackson 这样的 JSON 处理器可以轻松解析这样的多态数据结构,但它们需要某种 type 标志来区分另一种类型(即 type: "user"type: "lecturer")。还有一种方法可以在没有此类 type 标志的情况下执行此操作,但涉及更多的手工工作。 last example here 显示了如何做到这一点。

【讨论】:

  • 感谢您的输入.. 将尝试查看它
【解决方案4】:

是的,这是一种可能的解决方案。 Gson 会忽略所有名称与 @SerializedName 注释不匹配的字段。因此,您可以尝试另一种解决方案,而无需再创建任何 pojo 类 - 以字符串形式返回结果,并尝试将此字符串解析为两个类。如果一个结果是空的 - 那么你有另一个。但是,如果两个 kbject 都不是空的,那么原始响应包含来自两个 pojo 的字段

【讨论】:

  • 所以我需要手动解析来自 API 的响应,而不是使用 POJO 类。谢谢你的想法。将尝试实施它。
  • 不,您不应该手动操作。 Gson 解析器将自动执行此操作,但是,如果未找到响应的字段名称,它将使用默认值。您可以尝试解析与 User 和 Lecturer 类相同的响应
  • 嗯,事情有点混乱。你能分享一个简单的例子吗?
猜你喜欢
  • 2014-03-28
  • 1970-01-01
  • 2018-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-15
  • 2014-03-18
  • 1970-01-01
相关资源
最近更新 更多