How to skip wrapper object in jackson json deserialization - android

I am trying to deserialize the following string using the jackson.
{
"roomName": "u8ec29p0j7q2m9f",
"broadcastPresenceRoles": {
"broadcastPresenceRole": [
"moderator",
"participant",
"visitor"
]
},
"owners": {
"owner": "anewuser#shahanshah"
},
"admins": {
"admin": "sanjeet#shahanshah"
},
"members": null,
"outcasts": {
"outcast": [
"sawan#shahanshah",
"sus#shahanshah"
]
},
"ownerGroups": {
"ownerGroup": "Friends"
}
}
This the response from the openfire rest apis.
I am having problem with the wrapper object wrapping the arrays.
Here
"broadcastPresenceRoles": {
"broadcastPresenceRole": [
"moderator",
"participant",
"visitor"
]
},
I tried this to unwrap the container but not getting success. I don't think writing wrapper classes is good idea (Since I will have to write several wrapper classes).Also I need the generalized solution so i can use it with other responses since the apis is having other responses in the similar wrapped objects format. Thanks in advance.

You can create a custom annotation with #JsonDeserialize inside and create a custom JsonDeserializer that implements ContextualDeserializer. The idea is inspired from the solution you mentioned but it is more general to unwrap any one property in a json object.
Following is the custom annotation using #JacksonAnnotationsInside as annotation container contains #JsonDeserialize:
#Retention(RetentionPolicy.RUNTIME)
#JacksonAnnotationsInside
#JsonDeserialize(using = JsonUnwrapPropertyDeserializer.class)
public #interface JsonUnwrapProperty {
}
and the custom JsonDeserializer that implements ContextualDeserializer:
public class JsonUnwrapPropertyDeserializer extends JsonDeserializer<Object> implements ContextualDeserializer {
private JavaType unwrappedJavaType;
private String unwrappedProperty;
#Override
public JsonDeserializer<?> createContextual(final DeserializationContext deserializationContext, final BeanProperty beanProperty) throws JsonMappingException {
unwrappedProperty = beanProperty.getMember().getName();
unwrappedJavaType = beanProperty.getType();
return this;
}
#Override
public Object deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {
final TreeNode targetObjectNode = jsonParser.readValueAsTree().get(unwrappedProperty);
return jsonParser.getCodec().readValue(targetObjectNode.traverse(), unwrappedJavaType);
}
}
and the usage example:
public class MyBean {
#JsonProperty("broadcastPresenceRoles")
#JsonUnwrapProperty
private List<String> broadcastPresenceRole;
#JsonProperty("admins")
#JsonUnwrapProperty
private String admin;
// constructor, getter and setter
}
#JsonProperty is to locate the wrapper object and #JsonUnwrappProperty is to deserialize the json object and extract a property into the annotated field.
Edited:
Following is an example with ObjectMapper:
String json = "{\n" +
" \"broadcastPresenceRoles\": {\n" +
" \"broadcastPresenceRole\": [\n" +
" \"moderator\",\n" +
" \"participant\",\n" +
" \"visitor\"\n" +
" ]\n" +
" },\n" +
" \"admins\": {\n" +
" \"admin\": \"sanjeet#shahanshah\"\n" +
" }\n" +
"}";
final ObjectMapper mapper = new ObjectMapper();
final MyBean myBean = mapper.readValue(json, MyBean.class);
System.out.println(myBean.getBroadcastPresenceRole());
System.out.println(myBean.getAdmin());
Output:
[moderator, participant, visitor]
sanjeet#shahanshah

I created a variation that solved the NPE based on #wilson response
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
#Retention(RetentionPolicy.RUNTIME)
#JacksonAnnotationsInside
#JsonDeserialize(using = JsonUnwrapProperty.JsonUnwrapPropertyDeserializer.class)
public #interface JsonUnwrapProperty {
public static class JsonUnwrapPropertyDeserializer extends JsonDeserializer<Object>
implements ContextualDeserializer {
private JavaType unwrappedJavaType;
private String unwrappedProperty;
#Override
public JsonDeserializer<?> createContextual(final DeserializationContext deserializationContext,
final BeanProperty beanProperty) throws JsonMappingException {
unwrappedProperty = beanProperty.getMember().getName();
unwrappedJavaType = beanProperty.getType();
return this;
}
#Override
public Object deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext)
throws IOException {
System.out.println(String.format("Ignoring %s in %s/%s", unwrappedProperty,
jsonParser.currentName(), jsonParser.nextFieldName()));
JsonToken token = jsonParser.nextValue();
return jsonParser.getCodec().readValue(jsonParser, unwrappedJavaType);
}
}
}

Related

Parsing deep nested JSON data

I am newbie learning Android and ran into an issue when trying to parse my API data into my app. It calls fine, but I am unsure why I am getting the error.
Here is the API data that is pulled:
{
"report":{
"sr":"28",
"type":"Basic",
"food":{
"ndbno":"01009",
"name":"Cheese, cheddar",
"ds":"Standard Reference",
"manu":"",
"ru":"g",
"nutrients":[
{
"nutrient_id":"255",
"name":"Water",
"derivation":"NONE",
"group":"Proximates",
"unit":"g",
"value":"37.02",
"measures":[
{
"label":"cup, diced",
"eqv":132,
"eunit":"g",
"qty":1,
"value":"48.87"
}
]
}
]
}
}
}
And here is my code:
JSONArray JA = new JSONArray(macros);
for (int i =0; i <JA.length(); i++){
JSONObject JO = (JSONObject) JA.get(i);
singleParsed = "Name:" + JO.get("report") + "\n" +
"Item:" + JO.get("reports.food.name") + "\n" +
"Nutrient:" + JO.get("reports.food.nutrients.name") + "\n" +
"Serving suggestions:" + JO.get("reports.food.measures.value");
So far that hasn't worked for me.
W/System.err: org.json.JSONException: Value {"report":{"sr":"28","type":"Basic","food":{"ndbno":"01009","name":"Cheese, cheddar","ds":"Standard Reference","manu":"","ru":"g","nutrients":[{"nutrient_id":"255","name":"Water","derivation":"NONE","group":"Proximates","unit":"g","value":"37.02","measures":[{"label":"cup, diced","eqv":132,"eunit":"g","qty":1,"value":"48.87"},{"label":"cup, melted","eqv":244,"eunit":"g","qty":1,"value":"90.33"},{"label":"cup, shredded","eqv":113,"eunit":"g","qty":1,"value":"41.83"},{"label":"oz","eqv":28.35,"eunit":"g","qty":1,"value":"10.50"},{"label":"cubic inch","eqv":17,"eunit":"g","qty":1,"value":"6.29"},{"label":"slice (1 oz)","eqv":28,"eunit":"g","qty":1,"value":"10.37"}]},{"nutrient_id":"208","name":"Energy","derivation":"NC","group":"Proximates","unit":"kcal","value":"404","measures":[{"label":"cup, diced","eqv":132,"eunit":"g","qty":1,"value":"533"},{"label":"cup, melted","eqv":244,"eunit":"g","qty":1,"value":"986"},{"label":"cup, shredded","eqv":113,"eunit":"g","qty":1,"value":"457"},{"label":"oz","eqv":28.35,"eunit":"g","qty":1,"value":"115"},{"label":"cubic inch","eqv":17,"eunit":"g","qty":1,"value":"69"},{"label":"slice (1 oz)","eqv":28,"eunit":"g","qty":1,"value":"113"}]},{"nutrient_id":"203","name":"Protein","derivation":"NONE","group":"Proximates","unit":"g","value":"22.87","measures":[{"label":"cup, diced","eqv":132,"eunit":"g","qty":1,"value":"30.19"},{"label":"cup, melted","eqv":244,"eunit":"g","qty":1,"value":"55.80"},{"label":"cup, shredded","eqv":113,"eunit":"g","qty":1,"value":"25.84"},{"label":"oz","eqv":28.35,"eunit":"g","qty":1,"value":"6.48"},{"label":"cubic inch","eqv":17,"eunit":"g","qty":1,"value":"3.89"},{"label":"slice (1 oz)","eqv":28,"eunit":"g","qty":1,"value":"6.40"}]},{"nutrient_id":"204","name":"Total lipid (fat)","derivation":"NONE","group":"Proximates","unit":"g","value":"33.31","measures":[{"label":"cup, diced","eqv":132,"eunit":"g","qty":1,"value":"43.97"},{"label":"cup, melted","eqv":244,"eunit":"g","qty":1,"value":"81.28"},{"label":"cup, shredded","eqv":113,"eunit":"g","qty":1,"value":"37.64"},{"label":"oz","eqv":28.35,"eunit":"g","qty":1,"value":"9.44"},{"label":"cubic inch","eqv":17,"eunit":"g","qty":1,"value":"5.66"},{"label":"slice (1 oz)","eqv":28,"eunit":"g","qty":1,"value":"9.33"}]},{"nutrient_id":"205","name":"Carbohydrate, by difference","derivation":"NC","group":"Proximates","unit":"g","value":"3.09","measures":[{"label":"cup, diced","eqv":132,"eunit":"g","qty":1,"value":"4.08"},{"label":"cup, melted","eqv":244,"eunit":"g","qty":1,"value":"7.54"},{"label":"cup, shredded","eqv":113,"eunit":"g","qty":1,"value":"3.49"},{"label":"oz","eqv":28.35,"eunit":"g","qty":1,"value":"0.88"},{"label":"cubic inch","eqv":17,"eunit":"g","qty":1,"value":"0.53"},{"label":"slice (1 oz)","eqv":28,"eunit":"g","qty":1,"value":"0.87"}]},{"nutrient_id":"291","name":"Fiber, total dietary","derivation":"NONE","group":"Proximates","unit":"g","value":"0.0","measures":[{"label":"cup, diced","eqv":132,"eunit":"g","qty":1,"value":"0.0"},{"label":"cup, melted","eqv":244,"eunit":"g","qty":1,"value":"0.0"},{"label":"cup, shredded","eqv":113,"eunit":"g","qty":1,"value":"0.0"},{"label":"oz","eqv":28.35,"eunit":"g","qty":1,"value":"0.0"},{"label":"cubic inch","eqv":17,"eunit":"g","qty":1,"value":"0.0"},{"label":"slice (1 oz)","eqv":28,"eunit":"g","qty":1,"value":"0.0"}]},{"nutrient_id":"269","name":"Sugars, total","derivation":"AS","group":"Proximates","unit":"g","value":"0.48","measures":[{"label":"cup, diced","eqv":132,"eunit":"g","qty":1,"value":"0.63"},{"label":"cup, melted","eqv":244,"eunit":"g","qty":1,"value":"1.17"},{"label":"cup, shredded","eqv":113,"eunit":"g","qty":1,"value":"0.54"},{"label":"oz","eqv":28.35,"eunit":"g","qty":1,"value":"0.14"},{"label":"cubic inch","eqv":17,"eunit":"g","qty":1,"value":"0.08"},{"label":"slice (1 oz)","eqv":28,"eunit":"g","qty":1,"value":"0.13"}]},{"nutrient_id":"301","name":"Calcium, Ca","derivation":"NONE","group":"Minerals","unit":"mg","value":"710","measures":[{"label":"cup, diced","eqv":132,"eunit":"g","q
at org.json.JSON.typeMismatch(JSON.java:111)
at org.json.JSONArray.<init>(JSONArray.java:96)
at org.json.JSONArray.<init>(JSONArray.java:108)
at com.monreal.deb.macrocalculator.fetchData.doInBackground(fetchData.java:38)
at com.monreal.deb.macrocalculator.fetchData.doInBackground(fetchData.java:17)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
I am extremely grateful for any help that you can provide.
Use Gson for parsing JSON. Its simpler and easier to implement. You just have to define some classes which will contain the parsed information from your JSON. From your JSON structure, you need to have the following classes.
Report.java
public class Report {
public Food food;
public String sr;
public String type;
}
Then Food.java
public class Food {
public Nutrients[] nutrients;
public String manu;
public String name;
public String ndbno;
public String ru;
public String ds;
}
Nutrients.java
public class Nutrients {
public String unit;
public String derivation;
public String name;
public String nutrient_id;
public String value;
public Measures[] measures;
public String group;
}
And finally, Measures.java
public class Measures {
public String eqv;
public String eunit;
public String value;
public String qty;
public String label;
}
Once you have these classes in your project, you are now ready to parse the JSON data using Gson with the following.
Gson gson = new Gson();
Report report = gson.fromJson(yourJsonString, Report.class);
To use Gson, you need to add the following dependency, in your build.gradle file.
dependencies {
compile 'com.google.code.gson:gson:2.8.2'
}
Hope that helps!

Parsing Json Nested array with different key [duplicate]

I have the following JSON text. How can I parse it to get the values of pageName, pagePic, post_id, etc.?
{
"pageInfo": {
"pageName": "abc",
"pagePic": "http://example.com/content.jpg"
},
"posts": [
{
"post_id": "123456789012_123456789012",
"actor_id": "1234567890",
"picOfPersonWhoPosted": "http://example.com/photo.jpg",
"nameOfPersonWhoPosted": "Jane Doe",
"message": "Sounds cool. Can't wait to see it!",
"likesCount": "2",
"comments": [],
"timeOfPost": "1234567890"
}
]
}
The org.json library is easy to use.
Just remember (while casting or using methods like getJSONObject and getJSONArray) that in JSON notation
[ … ] represents an array, so library will parse it to JSONArray
{ … } represents an object, so library will parse it to JSONObject
Example code below:
import org.json.*;
String jsonString = ... ; //assign your JSON String here
JSONObject obj = new JSONObject(jsonString);
String pageName = obj.getJSONObject("pageInfo").getString("pageName");
JSONArray arr = obj.getJSONArray("posts"); // notice that `"posts": [...]`
for (int i = 0; i < arr.length(); i++)
{
String post_id = arr.getJSONObject(i).getString("post_id");
......
}
You may find more examples from: Parse JSON in Java
Downloadable jar: http://mvnrepository.com/artifact/org.json/json
For the sake of the example lets assume you have a class Person with just a name.
private class Person {
public String name;
public Person(String name) {
this.name = name;
}
}
Google GSON (Maven)
My personal favourite as to the great JSON serialisation / de-serialisation of objects.
Gson g = new Gson();
Person person = g.fromJson("{\"name\": \"John\"}", Person.class);
System.out.println(person.name); //John
System.out.println(g.toJson(person)); // {"name":"John"}
Update
If you want to get a single attribute out you can do it easily with the Google library as well:
JsonObject jsonObject = new JsonParser().parse("{\"name\": \"John\"}").getAsJsonObject();
System.out.println(jsonObject.get("name").getAsString()); //John
Org.JSON (Maven)
If you don't need object de-serialisation but to simply get an attribute, you can try org.json (or look GSON example above!)
JSONObject obj = new JSONObject("{\"name\": \"John\"}");
System.out.println(obj.getString("name")); //John
Jackson (Maven)
ObjectMapper mapper = new ObjectMapper();
Person user = mapper.readValue("{\"name\": \"John\"}", Person.class);
System.out.println(user.name); //John
If one wants to create Java object from JSON and vice versa, use GSON or JACKSON third party jars etc.
//from object to JSON
Gson gson = new Gson();
gson.toJson(yourObject);
// from JSON to object
yourObject o = gson.fromJson(JSONString,yourObject.class);
But if one just want to parse a JSON string and get some values, (OR create a JSON string from scratch to send over wire) just use JaveEE jar which contains JsonReader, JsonArray, JsonObject etc. You may want to download the implementation of that spec like javax.json. With these two jars I am able to parse the json and use the values.
These APIs actually follow the DOM/SAX parsing model of XML.
Response response = request.get(); // REST call
JsonReader jsonReader = Json.createReader(new StringReader(response.readEntity(String.class)));
JsonArray jsonArray = jsonReader.readArray();
ListIterator l = jsonArray.listIterator();
while ( l.hasNext() ) {
JsonObject j = (JsonObject)l.next();
JsonObject ciAttr = j.getJsonObject("ciAttributes");
quick-json parser is very straightforward, flexible, very fast and customizable. Try it
Features:
Compliant with JSON specification (RFC4627)
High-Performance JSON parser
Supports Flexible/Configurable parsing approach
Configurable validation of key/value pairs of any JSON Hierarchy
Easy to use # Very small footprint
Raises developer friendly and easy to trace exceptions
Pluggable Custom Validation support - Keys/Values can be validated by configuring custom validators as and when encountered
Validating and Non-Validating parser support
Support for two types of configuration (JSON/XML) for using quick-JSON validating parser
Requires JDK 1.5
No dependency on external libraries
Support for JSON Generation through object serialisation
Support for collection type selection during parsing process
It can be used like this:
JsonParserFactory factory=JsonParserFactory.getInstance();
JSONParser parser=factory.newJsonParser();
Map jsonMap=parser.parseJson(jsonString);
You could use Google Gson.
Using this library you only need to create a model with the same JSON structure. Then the model is automatically filled in. You have to call your variables as your JSON keys, or use #SerializedName if you want to use different names.
JSON
From your example:
{
"pageInfo": {
"pageName": "abc",
"pagePic": "http://example.com/content.jpg"
}
"posts": [
{
"post_id": "123456789012_123456789012",
"actor_id": "1234567890",
"picOfPersonWhoPosted": "http://example.com/photo.jpg",
"nameOfPersonWhoPosted": "Jane Doe",
"message": "Sounds cool. Can't wait to see it!",
"likesCount": "2",
"comments": [],
"timeOfPost": "1234567890"
}
]
}
Model
class MyModel {
private PageInfo pageInfo;
private ArrayList<Post> posts = new ArrayList<>();
}
class PageInfo {
private String pageName;
private String pagePic;
}
class Post {
private String post_id;
#SerializedName("actor_id") // <- example SerializedName
private String actorId;
private String picOfPersonWhoPosted;
private String nameOfPersonWhoPosted;
private String message;
private String likesCount;
private ArrayList<String> comments;
private String timeOfPost;
}
Parsing
Now you can parse using Gson library:
MyModel model = gson.fromJson(jsonString, MyModel.class);
Gradle import
Remember to import the library in the app Gradle file
implementation 'com.google.code.gson:gson:2.8.6' // or earlier versions
Automatic model generation
You can generate model from JSON automatically using online tools like this.
A - Explanation
You can use Jackson libraries, for binding JSON String into POJO (Plain Old Java Object) instances. POJO is simply a class with only private fields and public getter/setter methods. Jackson is going to traverse the methods (using reflection), and maps the JSON object into the POJO instance as the field names of the class fits to the field names of the JSON object.
In your JSON object, which is actually a composite object, the main object consists o two sub-objects. So, our POJO classes should have the same hierarchy. I'll call the whole JSON Object as Page object. Page object consist of a PageInfo object, and a Post object array.
So we have to create three different POJO classes;
Page Class, a composite of PageInfo Class and array of Post Instances
PageInfo Class
Posts Class
The only package I've used is Jackson ObjectMapper, what we do is binding data;
com.fasterxml.jackson.databind.ObjectMapper
The required dependencies, the jar files is listed below;
jackson-core-2.5.1.jar
jackson-databind-2.5.1.jar
jackson-annotations-2.5.0.jar
Here is the required code;
B - Main POJO Class : Page
package com.levo.jsonex.model;
public class Page {
private PageInfo pageInfo;
private Post[] posts;
public PageInfo getPageInfo() {
return pageInfo;
}
public void setPageInfo(PageInfo pageInfo) {
this.pageInfo = pageInfo;
}
public Post[] getPosts() {
return posts;
}
public void setPosts(Post[] posts) {
this.posts = posts;
}
}
C - Child POJO Class : PageInfo
package com.levo.jsonex.model;
public class PageInfo {
private String pageName;
private String pagePic;
public String getPageName() {
return pageName;
}
public void setPageName(String pageName) {
this.pageName = pageName;
}
public String getPagePic() {
return pagePic;
}
public void setPagePic(String pagePic) {
this.pagePic = pagePic;
}
}
D - Child POJO Class : Post
package com.levo.jsonex.model;
public class Post {
private String post_id;
private String actor_id;
private String picOfPersonWhoPosted;
private String nameOfPersonWhoPosted;
private String message;
private int likesCount;
private String[] comments;
private int timeOfPost;
public String getPost_id() {
return post_id;
}
public void setPost_id(String post_id) {
this.post_id = post_id;
}
public String getActor_id() {
return actor_id;
}
public void setActor_id(String actor_id) {
this.actor_id = actor_id;
}
public String getPicOfPersonWhoPosted() {
return picOfPersonWhoPosted;
}
public void setPicOfPersonWhoPosted(String picOfPersonWhoPosted) {
this.picOfPersonWhoPosted = picOfPersonWhoPosted;
}
public String getNameOfPersonWhoPosted() {
return nameOfPersonWhoPosted;
}
public void setNameOfPersonWhoPosted(String nameOfPersonWhoPosted) {
this.nameOfPersonWhoPosted = nameOfPersonWhoPosted;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getLikesCount() {
return likesCount;
}
public void setLikesCount(int likesCount) {
this.likesCount = likesCount;
}
public String[] getComments() {
return comments;
}
public void setComments(String[] comments) {
this.comments = comments;
}
public int getTimeOfPost() {
return timeOfPost;
}
public void setTimeOfPost(int timeOfPost) {
this.timeOfPost = timeOfPost;
}
}
E - Sample JSON File : sampleJSONFile.json
I've just copied your JSON sample into this file and put it under the project folder.
{
"pageInfo": {
"pageName": "abc",
"pagePic": "http://example.com/content.jpg"
},
"posts": [
{
"post_id": "123456789012_123456789012",
"actor_id": "1234567890",
"picOfPersonWhoPosted": "http://example.com/photo.jpg",
"nameOfPersonWhoPosted": "Jane Doe",
"message": "Sounds cool. Can't wait to see it!",
"likesCount": "2",
"comments": [],
"timeOfPost": "1234567890"
}
]
}
F - Demo Code
package com.levo.jsonex;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.levo.jsonex.model.Page;
import com.levo.jsonex.model.PageInfo;
import com.levo.jsonex.model.Post;
public class JSONDemo {
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
try {
Page page = objectMapper.readValue(new File("sampleJSONFile.json"), Page.class);
printParsedObject(page);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void printParsedObject(Page page) {
printPageInfo(page.getPageInfo());
System.out.println();
printPosts(page.getPosts());
}
private static void printPageInfo(PageInfo pageInfo) {
System.out.println("Page Info;");
System.out.println("**********");
System.out.println("\tPage Name : " + pageInfo.getPageName());
System.out.println("\tPage Pic : " + pageInfo.getPagePic());
}
private static void printPosts(Post[] posts) {
System.out.println("Page Posts;");
System.out.println("**********");
for(Post post : posts) {
printPost(post);
}
}
private static void printPost(Post post) {
System.out.println("\tPost Id : " + post.getPost_id());
System.out.println("\tActor Id : " + post.getActor_id());
System.out.println("\tPic Of Person Who Posted : " + post.getPicOfPersonWhoPosted());
System.out.println("\tName Of Person Who Posted : " + post.getNameOfPersonWhoPosted());
System.out.println("\tMessage : " + post.getMessage());
System.out.println("\tLikes Count : " + post.getLikesCount());
System.out.println("\tComments : " + Arrays.toString(post.getComments()));
System.out.println("\tTime Of Post : " + post.getTimeOfPost());
}
}
G - Demo Output
Page Info;
****(*****
Page Name : abc
Page Pic : http://example.com/content.jpg
Page Posts;
**********
Post Id : 123456789012_123456789012
Actor Id : 1234567890
Pic Of Person Who Posted : http://example.com/photo.jpg
Name Of Person Who Posted : Jane Doe
Message : Sounds cool. Can't wait to see it!
Likes Count : 2
Comments : []
Time Of Post : 1234567890
Almost all the answers given requires a full deserialization of the JSON into a Java object before accessing the value in the property of interest. Another alternative, which does not go this route is to use JsonPATH which is like XPath for JSON and allows traversing of JSON objects.
It is a specification and the good folks at JayWay have created a Java implementation for the specification which you can find here: https://github.com/jayway/JsonPath
So basically to use it, add it to your project, eg:
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>${version}</version>
</dependency>
and to use:
String pageName = JsonPath.read(yourJsonString, "$.pageInfo.pageName");
String pagePic = JsonPath.read(yourJsonString, "$.pageInfo.pagePic");
String post_id = JsonPath.read(yourJsonString, "$.pagePosts[0].post_id");
etc...
Check the JsonPath specification page for more information on the other ways to transverse JSON.
Use minimal-json which is very fast and easy to use.
You can parse from String obj and Stream.
Sample data:
{
"order": 4711,
"items": [
{
"name": "NE555 Timer IC",
"cat-id": "645723",
"quantity": 10,
},
{
"name": "LM358N OpAmp IC",
"cat-id": "764525",
"quantity": 2
}
]
}
Parsing:
JsonObject object = Json.parse(input).asObject();
int orders = object.get("order").asInt();
JsonArray items = object.get("items").asArray();
Creating JSON:
JsonObject user = Json.object().add("name", "Sakib").add("age", 23);
Maven:
<dependency>
<groupId>com.eclipsesource.minimal-json</groupId>
<artifactId>minimal-json</artifactId>
<version>0.9.4</version>
</dependency>
The below example shows how to read the text in the question, represented as the "jsonText" variable. This solution uses the Java EE7 javax.json API (which is mentioned in some of the other answers). The reason I've added it as a separate answer is that the following code shows how to actually access some of the values shown in the question. An implementation of the javax.json API would be required to make this code run. The full package for each of the classes required was included as I didn't want to declare "import" statements.
javax.json.JsonReader jr =
javax.json.Json.createReader(new StringReader(jsonText));
javax.json.JsonObject jo = jr.readObject();
//Read the page info.
javax.json.JsonObject pageInfo = jo.getJsonObject("pageInfo");
System.out.println(pageInfo.getString("pageName"));
//Read the posts.
javax.json.JsonArray posts = jo.getJsonArray("posts");
//Read the first post.
javax.json.JsonObject post = posts.getJsonObject(0);
//Read the post_id field.
String postId = post.getString("post_id");
Now, before anyone goes and downvotes this answer because it doesn't use GSON, org.json, Jackson, or any of the other 3rd party frameworks available, it's an example of "required code" per the question to parse the provided text. I am well aware that adherence to the current standard JSR 353 was not being considered for JDK 9 and as such the JSR 353 spec should be treated the same as any other 3rd party JSON handling implementation.
Since nobody mentioned it yet, here is a beginning of a solution using Nashorn (JavaScript runtime part of Java 8, but deprecated in Java 11).
Solution
private static final String EXTRACTOR_SCRIPT =
"var fun = function(raw) { " +
"var json = JSON.parse(raw); " +
"return [json.pageInfo.pageName, json.pageInfo.pagePic, json.posts[0].post_id];};";
public void run() throws ScriptException, NoSuchMethodException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(EXTRACTOR_SCRIPT);
Invocable invocable = (Invocable) engine;
JSObject result = (JSObject) invocable.invokeFunction("fun", JSON);
result.values().forEach(e -> System.out.println(e));
}
Performance comparison
I wrote JSON content containing three arrays of respectively 20, 20 and 100 elements. I only want to get the 100 elements from the third array. I use the following JavaScript function to parse and get my entries.
var fun = function(raw) {JSON.parse(raw).entries};
Running the call a million times using Nashorn takes 7.5~7.8 seconds
(JSObject) invocable.invokeFunction("fun", json);
org.json takes 20~21 seconds
new JSONObject(JSON).getJSONArray("entries");
Jackson takes 6.5~7 seconds
mapper.readValue(JSON, Entries.class).getEntries();
In this case Jackson performs better than Nashorn, which performs much better than org.json.
Nashorn API is harder to use than org.json's or Jackson's. Depending on your requirements Jackson and Nashorn both can be viable solutions.
I believe the best practice should be to go through the official Java JSON API which are still work in progress.
There are many JSON libraries available in Java.
The most notorious ones are: Jackson, GSON, Genson, FastJson and org.json.
There are typically three things one should look at for choosing any library:
Performance
Ease of use (code is simple to write and legible) - that goes with features.
For mobile apps: dependency/jar size
Specifically for JSON libraries (and any serialization/deserialization libs), databinding is also usually of interest as it removes the need of writing boiler-plate code to pack/unpack the data.
For 1, see this benchmark: https://github.com/fabienrenaud/java-json-benchmark I did using JMH which compares (jackson, gson, genson, fastjson, org.json, jsonp) performance of serializers and deserializers using stream and databind APIs.
For 2, you can find numerous examples on the Internet. The benchmark above can also be used as a source of examples...
Quick takeaway of the benchmark: Jackson performs 5 to 6 times better than org.json and more than twice better than GSON.
For your particular example, the following code decodes your json with jackson:
public class MyObj {
private PageInfo pageInfo;
private List<Post> posts;
static final class PageInfo {
private String pageName;
private String pagePic;
}
static final class Post {
private String post_id;
#JsonProperty("actor_id");
private String actorId;
#JsonProperty("picOfPersonWhoPosted")
private String pictureOfPoster;
#JsonProperty("nameOfPersonWhoPosted")
private String nameOfPoster;
private String likesCount;
private List<String> comments;
private String timeOfPost;
}
private static final ObjectMapper JACKSON = new ObjectMapper();
public static void main(String[] args) throws IOException {
MyObj o = JACKSON.readValue(args[0], MyObj.class); // assumes args[0] contains your json payload provided in your question.
}
}
Let me know if you have any questions.
This blew my mind with how easy it was. You can just pass a String holding your JSON to the constructor of a JSONObject in the default org.json package.
JSONArray rootOfPage = new JSONArray(JSONString);
Done. Drops microphone.
This works with JSONObjects as well. After that, you can just look through your hierarchy of Objects using the get() methods on your objects.
In addition to other answers, I recomend this online opensource service jsonschema2pojo.org for quick generating Java classes from json or json schema for GSON, Jackson 1.x or Jackson 2.x. For example, if you have:
{
"pageInfo": {
"pageName": "abc",
"pagePic": "http://example.com/content.jpg"
}
"posts": [
{
"post_id": "123456789012_123456789012",
"actor_id": 1234567890,
"picOfPersonWhoPosted": "http://example.com/photo.jpg",
"nameOfPersonWhoPosted": "Jane Doe",
"message": "Sounds cool. Can't wait to see it!",
"likesCount": 2,
"comments": [],
"timeOfPost": 1234567890
}
]
}
The jsonschema2pojo.org for GSON generated:
#Generated("org.jsonschema2pojo")
public class Container {
#SerializedName("pageInfo")
#Expose
public PageInfo pageInfo;
#SerializedName("posts")
#Expose
public List<Post> posts = new ArrayList<Post>();
}
#Generated("org.jsonschema2pojo")
public class PageInfo {
#SerializedName("pageName")
#Expose
public String pageName;
#SerializedName("pagePic")
#Expose
public String pagePic;
}
#Generated("org.jsonschema2pojo")
public class Post {
#SerializedName("post_id")
#Expose
public String postId;
#SerializedName("actor_id")
#Expose
public long actorId;
#SerializedName("picOfPersonWhoPosted")
#Expose
public String picOfPersonWhoPosted;
#SerializedName("nameOfPersonWhoPosted")
#Expose
public String nameOfPersonWhoPosted;
#SerializedName("message")
#Expose
public String message;
#SerializedName("likesCount")
#Expose
public long likesCount;
#SerializedName("comments")
#Expose
public List<Object> comments = new ArrayList<Object>();
#SerializedName("timeOfPost")
#Expose
public long timeOfPost;
}
If you have some Java class(say Message) representing the JSON string(jsonString), you can use Jackson JSON library with:
Message message= new ObjectMapper().readValue(jsonString, Message.class);
and from message object you can fetch any of its attribute.
Gson is easy to learn and implement, what we need to know are following two methods
toJson() – Convert Java object to JSON format
fromJson() – Convert JSON into Java object
`
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import com.google.gson.Gson;
public class GsonExample {
public static void main(String[] args) {
Gson gson = new Gson();
try {
BufferedReader br = new BufferedReader(
new FileReader("c:\\file.json"));
//convert the json string back to object
DataObject obj = gson.fromJson(br, DataObject.class);
System.out.println(obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}
`
There are many open source libraries present to parse JSON content to an object or just to read JSON values. Your requirement is just to read values and parsing it to custom object. So org.json library is enough in your case.
Use org.json library to parse it and create JsonObject:
JSONObject jsonObj = new JSONObject(<jsonStr>);
Now, use this object to get your values:
String id = jsonObj.getString("pageInfo");
You can see a complete example here:
How to parse JSON in Java
You can use the Gson Library to parse the JSON string.
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(jsonAsString, JsonObject.class);
String pageName = jsonObject.getAsJsonObject("pageInfo").get("pageName").getAsString();
String pagePic = jsonObject.getAsJsonObject("pageInfo").get("pagePic").getAsString();
String postId = jsonObject.getAsJsonArray("posts").get(0).getAsJsonObject().get("post_id").getAsString();
You can also loop through the "posts" array as so:
JsonArray posts = jsonObject.getAsJsonArray("posts");
for (JsonElement post : posts) {
String postId = post.getAsJsonObject().get("post_id").getAsString();
//do something
}
Read the following blog post, JSON in Java.
This post is a little bit old, but still I want to answer you question.
Step 1: Create a POJO class of your data.
Step 2: Now create a object using JSON.
Employee employee = null;
ObjectMapper mapper = new ObjectMapper();
try {
employee = mapper.readValue(newFile("/home/sumit/employee.json"), Employee.class);
}
catch(JsonGenerationException e) {
e.printStackTrace();
}
For further reference you can refer to the following link.
You can use Jayway JsonPath. Below is a GitHub link with source code, pom details and good documentation.
https://github.com/jayway/JsonPath
Please follow the below steps.
Step 1: Add the jayway JSON path dependency in your class path using Maven or download the JAR file and manually add it.
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.2.0</version>
</dependency>
Step 2: Please save your input JSON as a file for this example. In my case I saved your JSON as sampleJson.txt. Note you missed a comma between pageInfo and posts.
Step 3: Read the JSON contents from the above file using bufferedReader and save it as String.
BufferedReader br = new BufferedReader(new FileReader("D:\\sampleJson.txt"));
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
br.close();
String jsonInput = sb.toString();
Step 4: Parse your JSON string using jayway JSON parser.
Object document = Configuration.defaultConfiguration().jsonProvider().parse(jsonInput);
Step 5: Read the details like below.
String pageName = JsonPath.read(document, "$.pageInfo.pageName");
String pagePic = JsonPath.read(document, "$.pageInfo.pagePic");
String post_id = JsonPath.read(document, "$.posts[0].post_id");
System.out.println("$.pageInfo.pageName " + pageName);
System.out.println("$.pageInfo.pagePic " + pagePic);
System.out.println("$.posts[0].post_id " + post_id);
The output will be:
$.pageInfo.pageName = abc
$.pageInfo.pagePic = http://example.com/content.jpg
$.posts[0].post_id = 123456789012_123456789012
I have JSON like this:
{
"pageInfo": {
"pageName": "abc",
"pagePic": "http://example.com/content.jpg"
}
}
Java class
class PageInfo {
private String pageName;
private String pagePic;
// Getters and setters
}
Code for converting this JSON to a Java class.
PageInfo pageInfo = JsonPath.parse(jsonString).read("$.pageInfo", PageInfo.class);
Maven
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.2.0</version>
</dependency>
Please do something like this:
JSONParser jsonParser = new JSONParser();
JSONObject obj = (JSONObject) jsonParser.parse(contentString);
String product = (String) jsonObject.get("productId");
{
"pageInfo": {
"pageName": "abc",
"pagePic": "http://example.com/content.jpg"
},
"posts": [
{
"post_id": "123456789012_123456789012",
"actor_id": "1234567890",
"picOfPersonWhoPosted": "http://example.com/photo.jpg",
"nameOfPersonWhoPosted": "Jane Doe",
"message": "Sounds cool. Can't wait to see it!",
"likesCount": "2",
"comments": [],
"timeOfPost": "1234567890"
}
]
}
Java code :
JSONObject obj = new JSONObject(responsejsonobj);
String pageName = obj.getJSONObject("pageInfo").getString("pageName");
JSONArray arr = obj.getJSONArray("posts");
for (int i = 0; i < arr.length(); i++)
{
String post_id = arr.getJSONObject(i).getString("post_id");
......etc
}
First you need to select an implementation library to do that.
The Java API for JSON Processing (JSR 353) provides portable APIs to parse, generate, transform, and query JSON using object model and streaming APIs.
The reference implementation is here: https://jsonp.java.net/
Here you can find a list of implementations of JSR 353:
What are the API that does implement JSR-353 (JSON)
And to help you decide... I found this article as well:
http://blog.takipi.com/the-ultimate-json-library-json-simple-vs-gson-vs-jackson-vs-json/
If you go for Jackson, here is a good article about conversion between JSON to/from Java using Jackson: https://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/
Hope it helps!
Top answers on this page use too simple examples like object with one property (e.g. {name: value}). I think that still simple but real life example can help someone.
So this is the JSON returned by Google Translate API:
{
"data":
{
"translations":
[
{
"translatedText": "Arbeit"
}
]
}
}
I want to retrieve the value of "translatedText" attribute e.g. "Arbeit" using Google's Gson.
Two possible approaches:
Retrieve just one needed attribute
String json = callToTranslateApi("work", "de");
JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
return jsonObject.get("data").getAsJsonObject()
.get("translations").getAsJsonArray()
.get(0).getAsJsonObject()
.get("translatedText").getAsString();
Create Java object from JSON
class ApiResponse {
Data data;
class Data {
Translation[] translations;
class Translation {
String translatedText;
}
}
}
...
Gson g = new Gson();
String json =callToTranslateApi("work", "de");
ApiResponse response = g.fromJson(json, ApiResponse.class);
return response.data.translations[0].translatedText;
If you have maven project then add below dependency or normal project add json-simple jar.
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
Write below java code for convert JSON string to JSON array.
JSONArray ja = new JSONArray(String jsonString);
Any kind of json array
steps to solve the issue.
Convert your JSON object to a java object.
You can use this link or any online tool.
Save out as a java class like Myclass.java.
Myclass obj = new Gson().fromJson(JsonStr, Myclass.class);
Using obj, you can get your values.
One can use Apache #Model annotation to create Java model classes representing structure of JSON files and use them to access various elements in the JSON tree. Unlike other solutions this one works completely without reflection and is thus suitable for environments where reflection is impossible or comes with significant overhead.
There is a sample Maven project showing the usage. First of all it defines the structure:
#Model(className="RepositoryInfo", properties = {
#Property(name = "id", type = int.class),
#Property(name = "name", type = String.class),
#Property(name = "owner", type = Owner.class),
#Property(name = "private", type = boolean.class),
})
final class RepositoryCntrl {
#Model(className = "Owner", properties = {
#Property(name = "login", type = String.class)
})
static final class OwnerCntrl {
}
}
and then it uses the generated RepositoryInfo and Owner classes to parse the provided input stream and pick certain information up while doing that:
List<RepositoryInfo> repositories = new ArrayList<>();
try (InputStream is = initializeStream(args)) {
Models.parse(CONTEXT, RepositoryInfo.class, is, repositories);
}
System.err.println("there is " + repositories.size() + " repositories");
repositories.stream().filter((repo) -> repo != null).forEach((repo) -> {
System.err.println("repository " + repo.getName() +
" is owned by " + repo.getOwner().getLogin()
);
})
That is it! In addition to that here is a live gist showing similar example together with asynchronous network communication.
jsoniter (jsoniterator) is a relatively new and simple json library, designed to be simple and fast. All you need to do to deserialize json data is
JsonIterator.deserialize(jsonData, int[].class);
where jsonData is a string of json data.
Check out the official website
for more information.
You can use JsonNode for a structured tree representation of your JSON string. It's part of the rock solid jackson library which is omnipresent.
ObjectMapper mapper = new ObjectMapper();
JsonNode yourObj = mapper.readTree("{\"k\":\"v\"}");

error while Deserialize the Google Direction json

I have this json
https://maps.googleapis.com/maps/api/directions/json?origin=-22.8895625,-47.0714089&destination=-22.892376,-47.027553&key=
And I need deserialize it
But I get this error
Additional text encountered after finished reading JSON content: ,. Path '', line 8, position 4.
What I am doing:
public static async Task<List<Model.Localizacao>> GetDirectionsAsync(Localizacao locUser, Localizacao locLoja)
{
using (var client = new HttpClient())
{
try
{
List<Model.Localizacao> lstLoc = new List<Model.Localizacao>();
var json = await client.GetStringAsync("https://maps.googleapis.com/maps/api/directions/json?origin=" + locUser.latitude + "," + locUser.longitude + "&destination="+ locLoja.latitude+","+locLoja.longitude+"&key=" + GOOGLEMAPSKEY);
json = json.Substring(json.IndexOf('['));
json = json.Substring(0, json.LastIndexOf(']') + 1);
lstLoc = JsonConvert.DeserializeObject<List<Model.Localizacao>>(json);
return lstLoc;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return null;
}
}
}
this is my class:
namespace neoFly_Montana.Model
{
class Localizacao
{
public double latitude { get; set; }
public double longitude { get; set; }
}
}
How can I solve that?
My key is the same for the maps of google
I believe the problem is in these lines:
json = json.Substring(json.IndexOf('['));
json = json.Substring(0, json.LastIndexOf(']') + 1);
This appears to set json to be all the text from the first [ to the last ]. That means that you're going to wind up with some malformed json.
geocoded_waypoints is an array, but so is routes, which means you're going to wind up with a String that looks like this:
[
{ "geocoder_status" : "OK" ... }
{ "geocoder_status" : "OK" ... }
], "routes": [
{ "bounds": { ... } ... }
]
That , "routes": [ will fail to parse.
Update
After some discussion in the comments, I think I'm at the end of the help I'm able to provide. I'm not familiar with C# or the particular JSON parsing library you're using.
However, I can offer some ideas as a starting point.
The JSON coming back from that Google call has a particular structure. I suspect you will have to create new model classes that match this structure. For example, the top-level object would have three fields, and might look like this in Java:
public class ApiResponse {
private List<Waypoint> geocoded_waypoints;
private List<Route> routes;
private String status;
}
Then you'd have to implement Waypoint and Route, again matching the structure of the Google response:
public class Waypoint {
private String geocoder_status;
private String place_id;
private List<String> types;
}
public class Route {
private Bounds bounds;
private String copyrights;
private List<Leg> legs;
private Polyline overview_polyline;
private String summary;
private List<String> warnings;
private List<String> waypoint_order;
}
And so on. Once you have a class to represent the top-level response as well as all the various sub-objects inside that response, you would probably be able to change this code:
List<Model.Localizacao> lstLoc = new List<Model.Localizacao>();
var json = await client.GetStringAsync("https://maps.googleapis.com/maps/api/directions/json?origin=" + locUser.latitude + "," + locUser.longitude + "&destination="+ locLoja.latitude+","+locLoja.longitude+"&key=" + GOOGLEMAPSKEY);
json = json.Substring(json.IndexOf('['));
json = json.Substring(0, json.LastIndexOf(']') + 1);
lstLoc = JsonConvert.DeserializeObject<List<Model.Localizacao>>(json);
return lstLoc;
to this:
var json = await client.GetStringAsync("https://maps.googleapis.com/maps/api/directions/json?origin=" + locUser.latitude + "," + locUser.longitude + "&destination="+ locLoja.latitude+","+locLoja.longitude+"&key=" + GOOGLEMAPSKEY);
return JsonConvert.DeserializeObject<ApiResponse>(json);

Deserialize json with same key but different type in android using Jackson

I am calling web-services which can have 2 types of json object in response. Now sometimes i get key profile with type String and sometimes it may have same key with type 'ProfileSubObject'. So how to manage this case? Below are my two types of object. I am using Jackson library to parse json.
1.)
{
"data": [
{
"profession": "iOS Developer",
"thanks": {
"count": 5
},
"profile": "test"
}
]
}
2.)
{
"data": [
{
"profession": "iOS Developer",
"thanks": {
"count": 5
},
"profile": {
"val1":"test1",
"val2":"test2"
}
}
]
}
Key profile have 2 different type of object based on web-service call.
Following is my data class structure.
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class DataObject {
#JsonProperty("profession")
private String profession;
#JsonProperty("profile")
private ProfileObject profile;
#JsonProperty("thanks")
private ThanksObject thanks;
public String getProfession() {
return profession;
}
public ThanksObject getThanks() {
return thanks;
}
public ProfileObject getProfile() {
return profile;
}
}
And Profile class is as per below.
public class ProfileObject {
ProfileObject(){
}
ProfileObject(ProfileSubObject profileSubObject){
this.profileSubObject= profileSubObject;
}
ProfileObject(String profile){
this.profile= profile;
}
private ProfileSubObject profileSubObject;
private String profile;
public ProfileSubObject getProfileSubObject() {
return profileSubObject;
}
}
Now when i parse my object, ProfileObject is always null. I want it to get parsed based on proifle key data type.
Anyone could help me with parsing?
In constructing the solution, I faced two problems:
the Json structure does not match a single DataObject
the original problem of deserializing same property into differnt types of Java objects.
The first problem I solved by constructing JavaType objects which tell Jackson the generic type of the collections involved. There are two such collections: a Map, consisting of a single entry with key "data" and value of List of DataObjects
The second problem, I solved with the Jackson feature of #JsonAnySetter which directs Jackson to call a single method for all properties it doesn't recognize. For this purpose, I added #JsonIgnore to the profile variable to make sure that Jackson indeed doesn't recognize it. Now Jackson calls the same method for the two input jsons
This is the new DataObject class:
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class DataObject
{
#JsonProperty("profession")
public String profession;
#JsonIgnore // forcing jackson to not recognize this property
public ProfileObject profile;
#JsonProperty("thanks")
public ThanksObject thanks;
public String getProfession() { return profession; }
public void setProfession(String p) { profession = p; }
public ThanksObject getThanks() { return thanks; }
public void setThanks(ThanksObject t) { thanks = t; }
public ProfileObject getProfile() { return profile; }
public void setProfile(ProfileObject p) { profile = p; }
#JsonAnySetter
public void setProfileFromJson(String name, Object value)
{
// if value is single String, call appropriate ctor
if (value instanceof String) {
profile = new ProfileObject((String)value);
}
// if value is map, it must contain 'val1', 'val2' entries
if (value instanceof Map) {
ProfileSubObject profileSubObject =
new ProfileSubObject(((Map<String, String>)value).get("val1"), ((Map<String, String>)value).get("val2"));
profile = new ProfileObject(profileSubObject);
}
// error?
}
}
Here is my test method, which includes the java type construction I mentioned:
public static void main(String[] args)
{
try (Reader reader = new FileReader("C://Temp/xx2.json")) {
ObjectMapper mapper = new ObjectMapper();
// type of key of map is String
JavaType stringType = TypeFactory.defaultInstance().constructType(String.class);
// type of value of map is list of DataObjects
JavaType listOfDataObject = TypeFactory.defaultInstance().constructCollectionType(List.class, DataObject.class);
// finally, construct map type with key and value types
JavaType rootMap = TypeFactory.defaultInstance().constructMapType(HashMap.class, stringType, listOfDataObject);
Map<String ,List<DataObject>> m = mapper.readValue(reader, rootMap);
DataObject do1 = m.values()
// get first (only?) value in map (it is list)
.stream().findFirst().orElse(Collections.emptyList())
// get first (only?) item in list - it is the DataObject
.stream().findFirst().orElse(null);
System.out.println(do1.profile);
System.out.println(do1.profile.profile);
System.out.println(do1.profile.profileSubObject.val1 + " " + do1.profile.profileSubObject.val2);
} catch (Exception e) {
e.printStackTrace();
}
}
This may be of help in regards to parsing JSON, use a JsonReader. It does assume you are using RESTful webservice and have already gotten a HttpURLConnection and an InputStream from the connection.
https://developer.android.com/reference/android/util/JsonReader.html

use JsonDeserializer on GSON

I have a model that work with multiple JSON responses. However this a response :
items: [
{
kind: "youtube#playlistItem",
etag: ""fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/jqbcTLu8tYm8b1FXGO14gNZrFG4"",
id: "PLUQ7I1jJqKB4lJarGcpWsP62l7iC06IkE2LDE0BxLe18",
That conflict with this one (notice the same id field with different type. The above id is String, the other is a Class) :
items: [
{
kind: "youtube#searchResult",
etag: ""fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/hDIU49vmD5aPhKUN5Yz9gtljG9A"",
id: {
kind: "youtube#playlist",
playlistId: "PLh6xqIvLQJSf3ynKVEc1axUb1dQwvGWfO"
},
I want to read the id field using a single model class.
This is my model Response class :
public class Response {
private ArrayList<Item> items = new ArrayList<Item>();
And this is my model Item class :
public class Item {
private Id id;
//nested class inside Item
public class Id
{
private String id;
private String kind;
private String playlistId;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
public String getPlaylistId() {
return playlistId;
}
public void setPlaylistId(String playlistId) {
this.playlistId = playlistId;
}
}
Notice that the Id class is inside Item class.
This is how i use registerTypeAdapter :
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Response.class,
new JsonDeserializer<Item.Id>() {
#Override
public Item.Id deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
Item.Id result = new Item().new Id();
if(jsonElement.isJsonPrimitive() == false)
{
result.setKind(jsonElement.getAsJsonObject().get("kind").getAsString());
result.setPlaylistId(jsonElement.getAsJsonObject().get("playlistId").getAsString());
//return new Item.Id(jsonElement.getAsJsonObject().get("kind").getAsString(), jsonElement.getAsJsonObject().get("playlistId").getAsString());
return result;
}
else
{
result.setId(jsonElement.getAsString());
//return new Item.Id(jsonElement.getAsString());
return result;
}
}
});
Gson gson = gsonBuilder.create();
Response result = Response.success(
gson.fromJson(json, gsonClass),
HttpHeaderParser.parseCacheHeaders(response));
However the above code throws java.lang.NullPointerException in this line :
if(jsonElement.isJsonPrimitive() == false)
What should i do?
Is this the correct way to use registerTypeAdapter?
Thanks for your time
Your main problem seems to be that you're registering a type adapter for Response class but you're giving a JsonDeserializer that handles Item.Id classes. Either you deserialize a full Response or limit yourself to Item or even Item.Id.
Another problem with deserializing Item.Id (as written in your question) directly is that it's a non-static inner class, which requires an instance of the parent class to be instantiated (as you do with the new Item().new Id()). I think that you would have to deserialize the whole Item manually if you want to keep it as such, frankly I don't see any reason not to make Item.Id static as it would simplify the problem.
Here's my solution with the static version of Item.Id
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Item.Id.class, new JsonDeserializer<Item.Id>() {
#Override
public Item.Id deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Item.Id id = new Item.Id();
if (!json.isJsonPrimitive()) {
JsonObject jsonObject = json.getAsJsonObject();
id.setKind(jsonObject.get("kind").getAsString());
id.setPlaylistId(jsonObject.get("playlistId").getAsString());
} else {
id.setId(json.getAsString());
}
return id;
}
});
And some test snippets that seemed to work for me:
Gson gson = builder.create();
Response response = gson.fromJson("{\n" +
" \"items\": [\n" +
" {\n" +
" \"kind\": \"youtube#playlistItem\",\n" +
" \"etag\": \"fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/jqbcTLu8tYm8b1FXGO14gNZrFG4\",\n" +
" \"id\": \"PLUQ7I1jJqKB4lJarGcpWsP62l7iC06IkE2LDE0BxLe18\"\n" +
" }\n" +
" ]\n" +
"}", Response.class);
Response response2 = gson.fromJson("{\n" +
" \"items\": [\n" +
" {\n" +
" \"kind\": \"youtube#searchResult\",\n" +
" \"etag\": \"fpJ9onbY0Rl_LqYLG6rOCJ9h9N8/hDIU49vmD5aPhKUN5Yz9gtljG9A\",\n" +
" \"id\": {\n" +
" \"kind\": \"youtube#playlist\",\n" +
" \"playlistId\": \"PLh6xqIvLQJSf3ynKVEc1axUb1dQwvGWfO\"\n" +
" }\n" +
" }\n" +
" ]\n" +
"}", Response.class);
If you want to keep Item.Id non-static, I think you need to write a deserializer for Item instead. Also keep in mind that json elements can be absent but the parser should still be able to handle it.
I had just the same problem long time ago, but i was working then with Json.Net, However json concept is (almost) the same so I hope I will succeed help.
I guess it might not work, but why try to not register with the Item class? I mean there is no 'Item.Id' in so it's obious get a null. BUT this: gsonBuilder.registerTypeAdapter(Item.class, likely to fail, becaus you dont parse the Item class explicitly (However it might work, I just never tried it in Gson. But in Json.Net similar way would work proper.)
So, how could you fix that? I'm too lazy to write an paraser but you could look here and read the surt summary summary from here (Search for Using the registerTypeAdapter().
I hope I helped.

Categories

Resources