How to fix "Expected BEGIN_OBJECT but was BEGIN_ARRAY"? - java

I'm sending an HTTP request using Retrofit 2, I've done everything regularly, however, the situation is "not standard". I have a problem that one of the objects to receive in the response class is once sent as an object and in the other as a list. So I don't know whether to initialize it in the response class as an object or as an array.
Here is my full JSON response:
{
"data": [
{
"name": "John",
"surname": "Smith",
"nicname": "Joe",
"age": "32",
"description": "Example",
"state": "Nevada",
"city": "Las Vegas",
"job": "Security",
"adress": "Some adress 1",
"postcode": "412421",
"details": {
"intro": {
"title": "Mr.",
"married": "No",
"children": "2"
},
"rest": {
"pitctures":"24",
"chats": "7",
"lastChat": "12-01-2016",
"lastVisited": "07-04-2017",
}
}
},
{
"name": "John",
"surname": "Smith",
"nicname": "Joe",
"age": "32",
"description": "Example",
"state": "Nevada",
"city": "Las Vegas",
"job": "Security",
"adress": "Some adress 1",
"postcode": "412421",
"details": {
"intro": {
"title": "Mr.",
"married": "No",
"children": "No"
},
"rest": []
}
}
],
"errors": false,
"update_notifications": {
"message": [],
"friend_request": [],
"code": "IzS0hivN1cyHBdygpeWv"
}
}
Details.java class:
public class Details {
#SerializedName("intro")
#Expose
private Intro intro;
#SerializedName("rest")
#Expose
private Rest restObject;
private ArrayList<Rest> restList;
public Details(Intro intro, Rest restObject) {
this.intro = intro;
this.restObject = restObject;
}
public Details(Intro intro, ArrayList<Rest> restList) {
this.intro = intro;
this.restList = restList;
}
public Intro getIntro() {
return intro;
}
public void setIntro(Intro intro) {
this.intro = intro;
}
public Rest getRestObject() {
return restObject;
}
public void setRestObject(Rest restObject) {
this.restObject = restObject;
}
public ArrayList<Rest> getRestList() {
return restList;
}
public void setRestList(ArrayList<Rest> restList) {
this.restList = restList;
}
}
And here is my CustomDeserializer.java (rest array neeed to be empty, maybe that's a problem) based on #Farid's answer:
public class CustomDeserializer implements JsonDeserializer<Details> {
#Override
public Details deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject detailsObject = json.getAsJsonObject().get("details").getAsJsonObject();
Details details;
JsonObject introObject = detailsObject.get("intro").getAsJsonObject();
String title = introObject.get("title").getAsString();
String married = introObject.get("married").getAsString();
String children = introObject.get("children").getAsString();
try {
JsonObject restObject = detailsObject.get("rest").getAsJsonObject();
String pitctures = restObject.get("pitctures ").getAsString();
String chats = restObject.get("chats ").getAsString();
String lastChat = restObject.get("lastChat ").getAsString();
String lastVisited = restObject.get("lastVisited ").getAsString();
details = new Details(new Intro(title, married, children),
new Rest(pitctures, chats, lastChat, lastVisited));
}catch (IllegalStateException e){
JsonArray restArray = detailsObject.get("rest").getAsJsonArray();
ArrayList<Rest> restList = new ArrayList<>();
details = new Details(new Intro(title, married, children), restList);
}
return details;
}
}
In MainActivity based on #Farid's answer:
Gson gsonConverter = new GsonBuilder().registerTypeAdapter(Details.class, new CustomDeserializer()).create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(myUrl)
.addConverterFactory(GsonConverterFactory.create(gsonConverter))
.build();
service1 = retrofit.create(MyAPI.class);
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setMessage("Please wait!");
progressDialog.show();
final MyRequest myRequest = new MyRequest();
myRequest.setPin(pin);
final Call<MyResponse> myResponseCall = service1.get (code, myRequest);
myResponseCall.enqueue(new Callback<MyResponse>() {
#Override
public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
}
});

It's possible. You'll have to create a custom Deserializer. As you can see there is JsonDeserializer<Details> whose type parameter is Details that means any time GSON tries to deserialize Details object, it will call CustomDeserializer to deserialize it. Anything inside Details object should be deserialized manually as seen in the CustomDeserializer class whereas all other types outside Details class (e.g. Class, String, int) will be handled by GSON seamlessly
CustomDeserializer.java
public class CustomDeserializer implements JsonDeserializer<Details> {
#Override
public Details deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject detailsObject = json.getAsJsonObject();
Details details;
Intro intro = new Intro(detailsObject.get("intro").getAsJsonObject().get("example").getAsString());
try {
JsonObject restObject = detailsObject.get("rest").getAsJsonObject();
String example = restObject.get("example").getAsString();
details = new Details(intro, new Rest(example));
}catch (IllegalStateException e){ // In case rest is ArrayList
JsonArray restArray = detailsObject.get("rest").getAsJsonArray();
ArrayList<Rest> resList = new ArrayList<>();
for (JsonElement element: restArray){
JsonObject restObject = element.getAsJsonObject();
String example = restObject.get("example").getAsString();
resList.add(new Rest(example));
}
details = new Details(intro, resList);
}
return details;
}
}
Then you have to register CustomDeserializer as TypeAdapter as below:
Gson gsonConverter = GsonBuilder().registerTypeAdapter(Details::class.java,
CustomDeserializer()).create();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gsonConverter))
///Rest of Retrofit builder code
If you want to know more about custom deserialization, search for "gson deserialization" and find a tutorial that appeals to you most.
Below code snippets are OP specific classes
Response.java
public class Response {
private List<DataItem> data = null;
private Boolean errors;
private String example;
public List<DataItem> getData() {
return data;
}
public void setData(List<DataItem> data) {
this.data = data;
}
public Boolean getErrors() {
return errors;
}
public void setErrors(Boolean errors) {
this.errors = errors;
}
public String getExample() {
return example;
}
public void setExample(String example) {
this.example = example;
}
}
Data.java
public class DataItem {
private String example;
private Details details;
public String getExample() {
return example;
}
public void setExample(String example) {
this.example = example;
}
public Details getDetails() {
return details;
}
public void setDetails(Details details) {
this.details = details;
}
}
Details.java
public class Details {
private Intro intro;
private Rest restObject;
private ArrayList<Rest> restList;
public Details(Intro intro, ArrayList<Rest> restList) {
this.intro = intro;
this.restList = restList;
}
public Details(Intro intro, Rest restObject) {
this.intro = intro;
this.restObject = restObject;
}
public Rest getRestObject() {
return restObject;
}
public ArrayList<Rest> getRestList() {
return restList;
}
public Intro getIntro() {
return intro;
}
public void setIntro(Intro intro) {
this.intro = intro;
}
}
Intro.java
public class Intro {
public Intro(String example) {
this.example = example;
}
private String example;
public String getExample() {
return example;
}
public void setExample(String example) {
this.example = example;
}
}
Rest.java
public class Rest {
private String example;
public Rest(String example) {
this.example = example;
}
public String getExample() {
return example;
}
}

Related

how can I work with wrapped data using moshi, retrofit and java?

I'm working with an API where all data are wrapped in a custom object (see below), so I cannot use moshi to convert the retrofit body direct to my models. What is the best way to work with moshi in this case?
#COLLECTIONS ENDPOINT
{
"status": 200,
"data": [
{
"id": 28122,
"name": "Abandonei",
"counts": {
"books": 3
}
},
{
"id": 21091,
"name": "Lendo",
"counts": {
"books": 6
}
},
],
"errors": [],
"pagination": {
"after": 2,
"hasNextPage": true
}
}
The same json structure is used in all api endpoints, the default fields are:
{
"status": 200,
"data": [],
"errors": [],
"pagination": {
"after": 1,
"hasNextPage": true
}
}
My Collection model:
public class BookCollection {
public long id;
public String name;
public ArrayList<Book> books;
public BookCollection(long id, String name) {
this.id = id;
this.name = name;
}
}
To avoid create a parent class to each model, I have implemented a way to use a class that receive a generic type.
To put this to work I've changed the Moshi class to Gson.
My model:
public class BookCollection {
public long id;
public String name;
public ArrayList<Book> books;
public BookCollection(long id, String name) {
this.id = id;
this.name = name;
}
}
The wrapper class used to unwrap the json data:
public class ApiWrapper<T> {
public final int status;
public final T data;
public final List<ApiError> errors = new ArrayList<>();
public ApiWrapper(int status, T data, List<ApiError> errors) {
this.status = status;
this.data = data;
this.errors.addAll(errors);
}
}
The Errors class, referenced in the class above:
public class ApiError {
public int code;
public String message;
public String error;
}
Usage:
public interface NetAPI {
#GET("me/collections")
Call<ResponseBody> getCollections(#Header("Authorization") String auth);
}
public class CollectionViewModel extends ViewModel {
private final MutableLiveData<List<Collection>> collections = new MutableLiveData<>();
private final MutableLiveData<Boolean> loading = new MutableLiveData<>();
private final MutableLiveData<Boolean> collectionError = new MutableLiveData<>();
private Call<ResponseBody> call;
private void fetchCollections() {
loading.setValue(true);
call = Api.getInstance().getCollections(TOKEN);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
collectionError.setValue(false);
//THE SECRET
Gson gson = new Gson();
ApiWrapper<List<Collection>> apiResponse = null;
apiResponse = gson.fromJson(response.body().string(), new TypeToken<ApiWrapper<List<Collection>>>(){}.getType());
collections.setValue(apiResponse.data);
loading.setValue(false);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e(getClass().getSimpleName(), "Error loading data", t);
collectionError.setValue(true);
loading.setValue(false);
}
});
}
}
At this way I can reuse my ApiWrapper class to any model (Books, Users, Login, etc).
Thanks.
You will need to setup gson/moshi to use your classes that you have created for the json to object mapping. Here is an example of what those java classes would look like. You can use data classes in kotlin as well. For moshi, you will have to create the adapter to help with the json to object mapping.
publci class CollectionResponse {
public int status;
public List<BookCollection> data;
public List<Error> errors;
public Pagination pagination;
}
public class Pagination {
public int after;
public boolean hasNextPage;
}
public class BookCollection {
public long id;
public String name;
public Count counts;
}
public Count {
public int books;
}
public class Error {
}

Not able to display the Data using retrofit library

I am new to retrofit my aim is to display the data from a url using the retrofit library.
My Json data is:
`{
"RestResponse": {
"messages": [
"Total [249] records found."
],
"result": [
{
"name": "Afghanistan",
"alpha2_code": "AF",
"alpha3_code": "AFG"
},
{
"name": "��land Islands",
"alpha2_code": "AX",
"alpha3_code": "ALA"
},
{
"name": "Albania",
"alpha2_code": "AL",
"alpha3_code": "ALB"
},
{
"name": "Algeria",
"alpha2_code": "DZ",
"alpha3_code": "DZA"
},`
I would like to display the names of country in the LogCat and here are the gson converted Pojo classes
public class RestResponse {
#SerializedName("messages")
#Expose
private List<String> messages = null;
#SerializedName("result")
#Expose
private List<Result> result = null;
public List<String> getMessages() {
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
public List<Result> getResult() {
return result;
}
public void setResult(List<Result> result) {
this.result = result;
}
}
Second one Result.java:
public class Result {
#SerializedName("name")
#Expose
private String name;
#SerializedName("alpha2_code")
#Expose
private String alpha2Code;
#SerializedName("alpha3_code")
#Expose
private String alpha3Code;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAlpha2Code() {
return alpha2Code;
}
public void setAlpha2Code(String alpha2Code) {
this.alpha2Code = alpha2Code;
}
public String getAlpha3Code() {
return alpha3Code;
}
public void setAlpha3Code(String alpha3Code) {
this.alpha3Code = alpha3Code;
}
}
and Finally Movies.java //Example.java generated by Gson Converter:
public class Movies {
#SerializedName("RestResponse")
#Expose
private RestResponse restResponse;
public RestResponse getRestResponse() {
return restResponse;
}
public void setRestResponse(RestResponse restResponse) {
this.restResponse = restResponse;
}
}
From the above classes I am trying to retrieve the data. My RetrofitInstance is:
public class RetrofitInstance {
private static Retrofit retrofit = null;
private static String BASE_URL = "http://services.groupkt.com/";
public static ApiEndpoints getCombine() {
if (retrofit == null) {
retrofit = new Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit.create(ApiEndpoints.class);
}
}
and Endpoints Interface is:
public interface ApiEndpoints {
#GET("country/get/all")
Call<Movies> getResults();
}
and In MainActivity is used the following:
ApiEndpoints getCountryDataService= RetrofitInstance.getCombine();
Call<Movies> call=getCountryDataService.getResults();
call.enqueue(new Callback<Movies>() {
#Override
public void onResponse(Call<Movies> call, Response<Movies> response) {
Movies info=response.body();
if(info !=null && info.getRestResponse() != null){
results=(ArrayList<Result>) info.getRestResponse().getResult();
for(Result r:results){
Log.i("testing123","*********************************"+ r.getName());
}
}
}
#Override
public void onFailure(Call<Movies> call, Throwable t) {
Log.i("Error",t.fillInStackTrace()+"s");
t.fillInStackTrace();
}
});
Finally I am not able to print the countries in the Log. I am getting the following Error like
java.net.UnknownServiceException: CLEARTEXT communication to services.groupkt.com not permitted by network security policys
and iam new to retrofit concept.
Please help
Thanks in Advance.
I solved my problem by reducing the gradle version from
classpath 'com.android.tools.build:gradle:3.1.4'
to
classpath 'com.android.tools.build:gradle:3.1.2'

Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 5921 path $.data[5].courier.data

I have this model object Courier :
public class Courier {
#SerializedName("data")
private List<User> data = null;
public Courier() {
}
public Courier(List<User> data) {
this.data = data;
}
public List<User> getData() {
return data;
}
public void setData(List<User> data) {
this.data = data;
}
}
I get this response from server:
{
"data": [
{
"id": 446,
"courier": {
"data": []
},
"title": "гром",
"description": "Логойский тракт 24 в России в начале следующей",
"departure": "ChIJPQKUckNv2UYRLr1NasgXZ08",
"arrival": "EkHQodC10YDQtdCx0YDRj9C90YvQuSDQv9C10YDQtdGD0LvQvtC6LCDQnNC-0YHQutCy0LAsINCg0L7RgdGB0LjRjw"
},
{
"id": 438,
"courier": {
"data": []
},
"title": "тест",
"description": "гппг лмш ш ш ш ш г У меня на сковородке стоит ли брать сва в кино мы все равно обсуждаем",
"departure": "ChIJH10nmDnP20YR-n7Kq6Whd5w",
"arrival": "Ej_QnNC-0YHQutCy0L7RgNC10YbQutCw0Y8g0YPQu9C40YbQsCwg0JzQvtGB0LrQstCwLCDQoNC-0YHRgdC40Y8"
},
{
"id": 439,
"courier": {
"data": []
},
"title": "лаьаьаат",
"description": "лала слат алс ал ала ал кща да аьад",
"departure": "ChIJH7D4cTnP20YRKlzSCnP6Mak",
"arrival": "Ej_QnNC-0YHQutCy0L7RgNC10YbQutCw0Y8g0YPQu9C40YbQsCwg0JzQvtGB0LrQstCwLCDQoNC-0YHRgdC40Y8"
},
{
"id": 442,
"courier": {
"data": {
"id": 122,
"email": null,
"phone": "73339999999",
"photo": null,
"rating": 0
}
},
"title": "картошечка",
"description": "Крупная сортированная",
"departure": "ChIJnZRv1jnP20YRWiezW55d1tA",
"arrival": "ChIJpfH6UJtp1EYRlhM20g-jzF4"
}
]
}
If object courier not have data, i get array "data": [], if object courier has data, i get object :
"courier": {
"data": {
"id": 122,
"email": null,
"phone": "73339999999",
"photo": null,
"rating": 0
}
}
And then I get error... Please give me advice how handle this case in android application...
is one of the most common mistakes when you start to use JSON with a client, for android please refer to this tutorial to understand
the best source to understand this kind of mistake is to read this post
a canonical SO post.
Is better to read it and understand it, that asking for a simple solution because you will go really often into this error.
while deserializing, Gson was expecting a JSON object, but found a
JSON array
A JSON Object is wrapped by a {
A JSON Array is wrapped by a [
What you need is to adapt your class Courier, to deserialize in the right way the JSON response.
take in mind that; a JSON array become deserialized in java as a Collection type or an array type;
PLEASE notice that is confusing to use two times data
on top of everything, the first data is
public class MyPojo
{
private Data[] data;
public Data[] getData ()
{
return data;
}
public void setData (Data[] data)
{
this.data = data;
}
#Override
public String toString()
{
return "ClassPojo [data = "+data+"]";
}
}
Data.class
public class Data
{
private String id;
private String title;
private String description;
private Courier courier;
private String arrival;
private String departure;
public String getId ()
{
return id;
}
public void setId (String id)
{
this.id = id;
}
public String getTitle ()
{
return title;
}
public void setTitle (String title)
{
this.title = title;
}
public String getDescription ()
{
return description;
}
public void setDescription (String description)
{
this.description = description;
}
public Courier getCourier ()
{
return courier;
}
public void setCourier (Courier courier)
{
this.courier = courier;
}
public String getArrival ()
{
return arrival;
}
public void setArrival (String arrival)
{
this.arrival = arrival;
}
public String getDeparture ()
{
return departure;
}
public void setDeparture (String departure)
{
this.departure = departure;
}
#Override
public String toString()
{
return "ClassPojo [id = "+id+", title = "+title+", description = "+description+", courier = "+courier+", arrival = "+arrival+", departure = "+departure+"]";
}
}
Courier.class
public class Courier
{
private String[] data;
public String[] getData ()
{
return data;
}
public void setData (String[] data)
{
this.data = data;
}
#Override
public String toString()
{
return "ClassPojo [data = "+data+"]";
}
}
I suggest you just to create a class Data with fields id, email, etc. And make field Data data in the class Courier instead of a List<> data
EDIT: then you can use a JsonDeserializer. Just remove #SerializedName("data") over the Data field, so that the Json will not parse this field. Then create a class:
public class CourierDeserializer implements JsonDeserializer<Courier> {
#Override
public Courier deserialize(final JsonElement json, final Type type,
final JsonDeserializationContext context) {
Courier result = new Gson().fromJson(json, Courier.class);
try {
if (json != null) {
result.setData((Data) context.deserialize(json, Data.class));
}
} catch (JsonParseException e) {
result.setData(null);
}
return result;
}
}
and finally register it where you create your GsonBuilder:
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(Courier.class, new CourierDeserializer());
mGson = gson.create();
builder.setConverter(new GsonConverter(mGson));
if you use Retrofit.

Map JSON to Java object

I have these type of JSON object which I'm getting from gridx filter expression:
{
"op": "or",
"data": [
{
"op": "contain",
"data": [
{
"op": "string",
"data": "id",
"isCol": true
},
{
"op": "string",
"data": "sdfv"
}
]
},
{
"op": "contain",
"data": [
{
"op": "string",
"data": "post",
"isCol": true
},
{
"op": "string",
"data": "sdfv"
}
]
},
{
"op": "contain",
"data": [
{
"op": "string",
"data": "birthday",
"isCol": true
},
{
"op": "string",
"data": "sdfv"
}
]
}
]
}
How I can map this to a Java object and then deserialize using Gson?
I've made these two classes:
package dto.Filter;
public class FilterData extends FilterExpression {
private String op;
private boolean isCol;
private String data;
public String getOp() {
return op;
}
public void setOp(String op) {
this.op = op;
}
public boolean isCol() {
return isCol;
}
public void setCol(boolean col) {
isCol = col;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
package dto.Filter;
import java.util.List;
public class FilterExpression {
private List<FilterData> filters;
private String op;
public List<FilterData> getFilters() {
return filters;
}
public void setFilters(List<FilterData> filters) {
this.filters = filters;
}
public String getOp() {
return op;
}
public void setOp(String op) {
this.op = op;
}
}
The problem is that I have both data as Object and String type. Do I need to use my custom TypeAdapter?
Make your data structure as
class DataStructure {
private String op;
private String data;
private String isCol;
public DataStructure(){
op="";
data="";
isCol="";
}
public String getOp() {
return op;
}
public void setOp(String op) {
this.op = op;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String isCol() {
return isCol;
}
public void setCol(String isCol) {
this.isCol = isCol;
}
#Override
public String toString() {
return "DataStructure [op=" + op + ", data=" + data + ", isCol=" + isCol + "]";
}
}
I have parse the JSON file using google GSON library. Here is maven repository.
Note: to read using GSON library add '[' at starting and ']' at ending.
I have read the JSON file and store the data in ArrayList. Hope after getting array list you can do serialization.
public class FilterData {
private static Gson gson = new Gson();
private static JsonParser parser = new JsonParser();
public static List<DataStructure> getData(List<DataStructure> datas){
List<DataStructure> result = new ArrayList<>();
for (DataStructure data : datas) {
for (JsonElement object : parser.parse(data.getData()).getAsJsonArray()) {
DataStructure dataStructure = new DataStructure();
JsonObject jObject = gson.fromJson(object, JsonObject.class);
dataStructure.setOp(jObject.get("op").toString());
dataStructure.setData(jObject.get("data").toString());
if (jObject.has("isCol"))
dataStructure.setData(jObject.get("isCol").toString());
System.out.println(dataStructure);
result.add(dataStructure);
}
}
return result;
}
public static void main(String[] args) throws FileNotFoundException {
JsonReader reader = new JsonReader(new InputStreamReader(new FileInputStream("input.json")));
List<DataStructure> datas = new ArrayList<>();
JsonArray jArray = parser.parse(reader).getAsJsonArray();
for (JsonElement object : jArray) {
DataStructure dataStructure = new DataStructure();
JsonObject jObject = gson.fromJson(object, JsonObject.class);
dataStructure.setOp(jObject.get("op").toString());
dataStructure.setData(jObject.get("data").toString());
if (jObject.has("isCol"))
dataStructure.setData(jObject.get("isCol").toString());
System.out.println(dataStructure);
datas.add(dataStructure);
}
List<DataStructure> insideData = getData(datas);
List<DataStructure> inside2Data = getData(insideData);
}
}

GSON parsing for changing json data

I am parsing a JSON data using GSON library and the issue what I am facing is, a part of my json data keeps changing below is how my JSON data looks.
{
"body": [{
"result": [
{
"EndTime": "1411495899000",
"StartTime": "1411495360000"
},
{
"EndTime": "1411495359000",
"StartTime": "1411494784000"
}],
"rule": {
"ruleid": "73B5EEB4"
}
},
{
"result": [
{
"noOfErrors": "5",
"severity": "high"
},
{
"noOfErrors": "4",
"severity": "low"
}],
"rule": {
"ruleid": "35B5EEB4"
}
}
],
"header": {
"contentver": "5.5"
}
}
So in the above JSON data the result array content keeps changing based on the ruleid and I want to choose the java bean for result content at runtime based on the ruleid. Any idea?
-Regards
Well, this is going to be a long answer ...
You could use a custom JsonDeserializer to deserialize the variable part of the json string based on the ruleid.
public class MessageAdapter implements JsonDeserializer<Message> {
private Map<String, Class<? extends Result>> ruleToResultClassMap;
public MessageAdapter() {
this.ruleToResultClassMap = new HashMap<String, Class<? extends Result>>();
ruleToResultClassMap.put("73B5EEB4", DurationResults.class);
ruleToResultClassMap.put("35B5EEB4", ErrorResults.class);
}
#java.lang.Override
public Message deserialize(JsonElement json, java.lang.reflect.Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject messageObject = json.getAsJsonObject();
JsonArray bodyArray = messageObject.getAsJsonArray("body");
List<Result> results = new ArrayList<Result>();
for (JsonElement bodyElement : bodyArray) {
JsonObject resultObject = bodyElement.getAsJsonObject();
JsonObject ruleObject = resultObject.getAsJsonObject("rule");
String ruleId = ruleObject.getAsJsonPrimitive("ruleid").getAsString();
Class<? extends Result> resultClass = ruleToResultClassMap.get(ruleId);
if (resultClass != null) {
Result result = context.deserialize(resultObject, resultClass);
results.add(result);
} else {
throw new IllegalArgumentException("Illegal ruleId: " + ruleId);
}
}
return new Message(results, context.<Header>deserialize(messageObject.getAsJsonObject("header"), Header.class));
}
}
You need to register the custom deserializer with GsonBuilder:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Message.class, new MessageAdapter());
Gson gson = gsonBuilder.create();
String jsonString = null; // your json string
Message message = gson.fromJson(jsonString, Message.class);
Here Message is the root POJO of the json string, you probably have your own. For full reference, I include all classes here:
public class Message {
private List<? extends Result> body;
private Header header;
public Message(List<? extends Result> body, Header header) {
this.body = body;
this.header = header;
}
public List<? extends Result> getBody() {
return body;
}
public Header getHeader() {
return header;
}
}
public class Header {
private String contentver;
public Header(String contentVer) {
this.contentver = contentVer;
}
public String getContentVer() {
return contentver;
}
}
public interface Result {
public Rule getRule();
}
public final class Rule {
private String ruleid;
public String getRuleid() {
return ruleid;
}
}
public class DurationResults implements Result {
private Duration[] result;
private Rule rule;
public Duration[] getResult() {
return result;
}
#Override
public Rule getRule() {
return rule;
}
public static final class Duration {
private long EndTime;
private long StartTime;
public long getStartTime() {
return StartTime;
}
public long getEndTime() {
return EndTime;
}
}
}
public class ErrorResults implements Result {
private Error[] result;
private Rule rule;
public Error[] getResult() {
return result;
}
#Override
public Rule getRule() {
return rule;
}
public static final class Error {
private int noOfErrors;
private String severity;
public int getNoOfErrors() {
return noOfErrors;
}
public String getSeverity() {
return severity;
}
}
}
I think you have to parse your json if your result change.
Replace first "result" to "FirstResult" , and replace second "result" to "SecondResult".
Your json have to look like this:
{
"body": [{
"FirstResult": [
{
"EndTime": "1411495899000",
"StartTime": "1411495360000"
},
{
"EndTime": "1411495359000",
"StartTime": "1411494784000"
}],
"rule": {
"ruleid": "73B5EEB4"
}
},
{
"SecondResult": [
{
"noOfErrors": "5",
"severity": "high"
},
{
"noOfErrors": "4",
"severity": "low"
}],
"rule": {
"ruleid": "35B5EEB4"
}
}
],
"header": {
"contentver": "5.5"
}
}
And you can parse json to Java Objects. If you have first result parse to FirstResultObject.java , if you have second result parse to SecondResult.java
SecondResult.java
public class SecondResult
{
private String noOfErrors;
private String severity;
public String getNoOfErrors ()
{
return noOfErrors;
}
public void setNoOfErrors (String noOfErrors)
{
this.noOfErrors = noOfErrors;
}
public String getSeverity ()
{
return severity;
}
public void setSeverity (String severity)
{
this.severity = severity;
}
}
FirstResult.java
public class FirstResult
{
private String EndTime;
private String StartTime;
public String getEndTime ()
{
return EndTime;
}
public void setEndTime (String EndTime)
{
this.EndTime = EndTime;
}
public String getStartTime ()
{
return StartTime;
}
public void setStartTime (String StartTime)
{
this.StartTime = StartTime;
}
}

Categories

Resources