I am trying to convert the http response body which is in JSON format into a Java object using the GSON library, but the object has all attributes equal to null after trying to do so.
My Object class:
public class User {
private String username;
private int shipCount;
private int structureCount;
private String joinedAt;
private int credits;
public User(String username, int shipCount, int structureCount, String joinedAt, int credits) {
this.username = username;
this.shipCount = shipCount;
this.structureCount = structureCount;
this.joinedAt = joinedAt;
this.credits = credits;
}
Plus getters and setters
My attempt at using GSON:
Gson gso = new Gson();
User userInf = gso.fromJson(response.body(), User.class);
System.out.println(userInf);
The response body is this:
{"user":{"username":":chrter","shipCount":0,"structureCount":0,"joinedAt":"2022-04-09T16:52:14.365Z","credits":0}}
Any help is greatly appreciated
The root object of your HTTP response is a JSON object that has only one field - "user". When GSON deserializes the response, it goes through all the fields of the root object and sets them to the corresponding fields of the class you have provided. So it will look for the field user in the class User and set it to the JSON's data.
Since class User has no field user, GSON doesn't fill that field. In fact it doesn't fill out any other fields, because there are no other fields in the root object.
To get around this you need to deserialize not the whole response, but only the user field of the root object. There are two ways of doing that.
Deserialize the root object, and then deserialize the field user of that object into the User class.
You can find an example of how to do it in #Saheed's answer. However you should note that it translates JSON string into java objects and then translates java objects back. It might cost you additional time if you're doing it in performance-sensitive area of your program.
Create another class which you will deserialize into, which would have the field user. It looks like this:
class Response {
public User user;
};
class User {
// ...
};
And then you deserialize like this:
Gson gso = new Gson();
// CHANGE: Deserialize the response and get the user field
Response response = gso.fromJson(response.body(),Response.class);
User userInf = response.user;
System.out.println(userInf);
Try something like this:
public static Map<String, Object> Converter(String str){
Map<String, Object> map = new Gson().fromJson(str, new TypeToken<HashMap<String, Object>>() {}.getType());
return map;
}
Map<String, Object> apiResponse = Converter(response.body().toString());
Map<String, Object> username = Converter(apiResponse.get("user").toString());
System.out.println(username);
Tweak it a bit to suit your need
Try this.
Map<?, ?> map = gson.fromJson(response.body(), Map.class);
for (Map.Entry<?, ?> entry : map.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
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
When we define a class with following format
public class Field {
#SerializedName("name")
public String name;
#SerializedName("category")
public String category;
}
for the JsonObject content
{
"name" : "string",
"category" : "string",
}
and using Gson to parse the content
Field field = new GsonBuilder().create().fromJson(
content, Field.class);
So,my question is can we use Gson to get the #Serialized name. For in this instance I want to know what #Serialized name is used for field.name,which is name and for field.category which is category.
As per suggested by #Sotirios Delimanolis, using Reflection we can get the Serialized name
java.lang.reflect.Field fields = Field.class.getDeclaredField("name");
SerializedName sName =fields.getAnnotation(SerializedName.class);
System.out.println(sName.value());
Use reflection to retrieve the Field object you want. You can then use Field#getAnnotation(Class) to get a SerializedName instance on which you can call value() to get the name.
Instead of parsing with Field.class, can't you parse it into a JsonObject.class instead? Then use JsonObject.get():
import com.google.gson.JsonObject;
Gson gson = new GsonBuilder().create();
JsonObject jsonObject = gson.fromJson(content, JsonObject.class);
String serializedName = jsonObject.get("name").getAsString();
Note that .getAsString() will return it as a String without embedded double quotes, compare this to when you call toString().
One thing I was trying to do was serialize an enum field, which is not an object. In that case, you can serialize using JsonElement.class, since it's just a primitive:
import com.google.gson.JsonElement;
Gson gson = new GsonBuilder().create();
JsonElement jsonElement = gson.fromJson("\"a\"", JsonElement.class);
String serializedName = jsonElement.getAsString();
Thats a way with alternate for example for a more complex example
Enum class
public enum SomeStatusCd {
#SerializedName(
value = "status_1",
alternate = {"an alternate 1", "an alternate 2"}
)
STATUS_1("status_1")
....
}
get the enum from alternate
public static SomeStatusCd getFromAlternate(String alternateFieldName){
SomeStatusCd result = null;
Field[] statusDeclaredFields = SomeStatusCd.class.getDeclaredFields();
String foundEnumName = null;
for (Field statusDeclaredField : statusDeclaredFields) {
SerializedName annotation = statusDeclaredField.getAnnotation(SerializedName.class);
if (annotation != null){
String[] declaredFieldAlternates = annotation.alternate();
for (String declaredFieldAlternate : declaredFieldAlternates) {
if (declaredFieldAlternate.equals(alternateFieldName)){
foundEnumName = statusDeclaredField.getName();
}
}
}
}
if (foundEnumName != null){
for (SomeStatusCd enumConstant : SomeStatusCd.class.getEnumConstants()) {
if (enumConstant.name().equals(foundEnumName)){
result = enumConstant;
}
}
}
return result;
}
Test it
SomeStatusCd fromAlternate = getFromAlternate("an alternate 1");
assertSame(fromAlternate, SomeStatusCd.STATUS_1);
I'm trying to serialize an object in JSON using a JSP like format using the following code:
ArrayList<AccountBean> al = new ArrayList<AccountBean>();
al = vc.getAccountName();
int i=0;
out.print("[");
while(i<al.size()){
Gson gson = new GsonBuilder().setPrettyPrinting().create();
out.print("{ID"+al.get(i).getAno()+":name"+al.get(i).getAccount_name()+"},");
i++;
}
out.print("]");
I'm getting a output like this:
[{ID1:nameEquity Share Capitals},{ID2:nameCalls In Arear},]
but my requirement is something like this:
[{"ID1":"nameEquity Share Capitals"},{"ID2":"nameCalls In Arear"}]
out.print('{"ID'+al.get(i).getAno()+'":"name'+al.get(i).getAccount_name()+'"},')
use ' to open/close the string, and " to wrap your json keys/values.
Otherwise you can do like this
out.print("{\"ID"+al.get(i).getAno()+"\":\"name"+al.get(i).getAccount_name()+"\"},")
escaping the quotes with \"
Anyway, have you tried this?
String json = gson.toJson(al)
Have a look here for more info: https://sites.google.com/site/gson/gson-user-guide
Best way to do this is using a custom serializer and I can edit this answer posting one if you want to go deeper.
However, since you are quite new to JSON and Gson I would answer with this simple code that you can paste&try in you IDE. I just "convert" you bean into a map, and the use Gson to serialize.
package stackoverflow.questions;
import java.util.*;
import com.google.gson.Gson;
public class Q20323412 {
public static class AccountBean{
Integer _id;
String _name;
public String getAccount_name(){
return _name;
}
public Integer getAno(){
// what a weird name, in italian for this method..
return _id;
}
public AccountBean(Integer id, String name){
_id = id;
_name = name;
}
}
/**
* #param args
*/
public static void main(String[] args) {
ArrayList<AccountBean> al = new ArrayList<AccountBean>();
al.add(new AccountBean(1, "Equity Share Capitals"));
al.add(new AccountBean(2, "Calls In Arear"));
ArrayList<Map> al2 = new ArrayList<>();
for(AccountBean account : al){
HashMap hm = new HashMap();
hm.put("ID"+ account.getAno(), "name"+account.getAccount_name());
al2.add(hm);
}
Gson g = new Gson();
System.out.println(g.toJson(al2));
}
}
Since you did not post your bean, I invented one that has features similar to your's.