I'm consuming an external API, for which a JSON Object is returned. Contained in that Object response is an array that I need to extract and set to a List of a particular entity type. Java, however, is not a language that I'm very familiar with, so I'm having problems attempting to figure this out.
I've created a type of wrapper class to work with this in the setter.
The best I've come up with that compiles is below, but produces an error that I can't figure out.
public void setFlights(Object responseBody) {
String responseString = responseBody.toString();
JSONObject responseJSONObject = new JSONObject(responseString);
JSONArray responseJSONArray = responseJSONObject.getJSONArray("flights");
Gson gson = new Gson();
Type flightType = new TypeToken<List<Flight>>() {}.getType();
this.flights = gson.fromJson(String.valueOf(responseJSONArray), flightType);
}
As you can see, I'm kind of throwing it at the wall to see if it will stick. I'm trying to use Gson to get around some of the Type issues I've come across.
The error produced when executing is:
org.json.JSONException: Expected a ':' after a key at 7 [character 8 line 1]
Response String is as follows:
Response String Image
If that's difficult to deal with, here's the response in text:
INFO: {"FlightInfoResult":{"next_offset":-1,"flights":[{"ident":"N1RJ","aircrafttype":"HDJT","filed_ete":"01:25:00","filed_time":1593038253,"filed_departuretime":1593037500,"filed_airspeed_kts":400,"filed_airspeed_mach":"","filed_altitude":360,"route":"WEAZL4 CLAWD","actualdeparturetime":1593038285,"estimatedarrivaltime":1593043320,"actualarrivaltime":1593043320,"diverted":"","origin":"KJQF","destination":"KJXN","originName":"Concord-Padgett Rgnl","originCity":"Concord, NC","destinationName":"Jackson County","destinationCity":"Jackson, MI"},{"ident":"N1RJ","aircrafttype":"HDJT","filed_ete":"01:24:00","filed_time":1593000320,"filed_departuretime":1592998200,"filed_airspeed_kts":400,"filed_airspeed_mach":"","filed_altitude":350,"route":"PEGTE","actualdeparturetime":1593000420,"estimatedarrivaltime":1593005149,"actualarrivaltime":1593005149,"diverted":"","origin":"KJXN","destination":"KJQF","originName":"Jackson County","originCity":"Jackson, MI","destinationName":"Concord-Padgett Rgnl","destinationCity":"Concord, NC"},{"ident":"N1RJ","aircrafttype":"HDJT","filed_ete":"01:29:00","filed_time":1592518049,"filed_departuretime":1592513400,"filed_airspeed_kts":317,"filed_airspeed_mach":"","filed_altitude":360,"route":"WEAZL4 CLAWD","actualdeparturetime":1592517936,"estimatedarrivaltime":1592523120,"actualarrivaltime":1592523120,"diverted":"","origin":"KJQF","destination":"KJXN","originName":"Concord-Padgett Rgnl","originCity":"Concord, NC","destinationName":"Jackson County","destinationCity":"Jackson, MI"},{"ident":"N1RJ","aircrafttype":"HDJT","filed_ete":"01:24:00","filed_time":1592481020,"filed_departuretime":1592479800,"filed_airspeed_kts":319,"filed_airspeed_mach":"","filed_altitude":350,"route":"PEGTE","actualdeparturetime":1592481126,"estimatedarrivaltime":1592486100,"actualarrivaltime":1592486100,"diverted":"","origin":"KJXN","destination":"KJQF","originName":"Jackson County","originCity":"Jackson, MI","destinationName":"Concord-Padgett Rgnl","destinationCity":"Concord, NC"}]}}
There very well may be a much more simple way of accomplishing what I need. Any example help is very much appreciated.
You can use Gson string to object mapper class directly as like below,
package com.sample.programs;
import java.util.List;
import com.google.gson.Gson;
public class FlightInfoResultMain {
public static void main(String[] args) {
String input = "{\"FlightInfoResult\":{\"next_offset\":-1,\"flights\":[{\"ident\":\"N1RJ\",\"aircrafttype\":\"HDJT\",\"filed_ete\":\"01:25:00\",\"filed_time\":1593038253,\"filed_departuretime\":1593037500,\"filed_airspeed_kts\":400,\"filed_airspeed_mach\":\"\",\"filed_altitude\":360,\"route\":\"WEAZL4 CLAWD\",\"actualdeparturetime\":1593038285,\"estimatedarrivaltime\":1593043320,\"actualarrivaltime\":1593043320,\"diverted\":\"\",\"origin\":\"KJQF\",\"destination\":\"KJXN\",\"originName\":\"Concord-Padgett Rgnl\",\"originCity\":\"Concord, NC\",\"destinationName\":\"Jackson County\",\"destinationCity\":\"Jackson, MI\"},{\"ident\":\"N1RJ\",\"aircrafttype\":\"HDJT\",\"filed_ete\":\"01:24:00\",\"filed_time\":1593000320,\"filed_departuretime\":1592998200,\"filed_airspeed_kts\":400,\"filed_airspeed_mach\":\"\",\"filed_altitude\":350,\"route\":\"PEGTE\",\"actualdeparturetime\":1593000420,\"estimatedarrivaltime\":1593005149,\"actualarrivaltime\":1593005149,\"diverted\":\"\",\"origin\":\"KJXN\",\"destination\":\"KJQF\",\"originName\":\"Jackson County\",\"originCity\":\"Jackson, MI\",\"destinationName\":\"Concord-Padgett Rgnl\",\"destinationCity\":\"Concord, NC\"},{\"ident\":\"N1RJ\",\"aircrafttype\":\"HDJT\",\"filed_ete\":\"01:29:00\",\"filed_time\":1592518049,\"filed_departuretime\":1592513400,\"filed_airspeed_kts\":317,\"filed_airspeed_mach\":\"\",\"filed_altitude\":360,\"route\":\"WEAZL4 CLAWD\",\"actualdeparturetime\":1592517936,\"estimatedarrivaltime\":1592523120,\"actualarrivaltime\":1592523120,\"diverted\":\"\",\"origin\":\"KJQF\",\"destination\":\"KJXN\",\"originName\":\"Concord-Padgett Rgnl\",\"originCity\":\"Concord, NC\",\"destinationName\":\"Jackson County\",\"destinationCity\":\"Jackson, MI\"},{\"ident\":\"N1RJ\",\"aircrafttype\":\"HDJT\",\"filed_ete\":\"01:24:00\",\"filed_time\":1592481020,\"filed_departuretime\":1592479800,\"filed_airspeed_kts\":319,\"filed_airspeed_mach\":\"\",\"filed_altitude\":350,\"route\":\"PEGTE\",\"actualdeparturetime\":1592481126,\"estimatedarrivaltime\":1592486100,\"actualarrivaltime\":1592486100,\"diverted\":\"\",\"origin\":\"KJXN\",\"destination\":\"KJQF\",\"originName\":\"Jackson County\",\"originCity\":\"Jackson, MI\",\"destinationName\":\"Concord-Padgett Rgnl\",\"destinationCity\":\"Concord, NC\"}]}}";
System.out.println("input - " + input);
//Create Gson object
Gson gson = new Gson();
FlightInfoResultObject responseObject = gson.fromJson(input, FlightInfoResultObject.class);
// parsing response to java pojo
List<Flights> listOfFlights = responseObject.getFlightInfoResult().getFlights();
for (Flights flight : listOfFlights) {
System.out.println("flight - " + flight.getIdent());
}
}
}
Object Mapping class: Inside Flights.class you can add all the variable which you have in json response.
class FlightInfoResultObject {
FlightInfoResult FlightInfoResult;
#Getter
#Setter
}
class FlightInfoResult {
Integer next_offset;
List<Flights> flights;
#Getter
#Setter
}
class Flights {
String ident;
String aircrafttype;
#Getter
#Setter
}
I think it's impossible to retrieve the inner JSON element directly using gson.
You have to get FlightInfoResult then flights accordingly. This should work:
Gson gson = new Gson();
JsonObject jsonObject = com.google.gson.JsonParser.parseString(responseString).getAsJsonObject();
JsonArray flightArray = jsonObject.getAsJsonObject("FlightInfoResult").getAsJsonArray("flights");
Type flightType = new TypeToken<List<Flight>>() {}.getType();
List<Flight> flights = gson.fromJson(flightArray, flightType);
Anyway, make sure the name of all properties inside class Flight matches Json elements name, to avoid mapping errors.
Since you didn't post your Flight class definition and gson naming rule, but the Flight class should be like:
public class Flight {
private String ident;
private String aircrafttype;
private String filed_ete;
private float filed_time;
private float filed_departuretime;
private float filed_airspeed_kts;
private String filed_airspeed_mach;
private float filed_altitude;
private String route;
private float actualdeparturetime;
private float estimatedarrivaltime;
private float actualarrivaltime;
private String diverted;
private String origin;
private String destination;
private String originName;
private String originCity;
private String destinationName;
private String destinationCity;
// getters setters
How can I convert the JSON string like this:
{ "summary": {
"totalMR":4.599000000000903E12,
"totalMA":1.9174920000386694E11,
"totalQA":5.1111111181E9,
"totalQR":1.000020666115264E11
},
"result": [{},{}],
"success":"true",
"total":49
}
to a Java object. I went through many similar posts and implemented constructors but couldn't find the proper explanation of why I'm unable to De-serialize the JSON.
Am I doing anything wrong?
My Class:
public class expResponse {
private String success;
private String total;
private ArrayList<LinkedHashMap<String,Object>> result;
private LinkedHashMap<String,SummaryResponse> summary;
// Constructor: public expResponse(){}
// Getter and Setter
}
public class SummaryResponse {
private Float totalQR;
private Float totalQA;
private Float totalMR;
private Float totalMA;
public SummaryResponse(){}
// Setter and Getter
}
My Code:
private expResponse processResult(String result) throws IOException{
ObjectMapper objectMapper = new ObjectMapper();
expResponse expResponseObj =
objectMapper.readValue(result, expResponse.class);
return expResponseObj;
The json you posted would not deserialize into a map of SummaryResponse objects, but rather an individual SummaryResponse object. To make your binding work, you would have to have json that looked something like this:
{
...
'summary': {
'summary1': {"totalMR":4.599000000000903E12,"totalMA":1.9174920000386694E11,"totalQA":5.1111111181E9,"totalQR":1.000020666115264E11}
'summary2': {"totalMR":4.599000000000903E12,"totalMA":1.9174920000386694E11,"totalQA":5.1111111181E9,"totalQR":1.000020666115264E11}
}
...
}
Alternatively, if you need to make your Java class conform to the json you provided, you simply need to change the declaration of summary:
private SummaryResponse summary;
Field summary in your json is an object of type SummaryResponse and not a LinkedHashMap.
public class ExpResponse {
private String success;
private String total;
private ArrayList<LinkedHashMap<String,Object>> result;
private Summary summary;
}
I don't think you have a problem in the code. Your input fails because it is not in the correct format. If you try to write the same values from an object with the same values to string you get something like:
{
"success":"true",
"total":"49",
"result":null,
"summary":{
"one_summary":{
"totalQR":2000.0,
"totalQA":1500.0,
"totalMR":1000.0,
"totalMA":500.0
}
}
}
And the major difference is the one summary. This is because summary is a map and maps need a key for each entryset. That means that summary is your map which has a one_summary key.
Is it the SummaryResponse that can't be deserialised?
I guess your attributes should have the same name "totalMR", "totalMA"....
or you should use an annotation JsonProperty(value="totalMR") and so on.
I have the json:
{"test": [{"param1": "param"}],
"test2": "test",
"test3": "test2"}
how can I get fromGson to parse the arrays in a json correctly so that it populates the arrays into an array of a particular object type.
So test should map to TestObject[] test;
test2 -> String test2;
test3 -> String test3;
I tried gson.fromJson(response, TestData.class); that gave me an error: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 664
( that the fromJson is not parsing the array in the json correctly).
I also tried going through this post:
Parsing JSON array into java.util.List with Gson
But got confused.
but that did not work
Answer
public class TestClass {
public String param1;
}
public class TestMap {
public TestClass[] Test;
public String test2;
public String test3;
}
public Collection<TestMap> collectionFromJSON(String jsonString) {
Gson gson = new Gson();
Collection<TestMap> testMaps = gson.fromJson(jsonString, new TypeToken<Collection<TestMap>>() {
}.getType());
return testMaps;
}
public TestMap singleFromJSON(String jsonString) {
Gson gson = new Gson();
Journal testMap = gson.fromJson(jsonString, TestMap.class);
return testMap;
}
Okay, I will explain something here.
Explain
Normally if you have a nested array of objects inside another object, you need to create a new class. Ie. if Journal has Categories, Category has two other properties, title and index.
The class will be like
class Journal {
public Category[] categories;
....
}
class Category {
public String title;
public Integer index;
....
}
So now, the mistake is to confused Array of String and Array of Class. If the json is
{"Test", ["Test1", "Test2"...]
"Test2": "Test3"}
You can define it as an array of String. But it is a nested JSON Object, so it has to be class again.
Without seeing your class, I'm going to guess. This error
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:
Expected a string but was BEGIN_OBJECT at line 1 column 664
means you are trying to deserialize a String, so something like
"some string"
but what the JSON actually contained was a JSON object, something like
{"name" : "value"}
Your class is probably mapped wrong. It should be
String test2;
String test3;
TestObject[] test;
where TestObject should be
public class TestObject {
String param1;
}
since the JSON contains an JSON string called param1.
python has a very useful module called json
try var TestObject=json.parse()
I'm having trouble parsing the following JSON with Google's Gson:
{"Name":
{"object1":
{"field1":"17",
"field2":"360",
"field3":"19",
"field4":"sun",
"field5":"rain"
}
}
}
I have tried the following to get the value of field1 but it doesn't work
#SerializedName("Name/object1/field1")
public int fieldOne;
What am I doing wrong?
Your objects have to conserve the hierarchy of your json instructions. For your example, it would be something like this:
public class Object {
#SerializedName("field1")
public String fieldOne;
#SerializedName("field2")
public String fieldTwo;
#SerializedName("field3")
public String fieldThree;
#SerializedName("field4")
public String fieldFour;
}
public class Name {
#SerializedName("object1")
public Object obj;
}
public class GsonObj {
#SerializedName("Name")
public Name name;
}
Using the following call:
String json = "{\"Name\":{" +
"\"object1\":{" +
"\"field1\":\"17\",\"field2\":\"360\",\"field3\":\"19\",\"field4\":\"sun\",\"field5\":\"rain\"}}}";
Gson gson = new Gson();
GsonObj jsonResult = gson.fromJson(json, GsonObj.class);
Log.d("test", "field one: "+jsonResult.name.obj.fieldOne);
Log.d("test", "field two: "+jsonResult.name.obj.fieldTwo);
Log.d("test", "field three: "+jsonResult.name.obj.fieldThree);
Log.d("test", "field four: "+jsonResult.name.obj.fieldFour);
You have invalid JSON. JSON may either start with { or [ so you need to wrap your string with another pair of {}.
A good practice is to always check your data first. I often use this here:
http://jsonlint.com/
I don't think you can have "Name/object1/field" you have to specify key name directly without hierarchy.
refer How to parse dynamic JSON fields with GSON?
I need to convert the following Class:
package comS309.traxz.data;
import java.util.Collection;
import org.json.JSONException;
import org.json.JSONObject;
public class ExerciseSession {
public String DateCreated;
public String TotalTime;
public String CaloriesBurned;
public String AvgSpeed;
public String SessionName;
public String Distance;
public String SessionType;
public String UserId;
public Collection<LatLon> LatLons;
}
Where LatLon is as follows:
public class LatLon {
public String LatLonId;
public String Latitude;
public String Longitude;
public String ExerciseSessionId;
public String LLAveSpeed;
public String Distance;
}
So the Class ExerciseSession has a collection of LatLon objects. Now I need to convert The ExerciseSession Class into a Json format from java and send it to my server.
I am doing this on the android OS, if that matters.
My current solution is this:
JSONObject ExerciseSessionJSOBJ = new JSONObject();
ExerciseSessionJSOBJ.put("DateCreated", this.DateCreated);
ExerciseSessionJSOBJ.put("TotalTime", this.TotalTime);
ExerciseSessionJSOBJ.put("CaloriesBurned", this.CaloriesBurned);
ExerciseSessionJSOBJ.put("AvgSpeed", this.AvgSpeed);
ExerciseSessionJSOBJ.put("SessionName", this.SessionName);
ExerciseSessionJSOBJ.put("Distance", this.Distance);
ExerciseSessionJSOBJ.put("SessionType", this.SessionType);
ExerciseSessionJSOBJ.put("UserId", this.UserId);
//add the collection
for(LatLon l: LatLons)
{
ExerciseSessionJSOBJ.accumulate("LatLons", l);
}
I am not sure this is valid.. I am a novice with Json and need help.
Thanks in advance for the help!
This is very easy to do using Google's GSON library. Here's an example use:
Gson gson = new Gson();
String jsonRepresentation = gson.toJson(myComplexObject);
And to get the object back:
Gson gson = new Gson();
MyComplexObject myComplexObject = gson.fromJson(jsonRepresentation, MyComplexObject.class);
http://code.google.com/p/google-gson/
You can also serialize the object using flexjson: http://flexjson.sourceforge.net/
I think using the accumulate is correct. See: http://www.json.org/javadoc/org/json/JSONObject.html#accumulate(java.lang.String,%20java.lang.Object)
But you need to create a JSONObject for each LatLon as you do for the ExerciseSession object.
Then, the following line is wrong:
ExerciseSessionJSOBJ.accumulate("LatLons", l);
"l" must be transformed.
I would really suggest you avoid using JSONObject to convert between Strings and Java objects. It will probably claim your sanity if you have to do too much of it. As an alternative, I'm a big fan of Jackson, which does what you describe in a really pleasant and simple way.
As a basic example,
public static class LatLon {
public final String LatLonId;
public final String Latitude;
public final String Longitude;
public final String ExerciseSessionId;
public final String LLAveSpeed;
public final String Distance;
#JsonCreator
public LatLon(#JsonProperty("distance") String distance,
#JsonProperty("exerciseSessionId") String exerciseSessionId,
#JsonProperty("latitude") String latitude,
#JsonProperty("latLonId") String latLonId,
#JsonProperty("LLAveSpeed") String LLAveSpeed,
#JsonProperty("longitude") String longitude) {
this.Distance = distance;
this.ExerciseSessionId = exerciseSessionId;
this.Latitude = latitude;
this.LatLonId = latLonId;
this.LLAveSpeed = LLAveSpeed;
this.Longitude = longitude;
}
public static void something() {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"LLAveSpeed\":\"123\",\"Distance\":\"123\","
+ "\"ExerciseSessionId\":\"123\",\"LatLonId\":\"123\","
+ "\"Latitude\":\"123\",\"Longitude\":\"123\"}";
try {
//turn the json string into a LatLon object.
LatLon latLon = mapper.readValue(json, LatLon.class);
//turn the latLon object into a new JSON string
String newJson = mapper.writeValueAsString(latLon);
//confirm that the strings are equal
Log.w("JacksonDemo", "Are they equal? " + json.equals(newJson));
}
catch (IOException e) {
e.printStackTrace();
}
}
}
This outputs Are they equal? true.
So you use readValue() to convert json to a Java object, writeValueAsString() to write an object back into json. #JsonCreator marks the constructor Jackson should use to convert betwee json and Java. #JsonProperty("jsonKeyName") marks the name of a variable in the json string and the Java variable it should map to.
This is a little confusing at first but saves a lot of time once you figure it out. Let me know if anything is unclear.