Retrofit: Parse nested JSON elements to a list - java

I'm having difficulty trying to parse this JSON response into a list of "properties" elements. My JSON looks like this:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"mag": 6.6,
"place": "192km ESE of Tadine, New Caledonia"
}
},
{
"type": "Feature",
"properties": {
"mag": 7.5,
"place": "168km ESE of Tadine, New Caledonia"
}
},
{
"type": "Feature",
"properties": {
"mag": 6,
"place": "155km ESE of Tadine, New Caledonia"
}
}
]
}
This is response contains Earthquake details so basically each "properties" within "features" is the POJO I want, but all of them just in a List. Here is my Earthquake class:
public class Earthquake {
#SerializedName("mag")
private double magnitude;
#SerializedName("place")
private String location;
public Earthquake(double magnitude, String location) {
this.magnitude = magnitude;
this.location = location;
}
// getters
}
I've tried doing custom deserialization suggested here. It gives me the error
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
suggesting that I'm trying to parse a JsonObject instead of a JsonArray. Here is the deserializer I used.
public class EarthquakeDeserializer implements JsonDeserializer<ArrayList<Earthquake>> {
#Override
public ArrayList<Earthquake> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// get list of "features"
JsonElement features = json.getAsJsonObject().get("features");
JsonArray earthquakeElements = new JsonArray();
for (JsonElement feature : features.getAsJsonArray()){
JsonElement properties = feature.getAsJsonObject().get("properties");
earthquakeElements.add(properties);
}
Type listType = new TypeToken<ArrayList<Earthquake>>(){}.getType();
return new Gson().fromJson(earthquakeElements, listType);
}
}
Any ideas as to what's going on here?

you can create this kind of a POJO class for your Json, No matter if you want just single part of your response body, you need to create POJO for whole response and from that POJO you need to get appropriate attributes. ->
This is your main json object ->
public class Example {
#SerializedName("type")
#Expose
private String type;
#SerializedName("features")
#Expose
private List<Feature> features = null;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Feature> getFeatures() {
return features;
}
public void setFeatures(List<Feature> features) {
this.features = features;
}
}
this is your feature class ->
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Feature {
#SerializedName("type")
#Expose
private String type;
#SerializedName("properties")
#Expose
private Properties properties;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
this is your properties class ->
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Properties {
#SerializedName("mag")
#Expose
private Integer mag;
#SerializedName("place")
#Expose
private String place;
public Integer getMag() {
return mag;
}
public void setMag(Integer mag) {
this.mag = mag;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
}
After creating this classes, you can serialize the JSON to POJO via GSON library, you can refer to HussainAbbas's answer for how to do it.
Now you can get anything via creating object of response class, and via that object you can access any property you want. Thanks.

check this out
package com.example;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("type")
#Expose
private String type;
#SerializedName("features")
#Expose
private List<Feature> features = null;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Feature> getFeatures() {
return features;
}
public void setFeatures(List<Feature> features) {
this.features = features;
}
}
-----------------------------------com.example.Feature.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Feature {
#SerializedName("type")
#Expose
private String type;
#SerializedName("properties")
#Expose
private Properties properties;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
-----------------------------------com.example.Properties.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Properties {
#SerializedName("mag")
#Expose
private Integer mag;
#SerializedName("place")
#Expose
private String place;
public Integer getMag() {
return mag;
}
public void setMag(Integer mag) {
this.mag = mag;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
}
After this add this... in your retrofit response
Gson gson = new Gson()
String data = gson.toJson(response.body());
LoginResponse loginResponse = gson.fromJson(dataString,LoginResponse.class);
Example example = gson.fromJson(dataString,Example.class);
String feature_proprerties_mag = example.getFeatures().getProperties().getMag

Related

Jira API Automation - REST Assured

Am trying to automate Jira Issue Creation via REST API with Java Rest Assured. The following are my code snippets.
I need to reframe the following JSON in Java and pass it to the Body.
{
"fields": {
"project": {
"id": "13204"
},
"summary": "welcome to testing1",
"issuetype": {
"id": "3"
},
"reporter": {
"name": "parthiban.selvaraj"
},
"priority": {
"id": "3"
},
"description": "description",
"customfield_10201": {
"id": "10608"
}
}
}
Below is my Java code with getter and setter:
package jira;
import com.google.gson.Gson;
import io.restassured.RestAssured;
import io.restassured.authentication.PreemptiveBasicAuthScheme;
import io.restassured.http.ContentType;
import io.restassured.http.Method;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import java.util.List;
public class home {
public static void main (String args[]){
System.out.println("Welcome");
RestAssured.baseURI = "http://##.###.##.##:####/jira/rest/api/2/issue/";
PreemptiveBasicAuthScheme authScheme = new PreemptiveBasicAuthScheme();
authScheme.setUserName("########");
authScheme.setPassword("#######");
RestAssured.authentication = authScheme;
getterSetter values=new getterSetter();
values.setProject(13204);
values.setSummary("Checking via REST Assured");
values.setIssueType(3);
values.setReporter("#######");
values.setPriority(3);
values.setDescription("Welcome to JAVA World");
//Updating sprint name custom field value
values.setCustomfield_10201(10608);
Gson gson=new Gson();
String json= gson.toJson(values);
System.out.println("JSON Values " + json);
RequestSpecification httpRequest = RestAssured.given().header("Content-Type",
"application/json").body(json);
System.out.println(httpRequest + " Request ");
Response response = httpRequest.request(Method.POST, "");
System.out.println(response.getStatusCode());
String responseBody = response.getBody().asString();
System.out.println("response " + responseBody);
JsonPath jsonPath = new JsonPath(responseBody);
}
}
Getter and Setter File:
package jira;
import javax.xml.bind.annotation.XmlRootElement;
//#XmlRootElement
public class getterSetter {
private int project;
private int issueType;
private String reporter;
private String summary;
private int priority;
private String description;
private int customfield_10201;
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public void setProject(int project){
this.project=project;
}
public int getProject() {
return project;
}
public int getIssueType() {
return issueType;
}
public void setIssueType(int issueType) {
this.issueType = issueType;
}
public String getReporter() {
return reporter;
}
public void setReporter(String reporter) {
this.reporter = reporter;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getCustomfield_10201() {
return customfield_10201;
}
public void setCustomfield_10201(int customfield_10201) {
this.customfield_10201 = customfield_10201;
}
}
I understand JSON format which I am passing through request Body is wrong. Can anyone help me to pass correct JSON format in Request Body.
I tested in Postman with the above JSON format Issue created successfully in my Instance.
For the above code am hitting with
response code 500 and Internal Server Error.
According to the JSON string as the payload to create Jira issue, you can directly create several corresponding classes as follows:
class IssueInfo {
private Field fields;
//general getters and setters
}
class Field {
private Project project;
private String summary;
private IssueType issuetype;
private Reporter reporter;
private Priority priority;
private String description;
private Customfield10201 customfield_10201;
//general getters and setters
}
class Project {
private String id;
//general getters and setters
}
class IssueType {
private String id;
//general getters and setters
}
class Reporter {
private String name;
//general getters and setters
}
class Priority {
private String id;
//general getters and setters
}
class Customfield10201 {
private String id;
//general getters and setters
}
After assigning value of each required field, you can pass the instance of IssueInfo as request body.

How to convert Json into a Java bean object?

I am trying to convert a complex object into related Java beans. However, some sub class can be not generated correctly.
I am just using simulate MS Adaptive card to create a set of Java beans classes. When I call Gson package or Alibaba fastJson package to parse my json data. it always shows the super class type.
This is just an experiment to test Gson & fastJson whether it can convert complex objects. which is running on the Android studio.
My demo json is like following:
{
"type": "AdaptiveCard",
"version": "1.0",
"id": "workloadQCactivity 20",
"speak": "activity 20 <break time=\"300ms\"/> at<break time=\"300ms\"/> <break time=\"300ms\"/>building<break time=\"300ms\"/>A<break time=\"300ms\"/>floor<break time=\"300ms\"/>1<break time=\"300ms\"/>room<break time=\"300ms\"/>1<break time=\"300ms\"/> ",
"body": [{
"type": "Container",
"items": [{
"type": "ColumnSet",
"columns": [{
"type": "Column",
"width": "Stretch",
"items": [{
"type": "TextBlock",
"size": "large",
"weight": "bolder",
"text": "activity 20 at building A floor 1 room 1",
"wrap": true
}]
}]
}]
}],
"actions": [{
"type": "Action.ShowCard",
"card": {
"type": "AdaptiveCard",
"version": "1.0",
"body": [{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"isSubtle": true,
"text": "have thing to check list1",
"wrap": true
}, {
"type": "TextBlock",
"weight": "bolder",
"isSubtle": true,
"text": "this is section 1",
"wrap": true
}, {
"type": "TextBlock",
"isSubtle": true,
"text": "q1 of s1",
"wrap": true
}, {
"type": "TextBlock",
"isSubtle": true,
"text": "q2 of s2",
"wrap": true
}, {
"type": "TextBlock",
"weight": "bolder",
"isSubtle": true,
"text": "this is section 2",
"wrap": true
}, {
"type": "TextBlock",
"isSubtle": true,
"text": "q1 of s22",
"wrap": true
}, {
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"isSubtle": true,
"text": "have checklist 2",
"wrap": true
}, {
"type": "TextBlock",
"weight": "bolder",
"isSubtle": true,
"text": "section of the second checklist",
"wrap": true
}, {
"type": "TextBlock",
"isSubtle": true,
"text": "qqqqqq",
"wrap": true
}]
},
"title": "Show Checklist"
}]
}
Therefore, I just follow MS adaptive card to create following java beans.
First class: AdaptiveTypedElement
public class AdaptiveTypedElement {
#JsonProperty("additionalPorperties")
public Map<String, Object> additionalPorperties = new HashMap<String, Object>();
//#JsonProperty("type")
//public String type;
#JsonProperty("id")
public String id;
}
Second class: AdaptiveTypedElement
public class AdaptiveElement extends AdaptiveTypedElement {
#JsonProperty("spacing")
public AdaptiveSpacing spacing ;
#JsonProperty("separator")
public boolean separator = false;
#JsonProperty("speak")
public String speak;
#JsonProperty("separation")
// public AdaptiveSeparationStyle separation;
public String separation;
}
Third class AdaptiveContainer:
public class AdaptiveContainer extends AdaptiveElement {
#JsonProperty("typeName")
public String typeName = "Container";
#JsonProperty("type")
public String type = "Container";
#JsonProperty("items")
public List<AdaptiveElement> items = new ArrayList<AdaptiveElement>();
#JsonProperty("selectAction")
public AdaptiveAction selectAction = null;
#JsonProperty("style")
public AdaptiveContainerStyle style = AdaptiveContainerStyle.Default;
}
public class AdaptiveColumnSet extends AdaptiveElement {
#JsonProperty("typeName")
public final String typeName = "ColumnSet";
#JsonProperty("type")
public final String type = "ColumnSet";
#JsonProperty("columns")
public List<AdaptiveColumn> columns = new ArrayList<AdaptiveColumn>();
#JsonProperty("selectionAction")
public AdaptiveAction selectionAction = null;
}
public class AdaptiveColumn extends AdaptiveContainer{
#JsonProperty("typeName")
public final String typeName = "Column";
#JsonProperty("type")
public final String type = "Column";
#JsonProperty("size")
public String size;
#JsonProperty("with")
public String with;
}
public class AdaptiveAction {
#JsonProperty("title")
public String title;
#JsonProperty("speak")
public String speak;
}
public class AdaptiveShowCardAction extends AdaptiveAction {
#JsonProperty("typeName")
public final String typeName = "Action.ShowCard";
#JsonProperty("type")
public final String Type = "Action.ShowCard";
#JsonProperty("card")
public AdaptiveCard card;
}
public class AdaptiveTextBlock extends AdaptiveElement{
#JsonProperty("typeName")
public String typeName = "TextBlock";
#JsonProperty("type")
public String type = "TextBlock";
#JsonProperty("text")
public String text = "";
#JsonProperty("size")
public AdaptiveTextSize size;
#JsonProperty("weight")
public AdaptiveTextWeight weight;
#JsonProperty("color")
public AdaptiveTextColor color;
#JsonProperty("horizontalAlignment")
public AdaptiveHorizontalAlignment horizontalAlignment = AdaptiveHorizontalAlignment.Left;
#JsonProperty("wrap")
public boolean wrap = false;
#JsonProperty("isSubtle")
public boolean isSubtle = false;
#JsonProperty("maxLines")
public int maxLines = 0;
#JsonProperty("maxWidth")
public int maxWidth = 0;
}
public class AdaptiveCard extends AdaptiveTypedElement {
#JsonProperty("contentType")
public final String contentType = "application/vnd.microsoft.card.adaptive";
#JsonProperty("typeName")
public final String typeName = "AdaptiveCard";
#JsonProperty("type")
public String type = "AdaptiveCard";
#JsonProperty("body")
public List<AdaptiveElement> body = new ArrayList<AdaptiveElement>();
#JsonProperty("actions")
public List<AdaptiveAction> actions = new ArrayList<AdaptiveAction>();
#JsonProperty("speak")
public String speak = null;
#JsonProperty("title")
public String title;
#JsonProperty("version")
//public AdaptiveSchemaVersion version = null;
public String version = null;
#JsonProperty("fallbackText")
public String fallbackText = null;
#JsonProperty("lang")
public String lang = null;
}
In the end, I finally got AdaptiveCard Object. See my code:
return JSON.parseObject(attachJson, AdaptiveCard.class). Note that I add "implementation 'com.alibaba:fastjson:1.2.54'" in my Android Studio
When I check this object, I found the Body data member should be class "AdaptiveContainer " not "AdaptiveElement". I was wondering why it did not following subclass mechanism of OOP & OOD. I am expecting "AdaptiveContainer", but actually output is "AdaptiveElement".
enter image description here
rib-pet, your question has a far to big example. Anyway I tried to create a java class mapping for your sample using GSON
Action.java
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Action {
#SerializedName("type")
#Expose
private String type;
#SerializedName("card")
#Expose
private Card card;
#SerializedName("title")
#Expose
private String title;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
Body.java
package com.example;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Body {
#SerializedName("type")
#Expose
private String type;
#SerializedName("items")
#Expose
private List<Item> items = null;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
Body_.java (dependend on your wished model you should integrate this class better in some existing
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Body_ {
#SerializedName("type")
#Expose
private String type;
#SerializedName("size")
#Expose
private String size;
#SerializedName("weight")
#Expose
private String weight;
#SerializedName("isSubtle")
#Expose
private Boolean isSubtle;
#SerializedName("text")
#Expose
private String text;
#SerializedName("wrap")
#Expose
private Boolean wrap;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
public Boolean getIsSubtle() {
return isSubtle;
}
public void setIsSubtle(Boolean isSubtle) {
this.isSubtle = isSubtle;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Boolean getWrap() {
return wrap;
}
public void setWrap(Boolean wrap) {
this.wrap = wrap;
}
}
Card.java
package com.example;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Card {
#SerializedName("type")
#Expose
private String type;
#SerializedName("version")
#Expose
private String version;
#SerializedName("body")
#Expose
private List<Body_> body = null;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public List<Body_> getBody() {
return body;
}
public void setBody(List<Body_> body) {
this.body = body;
}
}
Column.java
package com.example;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Column {
#SerializedName("type")
#Expose
private String type;
#SerializedName("width")
#Expose
private String width;
#SerializedName("items")
#Expose
private List<Item_> items = null;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getWidth() {
return width;
}
public void setWidth(String width) {
this.width = width;
}
public List<Item_> getItems() {
return items;
}
public void setItems(List<Item_> items) {
this.items = items;
}
}
Example.java
package com.example;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("type")
#Expose
private String type;
#SerializedName("version")
#Expose
private String version;
#SerializedName("id")
#Expose
private String id;
#SerializedName("speak")
#Expose
private String speak;
#SerializedName("body")
#Expose
private List<Body> body = null;
#SerializedName("actions")
#Expose
private List<Action> actions = null;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSpeak() {
return speak;
}
public void setSpeak(String speak) {
this.speak = speak;
}
public List<Body> getBody() {
return body;
}
public void setBody(List<Body> body) {
this.body = body;
}
public List<Action> getActions() {
return actions;
}
public void setActions(List<Action> actions) {
this.actions = actions;
}
}
Item.java
package com.example;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Item {
#SerializedName("type")
#Expose
private String type;
#SerializedName("columns")
#Expose
private List<Column> columns = null;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Column> getColumns() {
return columns;
}
public void setColumns(List<Column> columns) {
this.columns = columns;
}
}
Item_.java also here better integration needed
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Item_ {
#SerializedName("type")
#Expose
private String type;
#SerializedName("size")
#Expose
private String size;
#SerializedName("weight")
#Expose
private String weight;
#SerializedName("text")
#Expose
private String text;
#SerializedName("wrap")
#Expose
private Boolean wrap;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Boolean getWrap() {
return wrap;
}
public void setWrap(Boolean wrap) {
this.wrap = wrap;
}
}
hope it helps!
I've figured out this solution via the following solution:
JSONObject and JSONArray
JSONArray body = contentObj.getJSONArray("body");
JSONArray actions = contentObj.getJSONArray("actions");
title.setText(body.getJSONObject(0).getString("text"));

Cannot deserialize generic class hierarchy using Jackson

I'm receiving, for instance, this JSON from an external vendor (where payload can be variable):
{
"payload": {
"enrolledAt": "2018-11-05T00:00:00-05:00",
"userId": "99c7ff5c-2c4e-423f-abeb-2e5f3709a42a"
},
"requestId": "80517bb8-2a95-4f15-9a73-fcf3752a1147",
"eventType": "event.success",
"createdAt": "2018-11-05T16:55:13.762-05:00"
}
I'm trying to model these using this class:
public final class Notification<T extends AbstractModel> {
#JsonProperty("requestId")
private String requestId;
#JsonProperty("eventType")
private String eventType;
#JsonProperty("createdAt")
private ZonedDateTime createdAt;
private T payload;
#JsonCreator
public Notification(#JsonProperty("payload") T payload) {
requestId = UUID.randomUUID().toString();
eventType = payload.getType();
createdAt = ZonedDateTime.now();
this.payload = payload;
}
// getters
}
...and then having these possible (generic) types:
public abstract class AbstractModel {
private String userId;
private Type type;
#JsonCreator
AbstractModel(#JsonProperty("companyUserId") String userId, #JsonProperty("type") Type type) {
this.userId = userId;
this.type = type;
}
// getters
public enum Type {
CANCEL("event.cancel"),
SUCCESS("event.success");
private final String value;
Type(String value) {
this.value = value;
}
public String getValue() { return value; }
}
}
public final class Success extends AbstractModel {
private ZonedDateTime enrolledAt;
#JsonCreator
public Success(String userId, #JsonProperty("enrolledAt") ZonedDateTime enrolledAt) {
super(userId, Type.SUCCESS);
this.enrolledAt = enrolledAt;
}
// getters
}
public final class Cancel extends AbstractModel {
private ZonedDateTime cancelledAt;
private String reason;
#JsonCreator
public Cancel(String userId, #JsonProperty("cancelledAt") ZonedDateTime cancelledAt,
#JsonProperty("reason") String reason) {
super(userId, Type.CANCEL);
this.cancelledAt = cancelledAt;
this.reason = reason;
}
// getters
}
The application is based on Spring Boot, so I'm deserializing the JSON like:
#Component
public final class NotificationMapper {
private ObjectMapper mapper;
public NotificationMapper(final ObjectMapper mapper) {
this.mapper = mapper;
}
public Optional<Notification<? extends AbstractModel>> deserializeFrom(final String thiz) {
try {
return Optional.of(mapper.readValue(thiz, new NotificationTypeReference()));
} catch (final Exception e) { /* log errors here */ }
return Optional.empty();
}
private static final class NotificationTypeReference extends TypeReference<Notification<? extends AbstractModel>> { }
}
...but eventually since I'm posting this right here, Jackson doesn't like any of that so far. I've tried several things like: JsonTypeInfo and JsonSubTypes, but I can't change the JSON input.
Anyone? Any clue(s)?
We ended up adding another key/value pair in the JSON – the contract was indeed modified a little bit to accommodate that "private" key/value pair.
In any case, if somebody runs into the same issue, this is the solution for the approach:
...
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
#JsonIgnoreProperties("_type")
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "_type")
#JsonSubTypes({
#JsonSubTypes.Type(value = Cancel.class, name = "_type"),
#JsonSubTypes.Type(value = Fail.class, name = "_type"),
#JsonSubTypes.Type(value = Success.class, name = "_type"),
})
public abstract class AbstractModel {
private String userId;
private Type type;
AbstractModel() { }
AbstractModel(final String userId, final Type type) {
this.userId = userId;
this.type = type;
}
// getters, toString, etc.
public enum Type {
CANCEL("event.cancelled"),
FAIL("event.failed"),
SUCCESS("event.success");
private final String value;
Type(String value) {
this.value = value;
}
public String getValue() { return value; }
}
}

How to make POJO and parse recursive objects using jackson?

I have a below JSON response that I am getting back from a rest service. Now I need to deserialize below JSON response into a POJO. I am working with Jackson.
{
"pagination": {
"number": 1,
"entriesPerPage": 200,
"total": 3
},
"postings": [{
"categories": [{
"taskid": "79720",
"name": "Sunglasses",
"parentCategory": {
"taskid": "394",
"name": "Sunglasses & Fashion Eyewear",
"parentCategory": {
"taskid": "2340",
"name": "Men's Accessories",
"parentCategory": {
"taskid": "10987",
"name": "Clothing, Shoes & Accessories"
}
}
}
}]
},
{
"categories": [{
"taskid": "12980",
"name": "Toys",
"parentCategory": {
"taskid": "123",
"name": "Fashion",
"parentCategory": {
"taskid": "78765",
"name": "Men's Accessories"
}
}
}]
}],
"total": 2
}
In above json, postings is a JSON array which can have multiple posting json object. Now categories is also JSON array. Now tricky part is I can have multiple levels of parentCategory inside each category object and I don't know how many levels of parentCategory I will have. Give above JSON, I need to extract taskid of each category and taskId of last parentCategory. So it should be like this:
79720=10987
12980=78765
Where 79720 is taskId of category and 10987 is the taskId of last parentCategory. Similarly for other one.
Below is my code where I am deserializing JSON into my POJO by making an http call:
ResponseEntity<Stuff> responseEntity = HttpClient.getInstance().getClient()
.exchange(URI.create(endpoint), HttpMethod.POST, requestEntity, Stuff.class);
Stuff response = responseEntity.getBody();
List<Posting> postings = response.getPostings();
for(Posting postings : postings) {
//....
}
Confusion I have is - How to make POJO for above JSON? I tried using jsonschema2pojo but it's not making right classes for parentCategory. Since I can have nested levels of parentCategory which I don't know before hand.
Is this possible to do using Jackson?
This is the POJO class generated for Category and ParentCategory. I am not sure whether I need to make any changes here so that I can parse recursive parentCategory object.
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({"taskid", "name", "parentCategory"})
public class Category {
#JsonProperty("taskid")
private String taskid;
#JsonProperty("name")
private String name;
#JsonProperty("parentCategory")
private ParentCategory parentCategory;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
...
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({"taskid", "name", "parentCategory"})
public class ParentCategory {
#JsonProperty("taskid")
private String taskid;
#JsonProperty("name")
private String name;
#JsonProperty("parentCategory")
private ParentCategory parentCategory;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
...
}
This time I would approach with GSon
Which manages recursion with less effort.
Pojos can be made from json2pojo website, simply choosing GSon as JSon library.
These are the Pojos:
import java.io.Serializable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Pagination implements Serializable
{
public Pagination() {
super();
// TODO Auto-generated constructor stub
}
#SerializedName("number")
#Expose
private Integer number;
#SerializedName("entriesPerPage")
#Expose
private Integer entriesPerPage;
#SerializedName("total")
#Expose
private Integer total;
private final static long serialVersionUID = 5114620434202813556L;
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public Integer getEntriesPerPage() {
return entriesPerPage;
}
public void setEntriesPerPage(Integer entriesPerPage) {
this.entriesPerPage = entriesPerPage;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
}
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Categories implements Serializable
{
public Categories() {
super();
// TODO Auto-generated constructor stub
}
#SerializedName("pagination")
#Expose
private Pagination pagination;
#SerializedName("postings")
#Expose
private List<Posting> postings = null;
#SerializedName("total")
#Expose
private Integer total;
private final static long serialVersionUID = 4589512697836725240L;
public Pagination getPagination() {
return pagination;
}
public void setPagination(Pagination pagination) {
this.pagination = pagination;
}
public List<Posting> getPostings() {
return postings;
}
public void setPostings(List<Posting> postings) {
this.postings = postings;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
}
import java.io.Serializable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Category implements Serializable
{
public Category() {
super();
// TODO Auto-generated constructor stub
}
#SerializedName("taskid")
#Expose
private String taskid;
#SerializedName("name")
#Expose
private String name;
#SerializedName("parentCategory")
#Expose
private ParentCategory parentCategory;
private final static long serialVersionUID = -2127963072268572959L;
public String getTaskid() {
return taskid;
}
public void setTaskid(String taskid) {
this.taskid = taskid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ParentCategory getParentCategory() {
return parentCategory;
}
public void setParentCategory(ParentCategory parentCategory) {
this.parentCategory = parentCategory;
}
}
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Posting implements Serializable
{
#SerializedName("categories")
#Expose
private List<Category> categories = null;
private final static long serialVersionUID = 8135185675909461065L;
public List<Category> getCategories() {
return categories;
}
public Posting() {
super();
// TODO Auto-generated constructor stub
}
public void setCategories(List<Category> categories) {
this.categories = categories;
}
}
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class ParentCategory implements Serializable
{
#SerializedName("taskid")
#Expose
private String taskid;
#SerializedName("name")
#Expose
private String name;
#SerializedName("parentCategory")
#Expose
private List<ParentCategory> parentCategory;
public ParentCategory() {
super();
// TODO Auto-generated constructor stub
}
private final static long serialVersionUID = -5989749742502713615L;
public String getTaskid() {
return taskid;
}
public void setTaskid(String taskid) {
this.taskid = taskid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<ParentCategory> getParentCategory() {
return parentCategory;
}
public void setParentCategory(List<ParentCategory> parentCategory) {
this.parentCategory = parentCategory;
}
}
So this is a test implementation:
Pagination pagination = new Pagination();
pagination.setNumber(1);
pagination.setEntriesPerPage(200);
pagination.setTotal(3);
Categories categories = new Categories();
categories.setPagination(pagination);
Category category = new Category();
category.setName("Sunglasses");
category.setTaskid("79720");
List<Category> categoryList = new ArrayList<Category>();
Posting posting = new Posting();
posting.setCategories(categoryList);
List<ParentCategory> parentCategoryList = new ArrayList<ParentCategory>();
List<ParentCategory> parentCategoryList2 = new ArrayList<ParentCategory>();
ParentCategory parentCategory1 = new ParentCategory();
parentCategory1.setName("Sunglasses & Fashion Eyewear");
parentCategory1.setTaskid("394");
ParentCategory parentCategory2 = new ParentCategory();
parentCategory2.setName("Men's Accessories");
parentCategory2.setTaskid("2340");
ParentCategory parentCategory3 = new ParentCategory();
parentCategory3.setName("Clothing, Shoes & Accessories");
parentCategory3.setTaskid("10987");
parentCategoryList.add(parentCategory2);
parentCategoryList2.add(parentCategory3);
parentCategory2.setParentCategory(parentCategoryList2);
parentCategory1.setParentCategory(parentCategoryList);
category.setParentCategory(parentCategory1);
Gson gson = new Gson();
System.out.println(gson.toJson(category));
...and this is the resulting Json:
{
"taskid": "79720",
"name": "Sunglasses",
"parentCategory": {
"taskid": "394",
"name": "Sunglasses \u0026 Fashion Eyewear",
"parentCategory": [{
"taskid": "2340",
"name": "Men\u0027s Accessories",
"parentCategory": [{
"taskid": "10987",
"name": "Clothing, Shoes \u0026 Accessories"
}]
}]
}
}
Maybe still need a bit of tweaking but you got the idea.
Hope it helps!
EDIT: as the op requests I add the Jackson Version.
Pojos:
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({"taskid", "name", "parentCategory"})
public class ParentCategory implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#JsonProperty("taskid")
private String taskid;
#JsonProperty("name")
private String name;
#JsonProperty("parentCategory")
private ParentCategory parentCategory;
public String getTaskid() {
return taskid;
}
public void setTaskid(String taskid) {
this.taskid = taskid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ParentCategory getParentCategory() {
return parentCategory;
}
public void setParentCategory(ParentCategory parentCategory) {
this.parentCategory = parentCategory;
}
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({"taskid", "name", "parentCategory"})
public class Category implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#JsonProperty("taskid")
private String taskid;
#JsonProperty("name")
private String name;
#JsonProperty("parentCategory")
private ParentCategory parentCategory;
public String getTaskid() {
return taskid;
}
public void setTaskid(String taskid) {
this.taskid = taskid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ParentCategory getParentCategory() {
return parentCategory;
}
public void setParentCategory(ParentCategory parentCategory) {
this.parentCategory = parentCategory;
}
}
public class Test {
public static void main(String[] args) throws JsonProcessingException {
Category category = new Category();
category.setName("Sunglasses");
category.setTaskid("79720");
List<Category> categoryList = new ArrayList<Category>();
List<ParentCategory> parentCategoryList = new ArrayList<ParentCategory>();
List<ParentCategory> parentCategoryList2 = new ArrayList<ParentCategory>();
ParentCategory parentCategory1 = new ParentCategory();
parentCategory1.setName("Sunglasses & Fashion Eyewear");
parentCategory1.setTaskid("394");
ParentCategory parentCategory2 = new ParentCategory();
parentCategory2.setName("Men's Accessories");
parentCategory2.setTaskid("2340");
ParentCategory parentCategory3 = new ParentCategory();
parentCategory3.setName("Clothing, Shoes & Accessories");
parentCategory3.setTaskid("10987");
parentCategory1.setParentCategory(parentCategory2);
parentCategory2.setParentCategory(parentCategory3);
category.setParentCategory(parentCategory1);
ObjectMapper objectMapper = new ObjectMapper();
String testJson = objectMapper.writeValueAsString(category);
System.out.println(testJson);
}
}
And here again a test result:
{
"taskid": "79720",
"name": "Sunglasses",
"parentCategory": {
"taskid": "394",
"name": "Sunglasses & Fashion Eyewear",
"parentCategory": {
"taskid": "2340",
"name": "Men's Accessories",
"parentCategory": {
"taskid": "10987",
"name": "Clothing, Shoes & Accessories"
}
}
}
}

Trouble converting Json Array into Pojo with array of pojos

JSON String
{
"order":{
"address":{
"city":"seattle"
},
"orderItem":[
{
"itemId":"lkasj",
"count":2
},
{
"itemId":"ldka",
"count":3
}
]
}
}
Order Class
public class Order {
private OrderItem[] orderItems;
private CustomerAddress address;
Order(OrderItem[] orderItems, CustomerAddress address ) {
this.orderItems = orderItems;
this.address = address;
}
public OrderItem[] getOrderItems() {
return orderItems;
}
public void setOrderItems(OrderItem[] orderItems) {
this.orderItems = orderItems;
}
public CustomerAddress getAddress() {
return address;
}
public void setAddress(CustomerAddress address) {
this.address = address;
}
}
My OrderItem class
package com.cbd.backend.model;
import org.springframework.data.annotation.Id;
public class OrderItem {
#Id
private String id;
private String itemId;
private String count;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
unit Test that blows up
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
}
Unit test to demonstrate issue
package com.cbd.backend.model;
import com.google.gson.Gson;
import org.junit.Test;
import static org.junit.Assert.*;
public class OrderTest {
Gson gson = new Gson();
#Test
public void gsonToOrder() {
Order order = gson.fromJson( a, Order.class );
assertNotNull(order);
assertNotNull(order.getOrderItems()[0]);
}
private final String a = "{ \"order\": { \"address\": { \"city\": \"seattle\" },\"orderItem\":[{ \"itemId\":\"lkasj\", \"count\":2 }, { \"itemId\":\"ldka\", \"count\":3 } ] } }";
}
Should I be using something other than gson or am i constructing this incorrectly
There are two problems in your code:
The root element of your JSON is "order", but the class does not have a property with this name. Try changing you model or just removing the element from the JSON.
There is a mismatch in the name of the "orderItem" property. It is plural in the class, but singular in the JSON.
To sum it up, the following JSON will work without any changes to the code.
{
"address":{
"city":"seattle"
},
"orderItems":[
{
"itemId":"lkasj",
"count":2
},
{
"itemId":"ldka",
"count":3
}
]
}
Also, "count" as it appears in the JSON seems to be numeric, so you might want to change the type of OrderItem.count to int or java.lang.Integer.

Categories

Resources