GSON Custom parsing - java

Hi I'm writing an android App that interfaces with an external webservice that outputs JSON formatted info.
I'm using GSON to generate POJOs for the output of the web service, but I'm having a problem with this entity:
player: {
1: {
number: "6",
name: "Joleon Lescott",
pos: "D",
id: "2873"
},
2: {
number: "11",
name: "Chris Brunt",
pos: "D",
id: "15512"
},
3: {
number: "23",
name: "Gareth McAuley",
pos: "D",
id: "15703"
}
}
Using a service like http://www.jsonschema2pojo.org/ I was able to generate a POJO that matches to this output like this:
public class Player {
#SerializedName("1")
#Expose
private com.example._1 _1;
#SerializedName("2")
#Expose
private com.example._2 _2;
.....
}
public class _1 {
#Expose
private String name;
#Expose
private String minute;
#Expose
private String owngoal;
#Expose
private String penalty;
#Expose
private String id;
....
}
However I would like to tweak this a little bit and instead of having an object for _1, _2, etc, I would like to have an array or list containing all data, like this:
public class Players{
private List<Player> players;
}
public class Player{
#Expose
private int position;
#Expose
private String name;
#Expose
private String minute;
#Expose
private String owngoal;
#Expose
private String penalty;
#Expose
private String id;
....
}
How can I accomplish this, without manually parsing the JSON file?

Register a TypeAdapter for your Players class. In the deserialize method iterate over keys in the json and add them to an ArrayList. That should work, I think. An example in pseudo-code:
class PlayersAdapter implements JsonDeserializer<Players> {
public Players deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) {
List<Player> players = new ArrayList<>();
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
players.add(ctx.deserialize(entry.getValue(), Players.class));
}
return new Players(players);
}
}
// ...
Gson gson = new GsonBuilder()
.registerTypeAdapter(Players.class, new PlayersAdapter())
.create();

Related

Jackson parse different level fields to one java class

I have the following JSON string and java class.
Json:
{
"records": [
{
"metadata": {
"id": "1129836408668",
"partition": "ecp:9-ca69437a-2ad5-4233-bfc4-fd9aa049569d",
"version": "ecp:9-f66cf504-ba65-48a9-91c0-d1d8229e4899",
"currentAt": "2021-12-07T11:13:50.699Z"
},
"state": {
"effectiveFrom": "2021-12-14T06:35:09.063Z",
"effectiveTo": "2021-12-14T06:35:09.063Z",
"currentFrom": "2021-12-14T06:35:09.063Z",
"currentTo": "2021-12-14T06:35:09.063Z",
"dataItem": {
"ModifiedDate": "2021-12-07T11:13:44.099Z",
"ObjectId": "1129836408668",
"ChangeFlag": "",
"IsUnconfirmed": "false",
"CreatedDate": "2021-12-07T11:13:44.099Z"
}
}
}
],
"index": null
}
Class A:
public class ParentClass {
private Date effectiveFrom;
private Date effectiveTo;
private Date currentFrom;
private Date currentTo;
private String id;
}
Class B
public class ChildClass extends ParentClass {
#JsonProperty("ModifiedDate")
private Date ModifiedDate;
#JsonProperty("ObjectId")
private String ObjectId;
#JsonProperty("ChangeFlag")
private String ChangeFlag;
#JsonProperty("IsUnconfirmed")
private String IsUnconfirmed;
#JsonProperty("CreatedDate")
private Date CreatedDate;
}
And I'd like to parse the values in state jsonnode to ChildClass wiht Jackson. Which way is the best way to do it.
My thoughts is trying to parse state into MapA, and then parse dateItem into MapB, then merge MapB to MapA, you will get a Mapc, and then parse MapC to ChildClass. However, I think this is not a efficiency way to do it. So will you guys have a better solution.
MapC:
{
effectiveFrom=2021-12-14T06:35:09.063Z,
effectiveTo=2021-12-14T06:35:09.063Z,
currentFrom=2021-12-14T06:35:09.063Z,
currentTo=2021-12-14T06:35:09.063Z,
ModifiedDate=2021-12-07T11:13:44.099Z,
ObjectId=1129836408668,
ChangeFlag=, IsUnconfirmed=false,
CreatedDate=2021-12-07T11:13:44.099Z
}
You don't actually need two classes. You need just one that is capable of deserializing dataItem block in a customized way. Something along the following lines should work:
public class ParentClass {
private Date effectiveFrom;
private Date effectiveTo;
private Date currentFrom;
private Date currentTo;
private String id;
private Date modifiedDate;
private String objectId;
private String changeFlag;
private String isUnconfirmed;
private Date createdDate;
#JsonProperty("dataItem")
private void unpackNested(Map<String, Object> dataItem) {
this.modifiedDate = Date.from(Instant.from(DateTimeFormatter.ISO_INSTANT.parse((String) dataItem.get("ModifiedDate"))));
this.objectId = (String) dataItem.get("ObjectId");
this.changeFlag = (String) dataItem.get("ChangeFlag");
this.isUnconfirmed = (String) dataItem.get("IsUnconfirmed");
this.createdDate = Date.from(Instant.from(DateTimeFormatter.ISO_INSTANT.parse((String) dataItem.get("CreatedDate"))));
}
}
You can find other options at https://www.baeldung.com/jackson-nested-values.

Nested JSONObject Deserialize to JSONObject

So I'm working on deserializing a nested JSONObject, but don't want to create a class for each nested object. I was trying to take on of the nested JSONObjects and put it in a JSONObject.
public class ContainerStatus {
#JsonProperty("name")
private String name;
#JsonProperty("state")
private JSONObject state;
#JsonProperty("lastState")
private JSONObject lastState;
#JsonProperty("ready")
private Boolean ready;
#JsonProperty("restartCount")
private Integer restartCount;
#JsonProperty("image")
private String image;
#JsonProperty("imageID")
private String imageID;
#JsonProperty("containerID")
private String containerID;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
Using this to deserialize:
{ "containerStatuses":
{
"name": "connect",
"state": {
"terminated": {
"exitCode": 1,
"reason": "Error",
"startedAt": "2019-03-20T15:40:08Z",
"finishedAt": "2019-03-20T15:40:50Z",
"containerID": "docker://"
}
},
"lastState": {},
"ready": true,
"restartCount": 0,
"image": "image",
"imageID": "docker-pullable://",
"containerID": "docker://"
}}
I get unrecognized field "terminated", because of the state JSONObject.
I want a:
JsonObject state = {
"terminated": {
"exitCode": 1,
"reason": "Error",
"startedAt": "2019-03-20T15:40:08Z",
"finishedAt": "2019-03-20T15:40:50Z",
"containerID": "docker://"
}
}
I can cast it into a generic object, but the format isn't JSON anymore:
#JsonProperty("state")
private Object state;
Gives me this format:
{running={startedAt=2019-03-20T14:53:53Z}}
You need to improve a little bit your example:
DeserializationFeature.UNWRAP_ROOT_VALUE, enable this feature to
unwrap JSON object.
Add JsonRootName annotation to your POJO class because class name does not match to property containerStatuses.
Use JsonNode which comes from Jackson library instead of JSONObject which comes probably from org.json.
Improved example could look like below:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonApp {
public static void main(String[] args) throws Exception {
String json = "{...}";
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
ContainerStatus cs = mapper.readValue(json, ContainerStatus.class);
System.out.println(cs.getState());
}
}
#JsonRootName("containerStatuses")
class ContainerStatus {
#JsonProperty("name")
private String name;
#JsonProperty("state")
private JsonNode state;
#JsonProperty("lastState")
private JsonNode lastState;
#JsonProperty("ready")
private Boolean ready;
#JsonProperty("restartCount")
private Integer restartCount;
#JsonProperty("image")
private String image;
#JsonProperty("imageID")
private String imageID;
#JsonProperty("containerID")
private String containerID;
// getters, setters, toString
}
Above code prints:
{"terminated":{"exitCode":1,"reason":"Error","startedAt":"2019-03-20T15:40:08Z","finishedAt":"2019-03-20T15:40:50Z","containerID":"docker://"}}

Map JSON to pojo using Jackson for List that have different parameters

JSON FORMAT:
[
{
"0":
{
"cast":"",
"showname":"woh pagle",
"type":"Episodes"
},
"video":[
{
"src":"video.mp4"
},
{
"DRM":"False"
}
]
}
]
Here problem is I am getting below exception:
org.codehaus.jackson.map.JsonMappingException: Can not deserialize
instance of java.util.ArrayList out of START_OBJECT token at [Source:
java.io.StringReader#1c9ca1; line: 1, column: 55617] (through
reference chain:
com.apalya.myplex.valueobject.ThirdPartyContentDetailsArray["video"])
My pojo classes are :
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonProperty("0")
private ThirdPartySubContentDetails subContent;
#JsonProperty("video")
private List<ThirdPartySubContentVideoInfo> video;
My Sub class pojo is :
private String src;
#JsonIgnore
#JsonProperty("DRM")
private String drm;
Please help me to write a pojo for that video list.
Your json starts as an array and not as an Object. The important part to change is how the Objectmapper should generate your json. For returning a List you need to do it this way:
List<FirstJson> jsonList = mapper.readValue(json, new TypeReference<List<FirstJson>>(){});
Here is my short working test I implement locally:
public static void main(String[] args) {
String json = "[{\"0\":{\"cast\":\"\",\"showname\":\"wohpagle\",\"type\":\"Episodes\"},\"video\":[{\"src\":\"video.mp4\"},{\"DRM\":\"False\"}]}]";
ObjectMapper mapper = new ObjectMapper();
List<FirstJson> jsonList = mapper.readValue(json, new TypeReference<List<FirstJson>>(){});
System.out.println(jsonList.toString());
}
The first part of your JsonArray in Pojo.(Named it FirstJson)
public class FirstJson{
#JsonProperty("0")
private FirstJson subContent;
private String cast;
private String showname;
private String type;
#JsonProperty("video")
private List<Video> videos;
//getter/setter
And the Video Pojo:
public class Video {
private String src;
#JsonProperty("DRM")
private String drm;
//getter/setter
Just a sidenote: If you declare your pojos in the same class file, the classes should be static. public static class FirstJson
According to the JSON structure described in the question, the following should be the POJOs:
public class MainPojo
{
#JsonProperty("0")
private ThirdPartySubContentDetails subContent;
#JsonProperty("video")
private List<ThirdPartySubContentVideoInfo> video;
// Getters and Setters for subContent and video
}
class ThirdPartySubContentDetails
{
private String cast;
private String showName;
private String type;
// Getters and Setters for cast, showName and type
}
#JsonIgnoreProperties(ignoreUnknown = true)
class ThirdPartySubContentVideoInfo
{
#JsonProperty("src")
private String src;
#JsonProperty("DRM")
private String drm;
// Getters and Setters for src and drm
}
You should call the deserializer method as follows:
List<MainPojo> list = new ObjectMapper().readValue(json, new TypeReference<List<MainPojo>>(){});

Get map from retrofit query

I have JSON that I get using retrofit
[{
"id":"1",
"name":"name",
"fields_json":{
"f1":"value1",
"f2":"value2",
"f3":"value3"
}
},{
"id":"2",
"name":"name2",
"fields_json":{
"f1":"value1",
"f2":"value2",
"f3":"value3"
}
}]
I want get List of Person(long id, String name, Map fields)
How I may get fields_json as Map in this class?
If you change your json a bit, so you can use special response classes
{"persons":[{id":"1","name":"name", ...} ] }
public class Response {
#SerializedName("persons")
#Expose
public ArrayList<Person> persones;
}
public class Person {
#SerializedName("id")
#Expose
public String id;
#SerializedName("name")
#Expose
public String name;
#SerializedName("fields_json")
#Expose
public FieldsJson fieldsJson;
}
public class FieldsJson {
#SerializedName("f1")
#Expose
public String f1;
#SerializedName("f2")
#Expose
public String f2;
#SerializedName("f3")
#Expose
public String f3;
}
and set this class as response
#POST("/url")
Call<Response> getPersones(
....
);
So, if you wish You can describe public fieldsJson as Map
Map<String, Object> fieldsJson
It cannot be added as a Map object.
Instead you need to create another java class that contains the f1-f3 variables.
Then add this new class as a variable with the name of fields_json to your current class.

Gson to POJO, how to read the inner JSON Objects as part of the same POJO?

I have a JSON like below and would like to convert it using Gson to one POJO.
I am trying to figure out how to basically cut down the inner nested objects like desc to be treated as part of the same Java object, instead of creating a new POJO named Desc.
Is there a way to do this with Serialized Names to look into nested JSON objects?
Thanks in advance!
JSON to be converted to POJO
{
'name': name,
'desc': {
'country': country,
'city': city,
'postal': postal,
'street': street,
'substreet': substreet,
'year': year,
'sqm': sqm
},
'owner': [owner],
'manager': [manager],
'lease': {
'leasee': [
{
'userId': leaseeId,
'start': leaseeStart,
'end': leaseeeEnd
}
],
'expire': leaseExpire,
'percentIncrease': leasePercentIncrease,
'dueDate': dueDate
},
'deposit': {
'bank': 'Sample Bank',
'description': 'This is a bank'
}
}
Custom POJO
public class Asset {
private String mId;
#SerializedName("name")
private String mName;
private String mCountry;
private String mCity;
private String mPostal;
private String mStreet;
private String mSubstreet;
private int mYear;
private int mSqm;
#SerializedName("owner")
private List<String> mOwners;
#SerializedName("manager")
private List<String> mManagers;
private List<Leasee> mLeasees;
private DateTime mLeaseExpiration;
private int mPercentIncrease;
private int mDueDate;
private String mDepositBank;
private String mDepositDescription;
}

Categories

Resources