如何在Retrofit中处理Dynamic JSON?

  发布于 2023-01-08 17:56

我正在使用高效的网络库改造,但是我无法处理包含单个前缀的Dynamic JSON, responseMessage后者object随机responseMessage变化,在某些情况下(动态),相同的prefix()会更改为String.

Json格式responseMessage的对象:

{
   "applicationType":"1",
   "responseMessage":{
      "surname":"Jhon",
      "forename":" taylor",
      "dob":"17081990",
      "refNo":"3394909238490F",
      "result":"Received"
   }

}

responseMessage Json格式动态更改为类型字符串:

 {
       "applicationType":"4",
       "responseMessage":"Success"          
 }

对我来说问题是因为改造有内置的JSON解析我们必须为每个请求分配单个POJO!但遗憾的是,REST-API是使用动态JSON响应构建的,前缀将在成功(...)失败(...)方法中随机更改为字符串到对象!

void doTrackRef(Map paramsref2) {
    RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint("http://192.168.100.44/RestDemo").build();



    TrackerRefRequest userref = restAdapter.create(TrackerRefRequest.class);
    userref.login(paramsref2,
            new Callback() {
                @Override
                public void success(
                        TrackerRefResponse trackdetailresponse,
                        Response response) {

                    Toast.makeText(TrackerActivity.this, "Success",
                    Toast.LENGTH_SHORT).show();

                }

                @Override
                public void failure(RetrofitError retrofitError) {


                    Toast.makeText(TrackerActivity.this, "No internet",
                        Toast.LENGTH_SHORT).show();
                }


            });
}

POJO:

public class TrackerRefResponse {


private String applicationType;

    private String responseMessage;          //String type

//private ResponseMessage responseMessage;  //Object of type ResponseMessage

//Setters and Getters


}

在上面的代码中POJO TrackerRefResponse.java前缀responseMessage设置为responseMessage类型的字符串或对象,因此我们可以创建具有相同名称的ref变量的POJO(java basics :))所以我JSON在Retrofit中寻找相同的动态解决方案.我知道在具有异步任务的普通http客户端中这是非常容易的工作,但它不是REST-Api JSON解析中的最佳实践!看看性能基准总是Volley或Retrofit是最好的选择,但我失败了处理动态JSON!

我知道可能的解决方案

    使用旧的asyc任务与http客户端解析.:(

    试着说服RESTapi后端开发人员.

    创建自定义Retrofit客户端:)

Oliver Hausl.. 38

晚到派对,但你可以使用转换器.

RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint("https://graph.facebook.com")
    .setConverter(new DynamicJsonConverter()) // set your static class as converter here
    .build();

api = restAdapter.create(FacebookApi.class);

然后你使用一个静态类来实现改造的转换器:

static class DynamicJsonConverter implements Converter {

    @Override public Object fromBody(TypedInput typedInput, Type type) throws ConversionException {
        try {
            InputStream in = typedInput.in(); // convert the typedInput to String
            String string = fromStream(in);
            in.close(); // we are responsible to close the InputStream after use

            if (String.class.equals(type)) {
                return string;
            } else {
                return new Gson().fromJson(string, type); // convert to the supplied type, typically Object, JsonObject or Map
            }
        } catch (Exception e) { // a lot may happen here, whatever happens
            throw new ConversionException(e); // wrap it into ConversionException so retrofit can process it
        }
    }

    @Override public TypedOutput toBody(Object object) { // not required
        return null;
    }

    private static String fromStream(InputStream in) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder out = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            out.append(line);
            out.append("\r\n");
        }
        return out.toString();
    }
}

我编写了这个示例转换器,因此它以String,Object,JsonObject或Map 的形式返回Json响应.显然并非所有的返回类型都适用于每个Json,并且肯定有改进的余地.但它演示了如何使用Converter将几乎任何响应转换为动态Json.

6 个回答
  • 晚到派对,但你可以使用转换器.

    RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint("https://graph.facebook.com")
        .setConverter(new DynamicJsonConverter()) // set your static class as converter here
        .build();
    
    api = restAdapter.create(FacebookApi.class);
    

    然后你使用一个静态类来实现改造的转换器:

    static class DynamicJsonConverter implements Converter {
    
        @Override public Object fromBody(TypedInput typedInput, Type type) throws ConversionException {
            try {
                InputStream in = typedInput.in(); // convert the typedInput to String
                String string = fromStream(in);
                in.close(); // we are responsible to close the InputStream after use
    
                if (String.class.equals(type)) {
                    return string;
                } else {
                    return new Gson().fromJson(string, type); // convert to the supplied type, typically Object, JsonObject or Map<String, Object>
                }
            } catch (Exception e) { // a lot may happen here, whatever happens
                throw new ConversionException(e); // wrap it into ConversionException so retrofit can process it
            }
        }
    
        @Override public TypedOutput toBody(Object object) { // not required
            return null;
        }
    
        private static String fromStream(InputStream in) throws IOException {
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder out = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                out.append(line);
                out.append("\r\n");
            }
            return out.toString();
        }
    }
    

    我编写了这个示例转换器,因此它以String,Object,JsonObject或Map <String,Object>的形式返回Json响应.显然并非所有的返回类型都适用于每个Json,并且肯定有改进的余地.但它演示了如何使用Converter将几乎任何响应转换为动态Json.

    2023-01-08 17:57 回答
  • RestClient.java

    import retrofit.client.Response;
    public interface RestClient {
      @GET("/api/foo") Response getYourJson();
    }
    

    YourClass.java

    RestClient restClient;
    
    // create your restClient
    
    Response response = restClient.getYourJson();
    
    Gson gson = new Gson();
    String json = response.getBody().toString();
    if (checkResponseMessage(json)) {
      Pojo1 pojo1 = gson.fromJson(json, Pojo1.class);
    } else {
      Pojo2 pojo2 = gson.fromJson(json, Pojo2.class);
    }
    

    您必须实现"checkResponseMessage"方法.

    2023-01-08 17:57 回答
  • 接受的答案对我来说似乎过于复杂,我这样解决:

    Call<ResponseBody> call = client.request(params);
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Response<ResponseBody> response) {
            if (response.isSuccess()) {
                Gson gson = new Gson();
                ResponseBody repsonseBody = response.body().string();
                if (isEmail) {
                    EmailReport reports = gson.fromJson(responseBody, EmailReport.class);
                } else{
                    PhoneReport reports = gson.fromJson(repsonseBody, PhoneReport.class);
                }
            }
        }
        @Override
        public void onFailure(Throwable t) {
            Log.e(LOG_TAG, "message =" + t.getMessage());
        }
    });
    

    这只是一个示例,试图向您展示如何使用不同的模型.

    变量isEmail只是您使用适当模型的条件的布尔值.

    2023-01-08 17:59 回答
  • 使用gson-converter以下方法尝试自定义反序列化(Retrofit 2.0的更新答案)

    创建三个模型,如下所示

    ResponseWrapper此类

    public class ResponseWrapper {
    
        @SerializedName("applicationType")
        @Expose
        private String applicationType;
        @SerializedName("responseMessage")
        @Expose
        private Object responseMessage;
    
        public String getApplicationType() {
            return applicationType;
        }
    
        public void setApplicationType(String applicationType) {
            this.applicationType = applicationType;
        }
    
        public Object getResponseMessage() {
            return responseMessage;
        }
    
        public void setResponseMessage(Object responseMessage) {
            this.responseMessage = responseMessage;
        }
    
    }
    

    ResponseMessage

    public class ResponseMessage extends ResponseWrapper {
    
    @SerializedName("surname")
    @Expose
    private String surname;
    @SerializedName("forename")
    @Expose
    private String forename;
    @SerializedName("dob")
    @Expose
    private String dob;
    @SerializedName("refNo")
    @Expose
    private String refNo;
    @SerializedName("result")
    @Expose
    private String result;
    
    public String getSurname() {
        return surname;
    }
    
    public void setSurname(String surname) {
        this.surname = surname;
    }
    
    public String getForename() {
        return forename;
    }
    
    public void setForename(String forename) {
        this.forename = forename;
    }
    
    public String getDob() {
        return dob;
    }
    
    public void setDob(String dob) {
        this.dob = dob;
    }
    
    public String getRefNo() {
        return refNo;
    }
    
    public void setRefNo(String refNo) {
        this.refNo = refNo;
    }
    
    public String getResult() {
        return result;
    }
    
    public void setResult(String result) {
        this.result = result;
    }
    
    }
    

    ResponseString

    public class ResponseString extends ResponseWrapper {
    
    }
    

    UserResponseDeserializer(自定义反序列化器)

    public class UserResponseDeserializer implements JsonDeserializer<ResponseWrapper> {
    @Override
    public ResponseWrapper deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    
    
            if (((JsonObject) json).get("responseMessage") instanceof JsonObject){
                return new Gson().fromJson(json, ResponseMessage.class);
            } else {
                return new Gson().fromJson(json, ResponseString.class);
            }
    
    }
    }
    

    改造2.0实施

    Gson userDeserializer = new GsonBuilder().setLenient().registerTypeAdapter(ResponseWrapper.class, new UserResponseDeserializer()).create();
    
    
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("base_url")
                .addConverterFactory(GsonConverterFactory.create(userDeserializer))
                .build();
    
    
        UserService request = retrofit.create(UserService.class);
        Call<ResponseWrapper> call1=request.listAllUsers();
    
        call1.enqueue(new Callback<ResponseWrapper>() {
            @Override
            public void onResponse(Call<ResponseWrapper> call, Response<ResponseWrapper> response) {
                ResponseWrapper responseWrapper=response.body();
                Log.i("DYNAMIC RESPONSE", String.valueOf(response.body().getResponseMessage()));
            }
    
            @Override
            public void onFailure(Call<ResponseWrapper> call, Throwable t) {
            }
        });
    

    使用的库

    编译'com.squareup.retrofit2:改造:2.3.0'

    编译'com.squareup.retrofit2:converter-gson:2.3.0'

    ***** 上一个答案(以上答案更推荐一个)*****

    像这样改变你的pojo

    public class TrackerRefResponse {
    
      private String applicationType;
      private Object responseMessage;
    
      public Object getResponseMessage() {
      return responseMessage;
      }
    
      public void setResponseMessage(Object responseMessage) {
      this.responseMessage = responseMessage;
     }
    }
    

    并像这样改变改造的onResponse

     @Override
    public void onResponse(Response<TrackerRefResponse > response) {
        if (response.isSuccess()) {
            if (response.getResponseMessage() instanceof String)
                {
                handleStringResponse();
             }
            else 
                {
                handleObjectResponse();
             }
        }
    }
    

    您还可以查看此帖子,了解有关动态json解析的更多详细信息

    2023-01-08 17:59 回答
  • 我知道我参加聚会非常晚了.我遇到了类似的问题,就这样解决了:

    public class TrackerRefResponse {
    
        private String applicationType;
        // Changed to Object. Works fine with String and array responses.
        private Object responseMessage;
    
    }
    

    我只是改为键入到Object.我选择这种方法是因为响应中只有一个字段是动态的(对我而言,我的响应更复杂),因此使用转换器会使生活变得困难.使用Gson从那里使用Object,具体取决于它是String还是Array值.

    希望这有助于寻找简单答案的人:).

    2023-01-08 17:59 回答
  • 任何可能的解决方案都可行.你还可以做的是将Retrofit api接口返回类型发送到响应.通过该响应,您将获得一个Inputstream可以转换为JSON对象并按您认为合适的方式读取的主体.

    请看:http://square.github.io/retrofit/#api-declaration - 在RESPONSE OBJECT TYPE下

    更新

    Retrofit 2现已推出,并对文档和库进行了一些更改.

    查看http://square.github.io/retrofit/#restadapter-configuration,可以使用请求和响应正文对象.

    2023-01-08 18:00 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有