How to parse nested JSON with GSON - java

Lets say i have a JSON like:
{
"assignments": [
{
'id': '111',
'activities': [
{
'activity': 'Activity 1',
},
{
'activity': 'Activity 2'
}
]
},
{
'id': '2222',
'Activities': [
{
'activity': 'Activity 1'
}
]
}
]
}
And I'm using GSON to parse it. I have a correctly set up Javabean and can access id without problems. How do i get the activities per id / object?
EDIT: more code:
public class Assignment {
private String id;
public String getId() {
return id;
}
}
Gson mGson= new Gson();
assignmentList=mGson.fromJson(json, AssignmentList.class);
assignmentList.getAssignments().get(0).getId());

I'd create another Bean for Activities since it is a JSON object in itself.
class Assignment {
private String id;
private List<Activity> activities; //getters and setters for this.
public String getId() {
return id;
}
}
class Activity {
private String activity; //Getters and setters
}
Gson mGson= new Gson();
assignmentList=mGson.fromJson(json, AssignmentList.class);
assignmentList.getAssignments().get(0).getActivities.get(1);

If there are only primitive types in the class, just defining two Java classes should be enough, just make sure not to inherit the class from GenericJson, it breaks the recursive operation of a Gson parser.

Related

Jackson Deserialization of dynamic data fails,

public class Baseproperties
{
#JsonProperty("id")
private String id ;
private Integer ccode;
//...set and geters
}
public class Person
{
#JsonProperty("name")
private String name ;
private Integer age;
#JsonProperty("props")
private Baseproperties bprop;
//...set and geters
}
public class Cars
{
#JsonProperty("model")
private String Model ;
private Integer yearOfMake;
#JsonProperty("props")
private Baseproperties bprop;
//...set and geters
}
public MessageWrapper
{
#JsonProperty("ct")
private String classType;
private Object data;
//...set and geters
}
I need to serialise MessageWrapper class to json, but the approach fails due to unable to desearialize the Object data;
here i am reading the classType and desearializing it to either Person or CarType
//Person
{
"name": "arnold",
"age": 21
}
//car
{
"model": "Moriz",
"yearOfMake": 1892
}
//example MessageWrapper
String s= "{
"ct": "<packagename>.car",
"data": {
"model": "Moriz",
"yearOfMake": 1892
"props":{
"id" : "12312",
"ccode" :33
}
}
}"
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
MessageWrapper mw = mapper.readValue(s, MessageWrapper.class);
if(mw.getclassType().toString().equals("<packagename>.car"))
Cars cw = mapper.readValue(mw.getData(), Cars.class);
but cw is wrong // serialise fails.
This is because there is no ObjectMapper::readValue method that takes Object as first argument.
By default with your approach Jackson will deserialize your data field to LinkedHashMap because you have given it Object type.
To then deserialize this value manually you will have to use ObjectMapper::convertValue and passing Cars.class as argument :
Cars cw = mapper.convertValue(mw.getData(), Cars.class);
And also get rid of :
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
as it does not seem to be needed here.
And just to add, I am not sure that approach with such dynamic data is good because, if you will be creating more and more types of objects you will end up with a tower of ifs or colosal switch statement.

Subclass as json parent object

I have a requirement where I need a subclass as object while creating a json payload.
EventBase
public class EventBase {
#JsonProperty("event_id")
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
PaymentCapture (the sub class)
#JsonTypeName("resource")
public class PaymentCapture extends EventBase {
#JsonProperty("parent_payment")
private String parentPayment;
public String getParentPayment() {
return parentPayment;
}
public void setParentPayment(String parentPayment) {
this.parentPayment = parentPayment;
}
}
And I need a json payload in below form:
{
"id": "someId",
"resource": {
"parent_payment": "23434"
}
}
I can understand this violates inheritance relationship, but just want to know if there is any solution available or not.
The closest I could get when having similar problem was creating an adapter class. This solution prints one extra property which might be possible to be ignored if for example some inheritance was allowed but I assume that not and use just the declared classes in addition to the adapter, which is like:
#RequiredArgsConstructor
public class PaymentCaptureAdapterClass {
#NonNull
#JsonProperty
private PaymentCapture resource;
#JsonProperty
private String getId() {
return resource.getId();
}
}
using this with code:
ObjectMapper om = new ObjectMapper();
om.enable(SerializationFeature.INDENT_OUTPUT);
PaymentCapture pc = new PaymentCapture();
pc.setId("someId");
pc.setParentPayment("23434");
log.info("\n{}", om.writeValueAsString(new AdapterClass(pc)));
prints something like:
{
"resource" : {
"event_id" : "someId", // might be able to be ignored
"parent_payment" : "23434"
},
"id" : "someId"
}

Deserialize JSON entities to POJO with ID references

Lets say we have the following JSON example:
{
"teachers": [{
"id": "abc",
"payment": 10,
"name": "xyz",
"clases": ["1", "3"]
}, {
"id": "qwe",
"payment": 12,
"name": "xcv",
"classes": ["1", "2"]
}],
"classes": [{
"id": "1",
"room": 7
}, {
"id": "2",
"room": 1
}, {
"id": "3",
"room": 2
}]
}
I would like to deserialize it to Java objects (getters/setters ommited):
class Teacher {
private String id;
private double payment;
private String name;
private List<CLassRoom> classRooms;
}
class ClassRoom {
private String id;
private int room;
}
As you see, we have a references here. I know I can deserialize it with Jackson (and would like to) but the problem is that I cannot touch DTO itself (so annotations are not possible, would also like to avoid wrappers (many classes)). Also, it would be nice if the "configuration" of deserialization was in separate file (json schema for example). I would also like to avoid some tags given by user - he should only pass me the values. Moreover, he should know where is the error, if he made some mistake.
Also, it would be nice if I could manipulate name of field in json (some clients may have different habits).
I didn't find anything which satisffied all of above requirements(entity reference and error handling are the most important). However - I just have heard about json schema, so maybe it provides such functionality (but I didn't find it though). Any helpful reference/example/lib? I will appreciate any help.
Just to be correct - imagine that the given json is a RELATIONAL database snapshot of the instance. I just want to create whole entity like the hibernate (or actually JPA) does :)
1. add jar of import org.json.JSONObject.
2. JSONObject object = new JSONObject(list)
2.1 object.has("teachers") if it is exists
2.2 JSONArray teacherArray = (JSONArray) object.get("teachers");
2.3 JSONObject teacherJsonObject = teacherArray .getJSONObject(0);
(if you have more than jsonobject in json arrary then itrate it.)
2.4 if(teacherJsonObject .has("id"))//you can check existence like this.
String id=teacherJsonObject .getString("id");
String payment=teacherJsonObject .getString("payment");
String name=teacherJsonObject .getString("name");
It may not be the best solution, but it's a working one.
Let's create a Parser class like the following:
public class Parser {
private List<Teacher> teachers;
private List<ClassRoom> classes;
public void parse() {
for (Teacher teacher : teachers) {
for (String classRoomId : teacher.getClasses()) {
for (ClassRoom classRoom : classes) {
if (classRoom.getId().equals(classRoomId)) {
teacher.getClassRooms().add(classRoom);
}
}
}
}
}
}
Modify your ClassRoom class to have a getter on the id field:
public class ClassRoom {
private String id;
private int room;
public String getId() {
return id;
}
}
And your Teacher class to get the Ids of classes AND the classRooms references:
public class Teacher {
private String id;
private double payment;
private String name;
private String[] classes;
private List<ClassRoom> classRooms = new ArrayList<>();
public String[] getClasses() {
return classes;
}
public List<ClassRoom> getClassRooms() {
return classRooms;
}
}
If you use the Gson library, you could then just parse your JSON like that:
Gson gson = new Gson();
Parser parser = gson.fromJson(jsonString, Parser.class);
parser.parse;
Now, every teacher will have their classRooms correctly referenced.

How to correctly use Jackson, Dropwizard and JSON patterns

I'm trying to workout how I should be structuring my JSON objects to best comply with http://jsonapi.org/format/
If I used the following classes:
Page (main object)
public class Page {
#Id
#ObjectId
private String id; //Used for mongodb
#JsonProperty
private String type;
#JsonProperty
private Attribute attributes;
#JsonProperty
private Meta meta;
public Page() {
// Jackson deserialization
}
// Getters and setters
}
Attributes (nested into page)
public class Attribute {
#JsonProperty
private Date created = new Date();
#JsonProperty
private String title;
#JsonProperty
private String body;
public Attribute() {
// Jackson deserialization
}
public Attribute(Date created, String title, String body) {
this.created = created;
this.title = title;
this.body = body;
}
// Getters and setters
}
Meta (nested into page)
public class Meta {
#JsonProperty
private List<String> authors;
public Meta() {
}
public Meta(List<String> authors) {
this.authors = authors;
}
// Getters and setters
}
I can create this object with a post such as:
{
"type": "page",
"attributes": {
"title": "This is the title",
"body": "<p>This is a long section of html, other stuff</p>"
},
"meta": {
"authors": [
"Steve",
"John",
"Sam"
]
}
}
And the resulting JSON object is created:
{
id:"56cbed5036f66b05dc2df841",
type:"page",
attributes:{
created:1456205138886,
title:"This is the title",
body:"<p>This is a long section of html, other stuff</p>"
},
meta:{
authors:[
"Steve",
"John",
"Sam"
]
}
}
The question(s):
Is creating multiple classes the way I have the optimal/correct way of creating nested JSON objects, and should I be trying to wrap this all inside "data:" as per the link above states is a MUST do? If that is the case should I create a single POJO called Data which contains the Page object?
When looking for information around this type of thing all I seem to be able to find is people asking how to deserialize JSON into POJOs, which isn't what I'm looking for.
Really want to find some best practises here for writing APIs.
you should start then from what kind of 'behavior' your objects expose and how you want your API to expose.
Alhough there is no silver bullet, there is a good amount of literature around which can guide you in the right direction of how to model your API (and in turn your objects)
here are a few links:
http://restcookbook.com
http://www.infoq.com/minibooks/domain-driven-design-quickly
Value vs Entity objects (Domain Driven Design)
Personally, and -in general-, I create POJOs, but like also #cricket_007 mentioned it's kind of opinionated.
HTH.

Mule JSON data to objects

I have a json object
data = {
'ad': {
"date":"2013-06-05",
"catagory":"6",
"subcatagory":"5",
"text":"John john",
"ssn":"1306743999",
"email":"jonbrynjar#365.is",
"phone":"8612001"
},
'cc-info': {
"amount": "70",
"cardNumber": "4222222222222",
"expiryDate": "1215",
"currency": "ISK"
},
'dates': [
{ 'date': '2013-06-18', 'media': 1 },
{ 'date': '2013-06-19', 'media': 3 }
]
}
Then I have a subflow that takes the "cc-info" part of that json object and uses that data to call a third party service.
To extract the "cc-info" part of the json object I use #JsonAutoDetect class
#JsonAutoDetect
public class Handpoint {
private String amount;
private String cardNumber;
private String expiryDate;
private String currency;
public String getAmount() { return this.amount; }
public void setAmount(String amount) { this.amount = amount; }
public String getCardNumber() { return this.cardNumber; }
public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }
public String getExpiryDate() { return this.expiryDate; }
public void setExpiryDate(String expireDate) { this.expiryDate = expireDate; }
public String getCurrency() { return this.currency; }
public void setCurrency(String currency) { this.currency = currency; }
}
When I send in the whole json object I get an error.
The question is: Do I have to put every variable in the json object into my #JsonAutoDetect class ?
Or what would be best practice for this.
I have verified that my code works when I just send in the "cc-info" part of the json objcet.
You don't need that #JsonAutoDetect, it doesn't do anything different from defaults without arguments.
But if your question is whether you can just ignore unknown properties, answer is yes. Here are couple of ways.
For example:
mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
would do the trick.
There is an easier way to convert your JSON element to a series of objects. Have you tried the Google GSon library? There is a sample:
import com.google.gson.Gson;
Gson gson = new Gson();
Handpoint testing = gson.fromJson(data, Handpoint.class);
System.out.println("Amount: " + testing.getAmount());
On the other hand, if you want to deserialize the dates, that contain arrays, you'd better take a look here:
Gson Array deserialization

Categories