我正在使用改造高效的网络库,但我无法处理包含单个前缀responseMessage
的动态JSON,其随机更改为object
,相同的前缀(responseMessage
)更改在某些情况下(动态)字符串。
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<String, String> 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<TrackerRefResponse>() {
@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 :))所以我正在寻找相同的解决方案对于Retrofit中的动态JSON
。
我知道在具有异步任务的普通http客户端中这是非常容易的工作,但它不是REST-Api JSON
解析中的最佳实践!看着性能Benchmarks总是Volley或Retrofit是最好的选择,但我失败了处理动态JSON
!
我知道的可能解决方案
使用旧的asyc任务进行http客户端解析。 :(
尝试说服RESTapi后端开发人员。
创建自定义Retrofit客户端:)
答案 0 :(得分:36)
晚会,但你可以使用转换器。
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();
}
}
我编写了这个示例转换器,因此它返回Json响应,如String,Object,JsonObject或Map&lt;字符串,对象&gt;。显然并非所有的返回类型都适用于每个Json,并且肯定有改进的余地。但它演示了如何使用Converter将几乎任何响应转换为动态Json。
答案 1 :(得分:19)
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”方法。
答案 2 :(得分:13)
使用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();
}
}
}
答案 3 :(得分:10)
任何可能的解决方案都可行。你还可以做的是将Retrofit api接口返回类型发送到响应。通过该响应,您将获得一个正文Inputstream
,您可以将其转换为JSON对象并按您认为合适的方式阅读。
查看:http://square.github.io/retrofit/#api-declaration - 在RESPONSE OBJECT TYPE
下更新
Retrofit 2现已推出,并对文档和库进行了一些更改。
查看http://square.github.io/retrofit/#restadapter-configuration是否有可以使用的请求和响应正文对象。
答案 4 :(得分:9)
接受的答案对我来说似乎过于复杂,我这样解决:
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
只是您使用适当模型的条件的布尔值。
答案 5 :(得分:6)
我知道我参加聚会非常晚了。我遇到了类似的问题,就这样解决了:
public class TrackerRefResponse {
private String applicationType;
// Changed to Object. Works fine with String and array responses.
private Object responseMessage;
}
我只是改为输入到Object。我选择这种方法是因为响应中只有一个字段是动态的(对我而言,我的响应更复杂),因此使用转换器会使生活变得困难。使用Gson从那里使用Object,具体取决于它是String还是Array值。
希望这有助于寻找简单答案的人:)。
答案 6 :(得分:3)
如果无法更改后端API,我会考虑以下变体(如果使用Gson转换JSON)。
我们可以使用Gson type adapters为ResponseMessage
类型创建一个自定义适配器,动态决定如何解析inoming JSON(使用if (reader.peek() == JsonToken.STRING)
之类的东西)。
将一些描述响应类型的元信息放入HTTP标头中,并使用它来确定必须向Gson实例提供哪些类型信息。
答案 7 :(得分:1)
除了你所说的 -
使用回调 然后,您可以使用常规get方法检索字段。 有关更多信息,请浏览gson的javadoc。
http://google-gson.googlecode.com/svn/tags/1.2.3/docs/javadocs/com/google/gson/JsonObject.html
答案 8 :(得分:0)
我也遇到了这个问题。 但是我不确定这是否是您的情况,(我正在使用Retrofit2)
我需要处理错误和成功消息。
成功
{
"call_id": 1,
"status": "SUCCESS",
"status_code": "SUCCESS",
"result": {
"data1": {
"id": "RFP2UjW7p8ggpMXzYO9tRg==",
"name": "abcdef",
"mobile_no": "96655222",
"email": ""
},
"data2": [
{
"no": "12345"
},
{
"no": "45632"
}
]
}
}
出错时,
{
"call_id": 1,
"status": "FAILED",
"status_code": "NO_RECORDS",
"error": {
"error_title": "xxx",
"error_message": "details not found"
}
}
为此,我刚刚创建了另一个POJO Error
,
public class ValidateUserResponse {
@SerializedName("call_id")
public String callId;
@SerializedName("status")
public String status;
@SerializedName("status_code")
public String statusCode;
@SerializedName("result")
public ValidateUserResult result;
@SerializedName("error")
public Error error;
}
Error.java
public class Error {
@SerializedName("error_title")
public String errorTitle;
@SerializedName("error_message")
public String errorMessage;
}
ValidateUser.java
public class ValidateUserResult {
@SerializedName("auth_check")
public String authCheck;
@SerializedName("data1")
public Data1 data1;
@SerializedName("data2")
public List<Data2> data2;
}
在上述情况下,如果json上的result
键包含data1,data2,则ValidateUserResult.java
会被初始化。
如果出错,则Error.java
类将被初始化。
答案 9 :(得分:0)
我知道我来晚了,但我只想分享自己的想法。我在一个正在编写方法的项目中工作。该方法使用改造从服务器获取数据。由于公司中的其他开发人员将使用此方法,因此无法使用POJO
类(在您的示例中为TrackerRefResponse
类)。所以我这样使用JsonObject
/ Object
:
public class APIService{
@FormUrlEncoded
@POST
Call<JsonObject> myPostMethod(@Url String url, @Field("input") String input);
}
然后在我的方法中,我这样写:
Call<JsonObject> call = RetrofitClient.getAPIService().establishUserSession(post_request_url, someParameter);
call.enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
JsonObject jsonObject = response.body();
String jsonString = response.body().toString();
// then do your stuff. maybe cast to object using a factory pattern
}
// rest of the code
}
您也可以使用Object
代替'JsonObject`。稍后,当您知道响应的类型时,也许可以将其转换为所需的对象。
答案 10 :(得分:0)
看看它对我有用的其他选项:-
杰森
1.
{
"applicationType":"1",
"responseMessage":
{
"surname":"Jhon",
"forename":" taylor",
"dob":"17081990",
"refNo":"3394909238490F",
"result":"Received"
}
}
2.
{
"applicationType":"4",
"responseMessage":
{
"forename":" taylor",
"dob":"17081990",
}
}
3.
{
"applicationType":"5",
"responseMessage":
{
"refNo":"3394909238490F",
"result":"Received"
}
}
public class ResponseMessage
{
private String surname;
private String forename;
private String dob;
private String refNo;
private String result;
public void setSurname(String surname){
this.surname = surname;
}
public String getSurname(){
return this.surname;
}
public void setForename(String forename){
this.forename = forename;
}
public String getForename(){
return this.forename;
}
public void setDob(String dob){
this.dob = dob;
}
public String getDob(){
return this.dob;
}
public void setRefNo(String refNo){
this.refNo = refNo;
}
public String getRefNo(){
return this.refNo;
}
public void setResult(String result){
this.result = result;
}
public String getResult(){
return this.result;
}
}
public class Root
{
private String applicationType;
private ResponseMessage responseMessage;
public void setApplicationType(String applicationType){
this.applicationType = applicationType;
}
public String getApplicationType(){
return this.applicationType;
}
public void setResponseMessage(ResponseMessage responseMessage){
this.responseMessage = responseMessage;
}
public ResponseMessage getResponseMessage(){
return this.responseMessage;
}
}
现在是最终代码
if(responseMessage.getSurname() !=null){
---do something---
}
if(responseMessage.getForename !=null){
----do something
}
if(responseMessage.getDob() !=null){
---do something---
}
if(responseMessage.getRefNo() !=null){
---do something---
}
if(responseMessage.getResult() !=null){
---do something---
}