我正在使用高效的网络库改造,但是我无法处理包含单个前缀的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(Mapparamsref2) { 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
晚到派对,但你可以使用转换器.
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.
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"方法.
接受的答案对我来说似乎过于复杂,我这样解决:
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
只是您使用适当模型的条件的布尔值.
使用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解析的更多详细信息
我知道我参加聚会非常晚了.我遇到了类似的问题,就这样解决了:
public class TrackerRefResponse { private String applicationType; // Changed to Object. Works fine with String and array responses. private Object responseMessage; }
我只是改为键入到Object.我选择这种方法是因为响应中只有一个字段是动态的(对我而言,我的响应更复杂),因此使用转换器会使生活变得困难.使用Gson从那里使用Object,具体取决于它是String还是Array值.
希望这有助于寻找简单答案的人:).
任何可能的解决方案都可行.你还可以做的是将Retrofit api接口返回类型发送到响应.通过该响应,您将获得一个Inputstream
可以转换为JSON对象并按您认为合适的方式读取的主体.
请看:http://square.github.io/retrofit/#api-declaration - 在RESPONSE OBJECT TYPE下
更新
Retrofit 2现已推出,并对文档和库进行了一些更改.
查看http://square.github.io/retrofit/#restadapter-configuration,可以使用请求和响应正文对象.