How to convert Json String with dynamic fields to Object? - java

I have the followed snipets of Json String:
{
"networks": {
"tech11": {
"id": "1",
"name": "IDEN"
},
"tech12": {
"id": "2",
"name": "EVDO_B"
}
}
}
I use some methods to convert this String to Object:
private static Gson mGson = new Gson();
...
public static WebObjectResponse convertJsonToObject(String jsonString) {
WebObjectResponse webObjectResponse = null;
if(jsonString != null && jsonString.length() > 1){
webObjectResponse = mGson.fromJson(jsonString, WebObjectResponse.class);
}
return webObjectResponse;
}
Where WebObjectResponse is class that should represent above mentioned String.
Its not complicated if I get static fields.
But in my case the values have different names: tech11, tech12 ....
I can use #SerializedName but its works in specific cases like convert "class" to "class_".
As you see networks Object defined as list of tech Objects but with different post-fix.
public class WebObjectResponse{
private DataInfoList networks = null;
}
This is static implementation, i defined 2 values tech11 and tech12 but next response might be techXX
public class DataInfoList {
private DataInfo tech11 = null;
private DataInfo tech12 = null;
}
public class DataInfo {
private String id = null;
private String name = null;
}
What is the good way to convert current Json String to Object where list of elements are Objects too and have different names?
Thank you.

Use a Map!
I would do the following
public class WebObjectResponse {
private Map<String, DataInfo> networks;
}
public class DataInfo {
private String id = null;
private String name = null;
}
// later
Gson gson = new Gson();
String json = "{\"networks\": {\"tech11\": { \"id\": \"1\",\"name\": \"IDEN\" }, \"tech12\": { \"id\": \"2\", \"name\": \"EVDO_B\" } }}";
WebObjectResponse response = gson.fromJson(json, WebObjectResponse .class);
For each object in json networks, a new entry will be added to the Map field of your class WebObjectResponse. You then reference them by techXX or iterate through the keyset.
Assuming a structure like this
{
"networks": {
"tech11": {
"id": "1",
"name": "IDEN"
},
"tech12": {
"id": "2",
"name": "EVDO_B"
},
"tech13": {
"id": "3",
"name": "WOHOO"
}, ...
}
}

We would need your class structure for more details.
As far as I am aware, I think you will need to have some mappings defined somewhere (I used xml's) and then try to match json with one of the mappings to create objects.
Google gson is good. I did it in Jackson
Also, converting objects should be trivial. But since you might have variable fields like tech11 and tech12 , you might want to store the "network" value as a string and then extract fields out of it when required.
Hope I could help.
Edit : Sotirious nails it.

Please use this link for converting SON Response to Java POJO class
http://www.jsonschema2pojo.org/

Related

I want to extract a value from a json

I want to extract a key and its value from json object. I am having a 3 objects in a json with parent child relation, named as
1. Parent,
2. childOne_OfParent and
3. child_OF_childOne.
I want to extract all the value of "userQueryId" from child_OF_childOne and store into a string type variable.
How do I perform this. Thanks in advance.
My Json object is:
{
"createdBy": "****",
"dashboardId": 1,
"childOne_OfParent": [
{
"createdBy": null,
"dashboardSectionId": 1,
"child_OF_childOne": [
{
"createdBy": "XYZ",
"userQueryId": "283"
},
{
"createdBy": "ABC",
"userQueryId": "284"
},
{
"createdBy": "AWS",
"userQueryId": "285"
}
]
}
]
}
You can use the json to create a model java class like this. I used your json to create the class using the site https://codebeautify.org/json-to-java-converter. You can give a classname of your choice in the Class_Name.
public class Class_Name {
private String createdBy;
private float dashboardId;
ArrayList < Object > childOne_OfParent = new ArrayList < Object > ();
// Getter Methods
public String getCreatedBy() {
return createdBy;
}
public float getDashboardId() {
return dashboardId;
}
// Setter Methods
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public void setDashboardId(float dashboardId) {
this.dashboardId = dashboardId;
}
}
Then you can use the Jackson to convert your json into a java object and access the data you want. Here jsonString is your json and the objResp is your object.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Class_Name objResp = mapper.readerFor(Class_Name.class).readValue(jsonString);
Here is a useful guide for that. https://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/
The tool for these kind of tasks is JsonPath. It has xpath-like search capabilities.
Here is a working example of the given question
public static void main(String[] args) {
String searchQueryIds = "$.childOne_OfParent[*].child_OF_childOne[*].userQueryId";
try (InputStream is = Files.newInputStream(Paths.get("c:/temp/test.json"))) {
List<String> ids = JsonPath.parse(is).read(searchQueryIds);
System.out.println(ids);
} catch (Exception e) {
e.printStackTrace();
}
}
Assuming there is pojo for json and jackson library available. It will return comma separated queryUserIds.
Parent parent = new ObjectMapper().reader(Parent.class).readValue(inputJson);
String userIds = parent.getChildOne_OfParent().get(0).getChild_OF_childOne().stream()
.map(c -> c.getuserQueryId())
.collect(Collectors.joining(","));

Splitting a nested json to smaller jsons using Gson

I want to get a part of list json from a whole nested one. I have a json that looks like following:
{
"response": 200,
"responseMsg": "Allright",
"location": [
{
"stateId": 1,
"stateName": "West Bengal",
"district": [
{
"districtId": 15,
"districtName": "abc",
"village": [
{
"villageId": 121,
"villageName": "ABC"
},
{
"villageId": 90,
"villageName": "XYZ"
}
]
},
{
"districtId": 11,
"districtName": "xyz",
"village": [
{
"villageId": 58,
"villageName": "PQR"
}
]
}
]
}
]
}
I have written the bean files as following :
Details.java:
public class Details {
private int response = 0;
private String responseMsg = null;
private List<State> states = null;
public List<State> getLocation() {
return location;
}
State.java:
public class State {
private int stateId = 0;
private String stateName=null;
private List<District> district;
public List<District> getDistrict() {
return district;
}
Now, I want only the State json differently so that I can then use use it as List to populate the spinner in android.
For parsing the json, I am using
Gson googleJson = builder.create();Details details = googleJson.fromJson(result, Details.class);
List<State> stateList = details.getLocation();
But when i again convert this to json using gson.toJson(stateList) this gives:
[
{
"district": [
{
"village": [
{
"villageName": "Mekhliganj",
"villageId": 57
}
],
"districtName": "Cooch Bihar",
"districtId": 10
}
],"stateName=West Bengal","stateId":1
}
}
But this is other way round as state name goes in end when i again convert it to json.
Also , this same json (stateList) gives null pointer exception when I again try to parse it as:
State stateObj = gson.fromJson(stateList,State.class);
What should be the correct way to do this ? i.e. get a part of json (list) from a whole using gson and parse that part ?
Got the solution for you...
You are not passing the whole response in below function
try this steps to get whole response :
1) Store the data in String or any object class you are storing.
2)
Gson gson = new Gson();
String string = gson.toJson(response);
Note : You are just parsing remaining response. You are not parsing the original response. Just recheck the response when you parse in above function by putting break point on it.
public class Details {
private int response = 0;
private String responseMsg = null;
private Location location = null;
//add getter and setter
}
public class Location{
private List<State>stateList;
//add getter and setter
}
Finally
public class State {
private int stateId = 0;
private String stateName=null;
private List<District> district;
//add getter and setter
}

How to parse dynamic json in android with retrofit 2 using annotations

I have a JSON structure which I want to parse using retrofit 2 (#Expose). Below I have mentioned the JSON. Need help to parse it using dynamic annotations.
{
"status": 1,
"message": "success",
"data" : [
{
"type": 1,
"heading": "",
"description": "",
"created_on": 141123213,
"author_id": 123,
"author_name": "some name",
"author_pic": "some_pic",
"read_time": "3.1 min",
"post_pic_url": "",
"post_web_url": "",
"isLiked": false,
"isSaved": false,
"totalLikes": 12
},
{
"type": 2,
"author_id": 123,
"author_name": "some name",
"author_pic": "some pic",
"author_about": "",
"tags":[
"travel", "weekends"
],
"isFollowing": false
},
{
"type": 3,
"poll_name": "Some name",
"poll_options": [
"opt1", "opt2", "opt3"
],
"author_id": 123,
"author_name": "some name",
"author_pic": "some pic",
"isLiked": true,
"isFollowing": false
},
{
"type": 4,
"ad_url": "url",
"ad_pic": "pic"
},
{
"type": 5,
"tags": [
"tag1", "tag2", "tag3"
]
}
]
}
I have updated the JSON structure with all 5 types.
1 Use Retrofit convert
example GSON convert
2 Add com.squareup.retrofit2:converter-gson in gradle file
3 Add converter factory in Retrofit object
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Ws_Url)
.addConverterFactory(GsonConverterFactory.create())
.client(clientBuilder.build())
.build();
4 Create Model class for Your response
Use below link to generate model class
http://www.jsonschema2pojo.org/
Retrofit does not do serialization and deserialization, but Gson does.
You might want to use RuntimeTypeAdapterFactory from the Google Gson extras package.
It's not published at artifact repositories, and you can simply copy the code to your project.
If type adapters are somewhat complex (as they work with JSON streams), you might find JsonDeserializer<T> easier to use and probably maintain (they work with JSON trees consuming some more memory, but it's the only way to go here anyway).
Define your mappings similar to:
// There might be no the common root, and target lists might be parameterized with Object, but it's up to you
abstract class Element {
final int type = Integer.valueOf(0);
// Since the number of types is really finite, we can define all known types in one place
private Element() {
}
static final class Type1Element
extends Element {
// the rest of properties go here
// Gson does not need constructors, neither we do (at least public ones)
private Type1Element() {
}
}
static final class Type2Element
extends Element {
// the rest of properties go here
private Type2Element() {
}
}
}
final class Response<T> {
final int status = Integer.valueOf(0);
final String message = null;
final T data = null;
}
Now the deserializer itself:
final class ElementJsonDeserializer
implements JsonDeserializer<Element> {
private static final JsonDeserializer<Element> elementJsonDeserializer = new ElementJsonDeserializer();
private ElementJsonDeserializer() {
}
// The deserializer is essentially a singleton, but we hide away this fact making sure that only 1 instance exists
static JsonDeserializer<Element> getElementJsonDeserializer() {
return elementJsonDeserializer;
}
#Override
public Element deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
final int typeCode = jsonElement.getAsJsonObject().getAsJsonPrimitive("type").getAsInt();
// Simple dispatching here
// RuntimeTypeAdapterFactory basically does the same
switch ( typeCode ) {
case 1:
return context.deserialize(jsonElement, Type1Element.class);
case 2:
return context.deserialize(jsonElement, Type2Element.class);
default:
throw new JsonParseException("Unrecognized type: " + typeCode);
}
}
}
Now get it all working together (response.json is your JSON document resource):
private static final Type type = new TypeToken<Response<List<Element>>>() {
}.getType();
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(Element.class, getElementJsonDeserializer())
.create();
public static void main(final String... args)
throws IOException {
try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43802350.class, "response.json") ) {
final Response<List<Element>> response = gson.fromJson(jsonReader, type);
response.data
.stream()
.map(Element::getClass)
.map(Class::getSimpleName)
.forEach(System.out::println);
}
}
Output:
Type1Element
Type2Element
Of course, don't forget to register the gson instance with GsonConverterFactory.create(gson) in your Retrofit builder.

Gson, how to deserialize array or empty string

I trying to deserialize this json to array of objects:
[{
"name": "item 1",
"tags": ["tag1"]
},
{
"name": "item 2",
"tags": ["tag1","tag2"]
},
{
"name": "item 3",
"tags": []
},
{
"name": "item 4",
"tags": ""
}]
My java class looks like this:
public class MyObject
{
#Expose
private String name;
#Expose
private List<String> tags = new ArrayList<String>();
}
The problem is json's tags property which can be just empty string or array. Right now gson gives me error: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING
How should I deserialize this json?
I do not have any control to this json, it comes from 3rd pary api.
I do not have any control to this json, it comes from 3rd pary api.
If you don't have the control over the data, your best solution is to create a custom deserializer in my opinion:
class MyObjectDeserializer implements JsonDeserializer<MyObject> {
#Override
public MyObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jObj = json.getAsJsonObject();
JsonElement jElement = jObj.get("tags");
List<String> tags = Collections.emptyList();
if(jElement.isJsonArray()) {
tags = context.deserialize(jElement.getAsJsonArray(), new TypeToken<List<String>>(){}.getType());
}
//assuming there is an appropriate constructor
return new MyObject(jObj.getAsJsonPrimitive("name").getAsString(), tags);
}
}
What it does it that it checks whether "tags" is a JsonArray or not. If it's the case, it deserializes it as usual, otherwise you don't touch it and just create your object with an empty list.
Once you've written that, you need to register it within the JSON parser:
Gson gson = new GsonBuilder().registerTypeAdapter(MyObject.class, new MyObjectDeserializer()).create();
//here json is a String that contains your input
List<MyObject> myObjects = gson.fromJson(json, new TypeToken<List<MyObject>>(){}.getType());
Running it, I get as output:
MyObject{name='item 1', tags=[tag1]}
MyObject{name='item 2', tags=[tag1, tag2]}
MyObject{name='item 3', tags=[]}
MyObject{name='item 4', tags=[]}
Before converting the json into object replace the string "tags": "" with "tags": []
Use GSON's fromJson() method to de serialize your JSON.
You can better understand this by the example given below:
import java.util.ArrayList;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
public class JsonToJava {
/**
* #param args
*/
public static void main(String[] args) {
String json = "[{\"firstName\":\"John\", \"lastName\":\"Doe\", \"id\":[\"10\",\"20\",\"30\"]},"
+ "{\"firstName\":\"Anna\", \"lastName\":\"Smith\", \"id\":[\"40\",\"50\",\"60\"]},"
+ "{\"firstName\":\"Peter\", \"lastName\":\"Jones\", \"id\":[\"70\",\"80\",\"90\"]},"
+ "{\"firstName\":\"Ankur\", \"lastName\":\"Mahajan\", \"id\":[\"100\",\"200\",\"300\"]},"
+ "{\"firstName\":\"Abhishek\", \"lastName\":\"Mahajan\", \"id\":[\"400\",\"500\",\"600\"]}]";
jsonToJava(json);
}
private static void jsonToJava(String json) {
Gson gson = new Gson();
JsonParser parser = new JsonParser();
JsonArray jArray = parser.parse(json).getAsJsonArray();
ArrayList<POJO> lcs = new ArrayList<POJO>();
for (JsonElement obj : jArray) {
POJO cse = gson.fromJson(obj, POJO.class);
lcs.add(cse);
}
for (POJO pojo : lcs) {
System.out.println(pojo.getFirstName() + ", " + pojo.getLastName()
+ ", " + pojo.getId());
}
}
}
POJO class:
public class POJO {
private String firstName;
private String lastName;
private String[] id;
//Getters and Setters.
I hope this will solve your issue.
You are mixing datatypes. You cant have both an Array and a string. Change
"tags": ""
to
"tags": null
and you are good to go.
Use Jacskon Object Mapper
See below simple example
[http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/][1]
Jackson type safety is way better than Gson. At times you will stackoverflow in Gson.

Using Gson to unserialize an array of objects

I have a JSON response that looks like this. I want to extract the values of "text" and put them into a Set of Strings (i.e. I don't necessarily need the entire JSON to be derialised).
I am using the GSON library
So far my method looks like this (It's obviously wrong):
public static Response deserialise(String json){
Gson gson = new Gson();
Response r = gson.fromJson(json, Response.class);
return r;
}
I am calling deserialise with this:
Response r = deserialise(json);
System.out.println("[status]: "+r.getStatus()); // works fine
Collection<Keyword> coll = r.getKeywords();
Iterator<Keyword> itr = coll.iterator();
while(itr.hasNext()){
System.out.println(itr.next().getWord()); //prints null every time
}
Response is a class with the following member variables (with getters and setters):
private String status;
private String usage;
private String language;
private Collection<Keyword> keywords;
Keyword is a class with the following member variables (with getters and setters):
private String word;
private String relevance;
The JSON looks like this:
{
"status": "OK",
"usage": "By accessing AlchemyAPI or using information generated by AlchemyAPI, you are agreeing to be bound by the AlchemyAPI Terms of Use: http://www.alchemyapi.com/company/terms.html",
"url": "http://www.theage.com.au/world/aussie-trying-to-make-a-difference-gunned-down-20110510-1egnv.html",
"language": "english",
"keywords": [
{
"text": "Mr McNichols",
"relevance": "0.99441"
},
{
"text": "Ms Benton",
"relevance": "0.392337"
},
{
"text": "Detroit",
"relevance": "0.363931"
},
{
"text": "Crocodile Hunter",
"relevance": "0.350197"
}
]
}
The problem is that the Collection of Keywords returns null values - although it seems to have the correct size, which is positive.
This just works:
public class Keyword {
public String text;
public String relevance;
}
public class MyJSON {
public String status;
public String usage;
public String language;
public Collection<Keyword> keywords;
}
In the main method
String str = "{\"status\": \"OK\","+
"\"usage\": \"By accessing AlchemyAPI or using information generated by AlchemyAPI, you are agreeing to be bound by the AlchemyAPI Terms of Use: http://www.alchemyapi.com/company/terms.html\","+
"\"url\": \"http://www.theage.com.au/world/aussie-trying-to-make-a-difference-gunned-down-20110510-1egnv.html\","+
"\"language\": \"english\","+
"\"keywords\": ["+
"{"+
"\"text\": \"Mr McNichols\","+
"\"relevance\": \"0.99441\""+
"},"+
"{"+
"\"text\": \"Ms Benton\","+
"\"relevance\": \"0.392337\""+
"},"+
"{"+
"\"text\": \"Detroit\","+
"\"relevance\": \"0.363931\""+
"},"+
"{"+
"\"text\": \"Crocodile Hunter\","+
"\"relevance\": \"0.350197\""+
"}"+
"]"+
"}";
Gson gson = new Gson();
MyJSON mj = gson.fromJson(str, MyJSON.class);
System.out.println(mj.language);
for(Keyword k: mj.keywords)
System.out.println(k.text+":"+k.relevance);
This prints
english
Mr McNichols:0.99441
Ms Benton:0.392337
Detroit:0.363931
Crocodile Hunter:0.350197
Look carefully at my Keyword class!(and my JSON string starts with {).
This was all down to my own stupidity.
In the keyword class I called the variable word when it should have been text in order to map properly to the JSON.

Categories

Resources