I want to use the Google Distance Matrix API to get the duration needed to travel between two locations. But when I try to get the duration from the returned data (JSON encoded) the method getJSONArray always returns null.
Here is the data sent by Google:
{
"destination_addresses" : [ "Rome, Metropolitan City of Rome, Italy" ],
"origin_addresses" : [ "Berlin, Germany" ],
"rows" : [
{
"elements" : [
{
"distance" : {
"text" : "1,501 km",
"value" : 1501458
},
"duration" : {
"text" : "15 hours 5 mins",
"value" : 54291
},
"status" : "OK"
}
]
}
],
"status" : "OK"
}
And here is the method to get the duration:
public static int getDurationFromJSON(String json){
try {
JSONObject jsonObj = new JSONObject(json)
.getJSONArray("rows")
.getJSONObject(0)
.getJSONArray ("elements")
.getJSONObject(0)
.getJSONObject("duration");
return (int)(jsonObj.getInt("value") / 60.0f + 0.5f);
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
getJSONArray("rows") returns null.
I am not sure why you are getting the null, but this line seems excessive:
(int)(Integer.parseInt(String.valueOf(jsonObj.getInt("value"))) / 60.0f + 0.5f);
JsonObj.getInt("Value) is going to return an int, why are you turning this into a string, only to then parse it back into an Int and then casting that back into an INT again?
This could be simplified into simply like this
return(int)((jsonObj.getInt("value")/60.0f) +0.5f)
As to the null, I would use a debugger and check the JSON being passed in and make sure it is what you think it is.
Also, as other have suggested, using something like restTemplate to auto parse the json into native mapped objects will make your life easier.
Okay, here the solution. Don't trust org.json.* Use Gson:
Json-Data:
{
"destination_addresses" : [ "Rome, Metropolitan City of Rome, Italy" ],
"origin_addresses" : [ "Berlin, Germany" ],
"rows" : [
{
"elements" : [
{
"distance" : {
"text" : "1,501 km",
"value" : 1501458
},
"duration" : {
"text" : "15 hours 5 mins",
"value" : 54291
},
"status" : "OK"
}
]
}
],
"status" : "OK"
}
Create Object for Result:
public class DirectionMatrixResult {
private String[] destination_addresses;
private String[] origin_addresses;
private DirectionMatrixResultRow[] rows;
public DirectionMatrixResultRow[] getRows() {
return rows;
}
public String[] getDestination_addresses() {
return destination_addresses;
}
public String[] getOrigin_addresses() {
return origin_addresses;
}
public void setDestination_addresses(String[] destination_addresses) {
this.destination_addresses = destination_addresses;
}
public void setOrigin_addresses(String[] origin_addresses) {
this.origin_addresses = origin_addresses;
}
public void setRows(DirectionMatrixResultRow[] rows) {
this.rows = rows;
}
}
public class DirectionMatrixResultRow {
private DirectionMatrixResultElement[] elements;
public DirectionMatrixResultElement[] getElements() {
return elements;
}
public void setElements(DirectionMatrixResultElement[] elements) {
this.elements = elements;
}
}
public class DirectionMatrixResultElement {
private DirectionMatrixResultElementValue distance;
private DirectionMatrixResultElementValue duration;
private String status;
public DirectionMatrixResultElementValue getDistance() {
return distance;
}
public DirectionMatrixResultElementValue getDuration() {
return duration;
}
public String getStatus() {
return status;
}
public void setDistance(DirectionMatrixResultElementValue distance) {
this.distance = distance;
}
public void setDuration(DirectionMatrixResultElementValue duration) {
this.duration = duration;
}
public void setStatus(String status) {
this.status = status;
}
}
public class DirectionMatrixResultElementValue {
private String text;
private long value;
public long getValue() {
return value;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public void setValue(long value) {
this.value = value;
}
}
Then call:
public static int getDurationFromJSON(String json){
try {
Gson gson = new Gson();
DirectionMatrixResult result = gson.fromJson(json, DirectionMatrixResult.class);
return (int)(result.getRows()[0].getElements()[0].getDuration().getValue() / 60.0f + 0.0f);
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
Related
I have the following JSON response snippet which is used to filter a list view by first_name, last_name, and email.
"data": {
"filters": {
"first_name": {
"key": "first_name",
"label": "First Name",
"order": 1,
"values": [
"Shaun",
"Max",
"Tyler"
],
"filter_type": "select"
},
"last_name": {
"key": "last_name",
"label": "Last Name",
"order": 2,
"values": [
"Nash",
"Mally",
"Carick"
],
"filter_type": "select"
},
"email": {
"key": "email",
"label": "Email",
"order": 3,
"values": [
"shaun#email.com",
"max#email.com",
"tyler#email.com"
],
"filter_type": "select"
}
},
...
}
My issue is that first_name, last_name, and email are custom filters which means the these JSON Object names can change. For example, another response might look like this:
"data": {
"filters": {
"age": {
"key": "age",
"label": "Age",
"order": 1,
"values": [
"33",
"24",
"47"
],
"filter_type": "select"
},
"middle_name": {
"key": "middle_name",
"label": "Middle Name",
"order": 2,
"values": [
"Nicholas",
"Ava",
"George"
],
"filter_type": "select"
},
"email": {
"key": "email",
"label": "Email",
"order": 3,
"values": [
"shaun#email.com",
"max#email.com",
"tyler#email.com"
],
"filter_type": "select"
}
},
...
}
Here, the custom filters being used are age, middle_name, and email. While these filter names might be different, each filter always has a key, label, order, values, and filter_type field.
I'm having trouble understanding how to properly parse the information here using GSON. I tried looking into using a JSON to POJO website but I don't know how to apply it since the filters won't always be the same. I also trying doing this:
JSONObject dataObject = myJSON.getJSONObject("data");
if(dataObject.has("filters")){
JSONObject filterJSONObject = dataObject.getJSONObject("filters");
//I need to retrieve the keys/values for each filter here
}
But this only returns the first filter object and not the rest.
Any help would be appreciated
I'd suggest different approach. You can create classes like this (names are just for sample, but field names are important) :
public static class Holder {
private final Filters data;
public Holder(Filters data) {
this.data = data;
}
public Filters getData() {
return data;
}
}
public static class Filters {
private final Map<String, Value> filters;
public Filters(Map<String, Value> filters) {
this.filters = filters;
}
public Map<String, Value> getFilters() {
return filters;
}
}
public static class Value {
private final String label;
private final int order;
public Value(String label, int order) {
this.label = label;
this.order = order;
}
public String getLabel() {
return label;
}
public int getOrder() {
return order;
}
}
The above structure will serialize into your sample json:
Value value1 = new Value("label1", 1);
Value value2 = new Value("label2", 2);
Map<String, Value> data = new HashMap<>();
data.put("age", value1);
data.put("email", value2);
Filters filters = new Filters(data);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Log.d("json", gson.toJson(new Holder(filters)));
Here is log output:
{
"data": {
"filters": {
"age": {
"label": "label1",
"order": 1
},
"email": {
"label": "label2",
"order": 2
}
}
}
}
You can check like following
JSONObject firstNameFilter = filterJSONObject.getJSONObject("first_name");
JSONObject ageFilter = filterJSONObject.getJSONObject("age");
if(firstNameFilter != null){
}
if(ageFilter != null){
}
You could get an Iterator which contains the list of keys in JSONObject using keys() method
You can try this method
Map<String, Object> filterMap = new HashMap<String, Object>();
if(dataObject.has("filters")){
JSONObject filterJSONObject = null;
try {
filterJSONObject = dataObject.getJSONObject("filters");
} catch (JSONException e) {
e.printStackTrace();
}
//I need to retrieve the keys/values for each filter here
Iterator<String> keysItr = filterJSONObject.keys();
while(keysItr.hasNext()) {
String key = keysItr.next();
Object value = null;
try {
value = filterJSONObject.get(key);
} catch (JSONException e) {
e.printStackTrace();
}
if(value instanceof JSONObject) {
value = togetValueMap((JSONObject) value);
}
filterMap.put(key, value);
}
}
private ArrayList<FilterValue> togetValueMap(JSONObject value) {
ArrayList<FilterValue> arrayList = new ArrayList<FilterValue>();
List<String> list = new ArrayList<String>();
for (int i = 0; i < value.length(); i++) {
FilterValue filterValue = new FilterValue();
try {
filterValue.setKey(value.getString("key"));
filterValue.setLabel(value.getString("label"));
filterValue.setOrder(value.getInt("order"));
filterValue.setFilter_type(value.getString("filter_type"));
JSONArray jsonArray = value.getJSONArray("values");
for (int j=0; j<jsonArray.length(); j++) {
list.add(jsonArray.getString(j) );
}
filterValue.setValues(list);
arrayList.add(filterValue);
} catch (JSONException e) {
e.printStackTrace();
}
}
return arrayList;
}
public static class FilterValue {
private String key;
private String label;
private int order;
private List<String> values;
private String filter_type;
public void setKey(String key) {
this.key = key;
}
public void setLabel(String label) {
this.label = label;
}
public void setOrder(int order) {
this.order = order;
}
public void setValues(List<String> values) {
this.values = values;
}
public void setFilter_type(String filter_type) {
this.filter_type = filter_type;
}
public String getKey() {
return key;
}
public String getLabel() {
return label;
}
public int getOrder() {
return order;
}
public List<String> getValues() {
return values;
}
public String getFilter_type() {
return filter_type;
}
}
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.
JSON
"entities": {
"nca_location": [
{
"confidence": 0.85126983589896,
"value": "struga",
"type": "value"
},
{
"confidence": 0.9188255680843,
"value": "Skopje",
"type": "value"
}
],
"intent": [
{
"confidence": 0.99990092463824,
"value": "nca_get_position_availability"
}
]
}
EntityDto
public class EntityDto {
private String name;
private List<EntityValueDto> values;
public EntityDto(String name, List<EntityValueDto> values) {
this.name = name;
this.values = values;
}
public List<EntityValueDto> getValues() {
return values;
}
public void setValues(List<EntityValueDto> values) {
this.values = values;
}
}
EntityValueDto
public class EntityValueDto {
private Float confidence;
private String value;
public EntityValueDto(Float confidence, String value) {
this.confidence = confidence;
this.value = value;
}
public Float getConfidence() {
return confidence;
}
public void setConfidence(Float confidence) {
this.confidence = confidence;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
How can I use GSON/Jackson to make this sort of mapping automatic? I would like to only extract the entities values and make a list out of them.
EntityDto example: nca_location would be the name, and the list would be the parsed objects.
ResponseEntity response = restTemplate.exchange(requestUrl, HttpMethod.POST, entity, Object.class);
This is how I get the response object from the API and I have no idea how to proceed.
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;
}
}
I want to do something like this posted here, but using this JSON response:
{
"status": "OK",
"origin_addresses": [ "Vancouver, BC, Canada", "Seattle, État de Washington, États-Unis" ],
"destination_addresses": [ "San Francisco, Californie, États-Unis", "Victoria, BC, Canada" ],
"rows": [ {
"elements": [ {
"status": "OK",
"duration": {
"value": 340110,
"text": "3 jours 22 heures"
},
"distance": {
"value": 1734542,
"text": "1 735 km"
}
}, {
"status": "OK",
"duration": {
"value": 24487,
"text": "6 heures 48 minutes"
},
"distance": {
"value": 129324,
"text": "129 km"
}
} ]
}, {
"elements": [ {
"status": "OK",
"duration": {
"value": 288834,
"text": "3 jours 8 heures"
},
"distance": {
"value": 1489604,
"text": "1 490 km"
}
}, {
"status": "OK",
"duration": {
"value": 14388,
"text": "4 heures 0 minutes"
},
"distance": {
"value": 135822,
"text": "136 km"
}
} ]
} ]
}
my classes are:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
class Response {
private String status;
private String[] destination_addresses;
private String[] origin_addresses;
private Elements[] rows;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String[] getDestination_addresses() {
return destination_addresses;
}
public void setDestination_addresses(String[] destination_addresses) {
this.destination_addresses = destination_addresses;
}
public String[] getOrigin_addresses() {
return origin_addresses;
}
public void setOrigin_addresses(String[] origin_addresses) {
this.origin_addresses = origin_addresses;
}
public Elements[] getRows() {
return rows;
}
public void setRows(Elements[] rows) {
this.rows = rows;
}
}
class Distance {
private String text;
private String value;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
class Duration {
private String text;
private String value;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
class Elements {
Duration duration[];
Distance distance[];
String status;
}
public class JSON {
public static void main(String[] args) throws IOException {
JsonReader reader = new JsonReader(new BufferedReader(new FileReader(
"json.json")));
reader.setLenient(true);
Response r = (new Gson().fromJson(reader, Response.class));
StringBuilder sb = new StringBuilder();
for (String s : r.getDestination_addresses()) {
sb.append(s);
}
System.out.println("getDestination_addresses: " + sb.toString());
StringBuilder sb1 = new StringBuilder();
for (String s : r.getOrigin_addresses()) {
sb1.append(s);
}
System.out.println("getOrigin_addresses: " + sb1.toString());
System.out.println("getStatus(): " + r.getStatus());
System.out.println("Rows length " + r.getRows().length);
System.out.println(r.getRows()[0].status); // here i get null
}
}
But it does not work fully, I can get only this fields correctly:
private String status;
private String[] destination_addresses;
private String[] origin_addresses;
the are information is null.
Your declarations are wrong. Change Response into
class Response {
private String status;
private String[] destination_addresses;
private String[] origin_addresses;
private Item[] rows;
...
}
where Item is:
class Item {
private Element[] elements;
...
}
and Element is:
class Element{
Duration duration;
Distance distance;
String status;
...
}
This should solve. Three more tips for you:
We are in full generics era, so avoid Element[] and use List instead (and so on, anycase I kept you "style" in answer)
Use something like this to visualize your JSON, it will help you to understand its structure
Duration and Distance have the same structure, maybe you can save a declaration, Gson does not care about name of classes, it looks at structure of it. From Gson point of view, Duration and Distance are the same: a string plus an integer.