Gson; list of objects in list of objects - java

I have json which looks like this:
[{
"id":14,
"namelanguage1":"Książka",
"namelanguage2":"das Buch",
"tags":
[{
"id":2,
"name":"Szkoła",
"language_user_id":null,
"created_at":"2014-04-11T17:30:28.356Z",
"updated_at":"2014-04-11T17:30:28.356Z",
"user_id":2
}],
"language1_id":5,
"language2_id":1,
},
{
"id":15,
"namelanguage1":"das Fußball",
"namelanguage2":"Piłka nożna",
"tags":[{
"id":2,
"name":"Szkoła",
"language_user_id":null,
"created_at":"2014-04-11T17:30:28.356Z",
"updated_at":"2014-04-11T17:30:28.356Z",
"user_id":2
},
{
"id":3,
"name":"Sport",
"language_user_id":null,
"created_at":"2014-04-11T17:30:33.059Z",
"updated_at":"2014-04-11T17:30:36.769Z",
"user_id":2
}],
"language1_id":1,
"language2_id":5,
}]
I don't know how to get a tag id. Now I have this:
public class Word {
#SerializedName("id")
public long id;
#SerializedName("namelanguage1")
public String nameLanguage1;
#SerializedName("namelanguage2")
public String nameLanguage2;
#SerializedName("language1_id")
public long language1_id;
#SerializedName("language2_id")
public long language2_id;
public ArrayList<Tag> tags;
and getters and setters for it. I don't know how to get id of tags. I try understand this example: example from stackoverflow but still I don't know how to do this.
It's how i have it in code:
words = VolleyDemoApplication.obtain().getGson()
.fromJson(response, new TypeToken<ArrayList<Word>>() {
}.getType());
I get values from word like this:
word.getNameLanguage1() + " " +word.getLanguage1_id() + " " + word.getNameLanguage2()+ " " + word.getLanguage2_id() + " " + word.getTags().
And here word.getTags(). and I don't know what write then.

There are a couple of things to point out, i have no clue why this code worked for you, when the json you have printed is not correct.
The actual format is :
[
{
"id": 14,
"namelanguage1": "aaa",
"namelanguage2": "das Buch",
"tags": [
{
"id": 2,
"name": "bbb",
"language_user_id": null,
"created_at": "2014-04-11T17:30:28.356Z",
"updated_at": "2014-04-11T17:30:28.356Z",
"user_id": 2
}
],
"language1_id": 5,
"language2_id": 1 ->> remove the comma here thats in your json text
},
{
"id": 15,
"namelanguage1": "zzz",
"namelanguage2": "yyy",
"tags": [
{
"id": 2,
"name": "ccc",
"language_user_id": null,
"created_at": "2014-04-11T17:30:28.356Z",
"updated_at": "2014-04-11T17:30:28.356Z",
"user_id": 2
},
{
"id": 3,
"name": "Sport",
"language_user_id": null,
"created_at": "2014-04-11T17:30:33.059Z",
"updated_at": "2014-04-11T17:30:36.769Z",
"user_id": 2
}
],
"language1_id": 1,
"language2_id": 5 ->> remopve the comma here too
}
]
The class word will need a SerializedName for tags arraylist.
#SerializedName(value="tags")
public ArrayList<Tag> tags;
You will need to create the tags class too:
public class Tag {
#SerializedName(value="id")
private int id;
#SerializedName(value="name")
private String tagName;
#SerializedName(value="language_user_id")
private String languageUserId;
#SerializedName(value="created_at")
private String createdAt;
#SerializedName(value="updated_at")
private String updatedAt;
#SerializedName(value="user_id")
private int userId;
// create getters and setters or else change the modifiers to public
}
You will access id in Tag class like this:
words.get(0).tags.get(0).getId(); ->> i am using 0 since its the first element, you will need a loop for this
or
words.get(0).tags.get(0).id;
Hope that helps.

Related

Deserialize complex JSON to Java, classes nested multiple levels deep

I am trying to make the Json output from Cucumber into a single Java object. This contains objects nested four levels deep, and I am having trouble deserializing it. I am presently using Jackson, but open to suggestions.
Here is my Json code:
{
"line": 1,
"elements": [
{
"line": 3,
"name": "Converteren centimeters naar voeten/inches",
"description": "",
"id": "applicatie-neemt-maten-in-cm-en-converteert-ze-naar-voet/inch,-en-vice-versa;converteren-centimeters-naar-voeten/inches",
"type": "scenario",
"keyword": "Scenario",
"steps": [
{
"result": {
"duration": 476796588,
"status": "passed"
},
"line": 4,
"name": "maak Maten-object aan met invoer in \"centimeters\"",
"match": {
"arguments": [
{
"val": "centimeters",
"offset": 37
}
],
"location": "StepDefinition.maakMatenObjectAanMetInvoerIn(String)"
},
"keyword": "Given "
},
{
"result": {
"duration": 36319,
"status": "passed"
},
"line": 5,
"name": "ik converteer",
"match": {
"location": "StepDefinition.converteerMaten()"
},
"keyword": "When "
},
{
"result": {
"duration": 49138,
"status": "passed"
},
"line": 6,
"name": "uitvoer bevat maat in \"voeten/inches\"",
"match": {
"arguments": [
{
"val": "voeten/inches",
"offset": 23
}
],
"location": "StepDefinition.uitvoerBevatMaatIn(String)"
},
"keyword": "Then "
}
]
},
{
"line": 8,
"name": "Converteren voeten/inches naar centimeters",
"description": "",
"id": "applicatie-neemt-maten-in-cm-en-converteert-ze-naar-voet/inch,-en-vice-versa;converteren-voeten/inches-naar-centimeters",
"type": "scenario",
"keyword": "Scenario",
"steps": [
{
"result": {
"duration": 84175,
"status": "passed"
},
"line": 9,
"name": "maak Maten-object aan met invoer in \"voeten/inches\"",
"match": {
"arguments": [
{
"val": "voeten/inches",
"offset": 37
}
],
"location": "StepDefinition.maakMatenObjectAanMetInvoerIn(String)"
},
"keyword": "Given "
},
{
"result": {
"duration": 23928,
"status": "passed"
},
"line": 10,
"name": "ik converteer",
"match": {
"location": "StepDefinition.converteerMaten()"
},
"keyword": "When "
},
{
"result": {
"duration": 55547,
"status": "passed"
},
"line": 11,
"name": "uitvoer bevat maat in \"centimeters\"",
"match": {
"arguments": [
{
"val": "centimeters",
"offset": 23
}
],
"location": "StepDefinition.uitvoerBevatMaatIn(String)"
},
"keyword": "Then "
}
]
}
],
"name": "Applicatie neemt maten in cm en converteert ze naar voet/inch, en vice versa",
"description": "",
"id": "applicatie-neemt-maten-in-cm-en-converteert-ze-naar-voet/inch,-en-vice-versa",
"keyword": "Feature",
"uri": "sample.feature"
}
I have tried a number of different approaches. First I used nested inner classes, but it appeared you had to make them static, which I feared would not work since I have multiple instances of the same object within one (multiple "element"-objects in the root, for example). Then I tried putting them in separate classes, with Json annotations. Here's where that got me (omitting setters):
public class CucumberUitvoer {
private String name;
private String description;
private String id;
private String keyword;
private String uri;
private int line;
#JsonProperty("elements")
private List<FeatureObject> elements;
public CucumberUitvoer(){}
}
public class FeatureObject {
private String name;
private String description;
private String id;
private String type;
private String keyword;
private int line;
#JsonProperty("steps")
private List<StepObject> steps;
public FeatureObject() {
}
}
public class StepObject {
#JsonProperty("result")
private ResultObject result;
private String name;
private String given;
private String location;
private String keyword;
private int line;
#JsonProperty("match")
private MatchObject match;
public StepObject(){}
}
public class ResultObject {
private int duration;
private String status;
public ResultObject(){}
}
public class MatchObject {
#JsonProperty("arguments")
private List<ArgumentObject> arguments;
private String location;
public MatchObject(){}
}
public class ArgumentObject {
private String val;
private String offset;
public ArgumentObject(){}
}
For clarification, here's a class diagram of how the nesting works.
This solution gives me the following error:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of nl.icaprojecten.TestIntegratieQuintor.JSONInterpreter.CucumberUitvoer out of START_ARRAY token
Here is the code doing the actual mapping:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
CucumberUitvoer obj1 = null;
try {
obj1 = mapper.readValue(json, CucumberUitvoer.class);
} catch (IOException e) {
e.printStackTrace();
}
Is there a quick fix to this approach to make it work, or should I try something entirely different?
Ok I spent some time debugging and trying to figure out what was the problem, and finally was something pretty obvious.
implements Serializable
Thats the line I added to MatchObject and worked.
When we try to deserialize some object first we have to make those classes implements the interface Serializable
I just tried your sample code and oddly, it works.
Can you please double check your imports, if the JSON is coming in as provided and the getters, setters, constructors are actually there?
You can get the idea from this code to deserialize,
public class testCustomDeSerializer extends JsonDeserializer<test> {
public testCustomDeSerializer() {
this(null);
}
public TestCustomDeSerializer(Class t) {
// super(t);
}
#Override
public Test deserialize(JsonParser p, DeserializationContext ctx) throws IOException, JsonProcessingException {
ObjectCodec objectCodec = p.getCodec();
JsonNode node = objectCodec.readTree(p);
ObjectMapper objectMapper = new ObjectMapper();
Test test= new Test();
test.setId(node.get("line").asText());
List<elements> elementList = new ArrayList<>();
JsonNode elementsNode = node.get("elements");
Iterator<JsonNode> slaidsIterator = elementsNode.elements();
while (slaidsIterator.hasNext()) {
Steps steps= new Steps();
JsonNode slaidNode = slaidsIterator.next();
JsonNode stepNode= (JsonNode) slaidNode.get("Steps");
BoundingPoly in = objectMapper.readValue(stepNode.toString(), Steps.class);
elementsNode.setSteps(in);
/// continue
return
}
Hope it helps

Dynamic Json Parsing Using Gson Android

I have a json as mentioned below.
{
"product": [
{
"classification": "abc",
"ABC": [
{
"classification": "abc",
"name": "abc new product one",
"price": "10775.0000",
},
{
"classification": "abc",
"name": "abc new product two",
"price": "12725.0000",
}
]
},
{
"classification": "def",
"DEF": [
{
"classification": "def",
"name": "def product one",
"price": "728.0000",
},
{
"classification": "def",
"name": "def product two",
"price": "1263.0000",
},
]
}
],
"status": "OK",
"message": "success"
}
In the above json, the key in capital letter is dynamic
(Ex: ABC, DEF)
. I've created pojo class as below:
public class ProductResponse{
private String status;
private String message;
private List<Products>;
Getters And Setters
}
public class Products{
private String classification;
}
I'm struggling to write the next part in Products pojo class, As the keys which are in capitals
(Ex: ABC, DEF)
are dynamic. I am using volley library for getting the data and for parsing I'm using gson library. Please help me out.
You can't have a dynamic name. the reason being is the name in your json needs to be linked to an attribute in your object.
I recommend you to add a "classification" attribute in your json and your model as following :
{
"type": "def",
" results": [
{
"name": "def product one",
"price": "728.0000",
},
{
"name": "def product two",
"price": "1263.0000",
},
]
}
public final class ProductResponse{
private String status;
private String message;
private List<Products> product = new Arraylist<>();
// Getters And Setters
}
public final class Products{
private String type; // type of product // ABC or DEF
private List<Result> results = new Arraylist<>();
// Getters And Setters
}
public final class Result{
private String name;
private String price;
// Getters And Setters
}
Your products class has now a list of results associated to a classification !
Hope it helps !
Your problem is the dynamic key, which I found is not dynamic. As I can see, For each element in the product array, the classification key's value is the next key. Only difference is that they are in capital letters.
{
"classification": "def",
"DEF": [
{
"classification": "def",
"name": "def product one",
"price": "728.0000",
},
{
"classification": "def",
"name": "def product two",
"price": "1263.0000",
},
]
}
As in, here "classification": "def" and the next key is DEF. What I would do here is get the value of classification key, capitalize all the letters in the string and then use it as the key.

Mapping JSONArray in RestTemplate Spring

I am trying to map this JSONArray using Spring RestTemplate:
[{
"Command": "/usr/sbin/sshd -D",
"Created": 1454501297,
"Id": "e00ca61f134090da461a3f39d47fc0cbeda77fbbc0610439d3c16a932686b612",
"Image": "ubuntu:latest",
"Labels": {
},
"Names": [
"/nova-c1896fbd-1309-4da2-8d77-b4fe4c02fa8e"
],
"Ports": [
],
"Status": "Up 2 hours"
}, {
"Command": "/usr/sbin/sshd -D",
"Created": 1450106126,
"Id": "7ffc9dbdd200e2c23adec442abd656ed57306955332697cb7da979f36ebf3b22",
"Image": "ubuntu:latest",
"Labels": {
},
"Names": [
"/nova-93b9ae40-8135-48b7-ac17-12094603b28c"
],
"Ports": [
],
"Status": "Up 2 hours"
}]
Here is ContainersInfo class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class ContainersInfo {
private String Id;
private List<String> Names;
public String getId() {
return Id;
}
public void setId(String id) {
Id = id;
}
public List<String> getNames() {
return Names;
}
public void setNames(List<String> names) {
Names = names;
}
}
However I get null when I want to get the data:
ContainersInfo[] containers = syncRestTemplate.getForObject("http://192.168.1.2:4243/containers/json?all=1", ContainersInfo[].class);
for (int i = 0; i < containers.length; i++)
System.out.println("id:" + containers[i].getId());
The resulting output is as follows:
id:null
id:null
Any idea, what I should do?
Your JSON field names are in pascal case as opposed to camel case (which is usually the case). Set Jackson naming strategy to PascalCaseStrategy, i.e by adding #JsonNaming(PascalCaseStrategy.class) annotation into ContainersInfo class.

Parse key-value pair type data structures using gson

I am trying to parse following response using gson library:
{
"successful": true,
"resultObject": {
"areas": {
"New york": [{
"id": 1,
"name": "Some area 1 in NY"
}, {
"id": 2,
"name": "Some area 2 in NY"
}, {
"id": 3,
"name": "Some area 3 in NY"
}],
"San Fransisco": [{
"id": 1,
"name": "Some area 1 in SF"
}, {
"id": 2,
"name": "Some area 2 in SF"
}, {
"id": 3,
"name": "Some area 3 in SF"
}],
"New Jersey": [{
"id": 1,
"name": "Some area 1 in NJ"
}, {
"id": 2,
"name": "Some area 2 in NJ"
}, {
"id": 3,
"name": "Some area 3 in NJ"
}]
}
}
}
I was trying to use
Pair<String, City[]>[] cities;
to parse the areas key but it is coming as null every time. Java code for City class:
public class City {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "ClassPojo [id = " + id + ", name = " + name + "]";
}
}
Any help is appreciated.
If the whole json needs to be parsed, I suggest you use a custom class, like this one:
public class GsonContainer{
public boolean successful;
public ResultObject resultObject;
public static class ResultObject{
public Map<String, List<City>> areas;
}
}//end class
If it is only the json under areas, use a Map<String,List<City>> instead.

GSON deserialization of object arrays

I have a class with the following attributes
public class JenkinsServer
{
private String url;
private String mode;
private String nodeName;
private String nodeDescription;
private String description;
private boolean useSecurity;
private boolean quietingDown;
private JenkinsServerView primaryView;
private List< JenkinsJob > jobs;
private List< JenkinsServerView > views;
}
Now I want GSON to deserialize/map a json document to it. It works well, except for my lists - they are empty. The json document looks as follows (snippet):
"jobs": [
{
"name": "AnotherJob",
"url": "https://build.example.com/jenkins/job/AnotherJob/",
"color": "disabled"
},
{
"name": "AnotherJob2",
"url": "https://build.example.com/jenkins/job/Build%20CI%20Build/",
"color": "blue"
},
"views": [
{
"name": "-All Views",
"url": "https://build.example.com/jenkins/view/-All%Views/"
},
{
"name": "Alle",
"url": "https://build.example.com/jenkins/"
},
The mapping works, even for the single instance of
JenkinsServerView primaryView
but not for the Lists. I'm starting the mapping this way:
Gson gson = gsonBuilder.create();
JenkinsServer server = gson.fromJson( reader, JenkinsServer.class );
looks your json data that you are trying to parse is invalid.
In your json jobs and views are arrays and both of them doesn't have the closing brace at the end.
The valid json will be as follows: (Observe the closing braces at the end of the array)
{
"jobs": [
{
"name": "AnotherJob",
"url": "https://build.example.com/jenkins/job/AnotherJob/",
"color": "disabled"
},
{
"name": "AnotherJob2",
"url": "https://build.example.com/jenkins/job/Build%20CI%20Build/",
"color": "blue"
}
],
"views": [
{
"name": "-All Views",
"url": "https://build.example.com/jenkins/view/-All%Views/"
},
{
"name": "Alle",
"url": "https://build.example.com/jenkins/"
}
]
}

Categories