I'm trying to parse some JSON data using gson in Java that has the following structure but by looking at examples online, I cannot find anything that does the job.
Would anyone be able to assist?
{
"data":{
"id":[
{
"stuff":{
},
"values":[
[
123,
456
],
[
123,
456
],
[
123,
456
],
],
"otherStuff":"blah"
}
]
}
}
You just need to create a Java class structure that represents the data in your JSON. In order to do that, I suggest you to copy your JSON into this online JSON Viewer and you'll see the structure of your JSON much clearer...
Basically you need these classes (pseudo-code):
class Response
Data data
class Data
List<ID> id
class ID
Stuff stuff
List<List<Integer>> values
String otherStuff
Note that attribute names in your classes must match the names of your JSON fields! You may add more attributes and classes according to your actual JSON structure... Also note that you need getters and setters for all your attributes!
Finally, you just need to parse the JSON into your Java class structure with:
Gson gson = new Gson();
Response response = gson.fromJson(yourJsonString, Response.class);
And that's it! Now you can access all your data within the response object using the getters and setters...
For example, in order to access the first value 456, you'll need to do:
int value = response.getData().getId().get(0).getValues().get(0).get(1);
Depending on what you are trying to do. You could just setup a POJO heirarchy that matches your json as seen here (Preferred method). Or, you could provide a custom deserializer. I only dealt with the id data as I assumed it was the tricky implementation in question. Just step through the json using the gson types, and build up the data you are trying to represent. The Data and Id classes are just pojos composed of and reflecting the properties in the original json string.
public class MyDeserializer implements JsonDeserializer<Data>
{
#Override
public Data deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException
{
final Gson gson = new Gson();
final JsonObject obj = je.getAsJsonObject(); //our original full json string
final JsonElement dataElement = obj.get("data");
final JsonElement idElement = dataElement.getAsJsonObject().get("id");
final JsonArray idArray = idElement.getAsJsonArray();
final List<Id> parsedData = new ArrayList<>();
for (Object object : idArray)
{
final JsonObject jsonObject = (JsonObject) object;
//can pass this into constructor of Id or through a setter
final JsonObject stuff = jsonObject.get("stuff").getAsJsonObject();
final JsonArray valuesArray = jsonObject.getAsJsonArray("values");
final Id id = new Id();
for (Object value : valuesArray)
{
final JsonArray nestedArray = (JsonArray)value;
final Integer[] nest = gson.fromJson(nestedArray, Integer[].class);
id.addNestedValues(nest);
}
parsedData.add(id);
}
return new Data(parsedData);
}
}
Test:
#Test
public void testMethod1()
{
final String values = "[[123, 456], [987, 654]]";
final String id = "[ {stuff: { }, values: " + values + ", otherstuff: 'stuff2' }]";
final String jsonString = "{data: {id:" + id + "}}";
System.out.println(jsonString);
final Gson gson = new GsonBuilder().registerTypeAdapter(Data.class, new MyDeserializer()).create();
System.out.println(gson.fromJson(jsonString, Data.class));
}
Result:
Data{ids=[Id {nestedList=[[123, 456], [987, 654]]}]}
POJO:
public class Data
{
private List<Id> ids;
public Data(List<Id> ids)
{
this.ids = ids;
}
#Override
public String toString()
{
return "Data{" + "ids=" + ids + '}';
}
}
public class Id
{
private List<Integer[]> nestedList;
public Id()
{
nestedList = new ArrayList<>();
}
public void addNestedValues(final Integer[] values)
{
nestedList.add(values);
}
#Override
public String toString()
{
final List<String> formattedOutput = new ArrayList();
for (Integer[] integers : nestedList)
{
formattedOutput.add(Arrays.asList(integers).toString());
}
return "Id {" + "nestedList=" + formattedOutput + '}';
}
}
Related
I have a map property:
private Map<String, Attribute> attributes = new HashMap<>();
Attribute object looks like this:
public class Attribute{
private String value;
private String name;
//with constructor setters and getters
}
How do I represent attributes Map object as JSON?
I am getting a JsonSyntaxException:
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY
when I'm trying to convert JSON object using fromJson() in the following code:
Attribute attribute = Gson().fromJson(jsonObect,Attribute.class)
My JSON object looks like this:
{
"attributes":[
{
"name":"some name",
"value":"some value"
}
]
}
it is easy to check:
Map<String,Attribute> attributes = new HashMap<>();
attributes.put("key_0", new Attribute("value_0", "name_0"));// I added constructor and getter/setter methods to class Attribute
attributes.put("key_1", new Attribute("value_1", "name_1"));
attributes.put("key_2", new Attribute("value_2", "name_2"));
//serialize using ObjectMapper
ObjectMapper mapper = new ObjectMapper();
var s = mapper.writeValueAsString(attributes);
System.out.println(s);
output:
{
"key_2":{
"value":"value_2",
"name":"name_2"
},
"key_1":{
"value":"value_1",
"name":"name_1"
},
"key_0":{
"value":"value_0",
"name":"name_0"
}
}
I am getting: "Expected BEGIN_ARRAY but was BEGIN_OBJECT" error when I'm trying to convert JSON object using fromJson() in the following code:
Attribute attribute = Gson().fromJson(jsonObect,Attribute.class)
The following JSON object doesn't match either a single Attribute object or a map Map<String, Attribute>:
{
"attributes":[
{
"name":"some name",
"value":"some value"
}
]
}
Have a look carefully, the value mapped to the key "attributes" is a JSON-array.
Hence, you can parse it successfully into a map of type Map<String, List<Attribute>>
That's how it can be implemented using Gson.fromJson() and TypeToken (for more options, see this question):
public static void main(String[] args) {
String jsonStr = """
{
"attributes":[
{
"name":"some name",
"value":"some value"
}
]
}""";
Gson gson = new Gson();
Type mapStrByStr = new TypeToken<Map<String, List<Attribute>>>(){}.getType();
Map<String, List<Attribute>> map = gson.fromJson(jsonStr, mapStrByStr);
System.out.println(map);
}
}
public static class Attribute{
private String value;
private String name;
#Override
public String toString() {
return "Attribute{" +
"value='" + value + '\'' +
", name='" + name + '\'' +
'}';
}
}
Output:
{attributes=[Attribute{value='some value', name='some name'}]}
i need to access the values of a Json, that its inside an Array, that its inside of a Json, the structure of the Json file its like this:
{
"Places": [
{
"id": 17,
"city": "Chicago",
"vehicle": "car"
},
{
"id": 13,
"city": "New York",
"vehicle": "plane",
}
]
}
i only need the values of "id", "city" and "vehicle"
im using the map function like this:
Gson gson = new Gson();
Map<String,String> userMap = gson.fromJson(contentoffile, Map.class);
for (Object value : userMap.values()) {
Map places= (Map) value;
int id = (int) (places.get("id"));
String city= (String) places.get("city");
String vehicle= (String) places.get("vehicle");
but i got the next error
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.Map
how i can acces the data?
btw, i can use other libraries for this, not only Map function
The structure you have is a JSON object that contains a JSON array places, I am not really sure what you are trying to achieve by using a Map<String, String>, you need to either create a Place POJO and parse accordingly OR just access it directly as a JsonObject:
Place.java
public class Place
{
private int id;
private String city;
private String vehicle;
public Place(int id, String city, String vehicle)
{
this.id = id;
this.city = city;
this.vehicle = vehicle;
}
// Setters & getters
}
public static void main(String[] args)
{
Gson gson = new Gson();
// Parse your file to a JsonObject
JsonObject jsonObject = gson.fromJson(contentoffile, JsonObject.class);
// Extract JsonArray (places) from JsonObject
JsonArray jsonArray = jsonObject.get("Places").getAsJsonArray();
Option 1: Converting into List<Place>:
// Convert JsonArray to a list of places
Type type = new TypeToken<List<Place>>() {}.getType();
List<Place> places = gson.fromJson(jsonArray, type);
//iterate over places
for (Place place : places)
{
int id = place.getId();
//etc..
}
}
Option 2: Iterating directly over JsonArray:
for (JsonElement jsonElement : jsonArray)
{
//This will represent a Place object
JsonObject curr = jsonElement.getAsJsonObject();
int id = curr.get("id").getAsInt();
String city = curr.get("city").getAsString();
String vehicle = curr.get("vehicle").getAsString();
}
Option 3: Create a wrapper class
public class PlaceWrapper
{
private List<Place> places;
//Const, setters, getters
}
public static void main(String[] args)
{
Gson gson = new Gson();
// Deserialize json
PlaceWrapper placeWrapper = gson.fromJson(contentoffile, PlaceWrapper.class);
// iterate over places
for (Place place : placeWrapper.getPlaces())
{
// do your thing
}
}
I have a JSON string like this:
{
"r": [
{
"pic": "1.jpg",
"name": "Name1"
},
{
"pic": "2.jpg",
"name": "Name2"
},
{
"pic": "3.jpg",
"name": "Name3"
}
]
}
I want to parse to this POJO model:
public class Catalog {
#SerializedName("r")
#Expose
private List<JSONObject> r = new ArrayList<JSONObject>();
public List<JSONObject> getR() {
return r;
}
public void setR(List<JSONObject> r) {
this.r = r;
}
}
I am parsing this way:
Catalog cat = new Gson().fromJson(jsonString,Catalog.class);
But finally am getting this json
{
"r": [
{
"nameValuePairs": {}
},
{
"nameValuePairs": {}
},
{
"nameValuePairs": {}
}
]
}
Please note that I don't want to use com.google.gson.JsonObject.
I want to use org.json.JSONObject. How to achieve this because almost all of my code uses it?
As it was already mentioned in other answer and comments, you probably might not really want to use org.json.JSONObject for several reasons. But if it's a must for you, you just have to create your org.json.JSONObject-aware Gson instance.
final class JSONObjectJsonDeserializer
implements JsonDeserializer<JSONObject> {
// The implementation is fully thread-safe and can be instantiated once
private static final JsonDeserializer<JSONObject> jsonObjectJsonDeserializer = new JSONObjectJsonDeserializer();
// Type tokens are immutable values and therefore can be considered constants (and final) and thread-safe as well
private static final TypeToken<Map<String, Object>> mapStringToObjectTypeToken = new TypeToken<Map<String, Object>>() {
};
private JSONObjectJsonDeserializer() {
}
static JsonDeserializer<JSONObject> getJsonObjectJsonDeserializer() {
return jsonObjectJsonDeserializer;
}
#Override
public JSONObject deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context) {
// Convert the input jsonElement as if it were a Map<String, Object> (a generic representation for JSON objectS)
final Map<String, Object> map = context.deserialize(jsonElement, mapStringToObjectTypeToken.getType());
// And forward the map to the JSONObject constructor - it seems to accept it nice
return new JSONObject(map);
}
}
Gson is designed thread-safe and does not need to be instantiated every time serialization or deserialization is necessary:
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(JSONObject.class, getJsonObjectJsonDeserializer())
.create();
And finally:
final Catalog catalog = gson.fromJson(jsonString, Catalog.class);
out.println(catalog.getR());
with the following result:
[{"name":"Name1","pic":"1.jpg"}, {"name":"Name2","pic":"2.jpg"}, {"name":"Name3","pic":"3.jpg"}]
Anyway, I would suggest you to redesign your mappings model.
I think you don't need JSONObject.
Try this
// is wrapped class for serialized json.
public class JsonExample
{
List<Catalog> r;
}
public class Catalog {
private String pic;
private String name;
public String getPic() {
return pic;
}
public String getName() {
return name;
}
}
JsonExample example = new Gson().fromJson(json, JsonExample.class);
Additional - using JSONObject
JSONObject obj = new JSONObject(json);
JSONArray arr = obj.getJSONArray("r");
List<Catalog> cataList = new ArrayList<>();
for(int i = 0 ; i < arr.length() ; ++i)
{
cataList.add(new Catalog(arr.getJSONObject(i)));
}
public class Catalog {
private String pic;
private String name;
public Catalog(JSONObject obj) throws JSONException
{
pic = obj.getString("pic");
name = obj.getString("name");
}
public String getPic() {
return pic;
}
public String getName() {
return name;
}
}
I think in your case, usage of gson library is not required at all.
Only org.json can solve the entire problem.
E.g.:
JSONObject json = new JSONObject(jsonString);
JSONArray jsonArray = json.getJSONArray("r");
List<JSONObject> jsonList = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
jsonList.add(jsonArray.getJSONObject(i));
}
Catalog catalog = new Catalog();
catalog.setR(jsonList);
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.
I have a JSON object stored in db in the form of string. I am using it to create dynamic form in the UI. Now the problem is I want to change some values in it based on other changes happening on the application. So suppose I updated label for the field, then I have to get this JSON and change that here.
This would be easy If I have stored same type of objects in this json, but my JSON is like follows:
[{
"name": "someName",
"xtype": "keyvaluecombo",
"fieldLabel": "Some Title",
"refType": "YES_NO",
"multiSelect": false,
"helpText": ""
},
{
"name": "someName2",
"xtype": "keyvaluecombo",
"fieldLabel": "Some Title2",
"refType": "YES_NO",
"multiSelect": false,
"helpText": ""
},
{
"xtype": "datefield",
"fieldLabel": "Joining Date",
"name": "joiningDate",
"submitFormat": "Y-m-d"
},
{
"xtype": "userselectioncombo",
"fieldLabel": "Selection",
"name": "selections",
"filterBy": {
"functions": [
"select"
]
}
}]
Now this is stored as String in db, what is efficient way of changing fieldLabel based on name. I could have tried working on it as string only and use regular expression, but that didn't feel right.
You should write a bean class, which should be mapping to you Json object like,
public class abc {
private String name;
private String xtype;
private String fieldLabel;
........
}
Then you should use
import java.lang.reflect.Type;
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
Type type = new TypeToken<List<abc>>() {
}.getType();
List<abc> abcList = gson.fromJson(confTemplate,
type); // confTemplate is your Json object you get from DB
this will get the list of beans.
for (abc abcData : abcList ) {
// you can do your stuff
}
First of all the best way, changing your database design with a new one that suits your model. Not keeping json in your database as a column. But if you can't do that, because sometimes it's impossible to change old db designs you can trace the following way.
And of course you should read your json from db before start and save it again after the below process.
Create a custom object that suits your model.
public class MyObject{
private String name;
private String fieldLabel;
public String getFieldLabel(){
return fieldLabel;
}
public void setFieldLabel( String fieldLabel ){
this.fieldLabel = fieldLabel;
}
public String getName(){
return name;
}
public void setName( String name ){
this.name = name;
}
// bla bla other fields
Convert your json into your object, and vice versa see the code example below:
public static void main( String[] args ){
Gson gson = new Gson();
String yourJson = "[{'name':'someName','xtype':'keyvaluecombo','fieldLabel':'Some Title','refType':'YES_NO','multiSelect':false,'helpText':''},{'name':'someName2','xtype':'keyvaluecombo','fieldLabel':'Some Title2','refType':'YES_NO','multiSelect':false,'helpText':''},{'xtype':'datefield','fieldLabel':'Joining Date','name':'joiningDate','submitFormat':'Y-m-d'},{'xtype':'userselectioncombo','fieldLabel':'Selection','name':'selections','filterBy':{'functions':['select']}}]";
// changing single quotes with double ones.
yourJson = yourJson.replaceAll( "'", "\"" );
JsonArray jsonArray = new JsonParser().parse( yourJson ).getAsJsonArray();
List<MyObject> result = new ArrayList<MyObject>();
for( JsonElement jsonElement : jsonArray ){
MyObject myObject = gson.fromJson( jsonElement, MyObject.class );
// change fields as you wish
if( myObject.getName().equals( "someName" ) ){
myObject.setFieldLabel( "TEST" );
}
// add it to another list
result.add( myObject );
}
// convert into another json again..
System.out.println( gson.toJson( result ) );
}
Easy to realize that Object in your list have attributes below:
"name"
"xtype"
"fieldLabel"
"refType"
"multiSelect"
"helpText"
"submitFormat"
"filterBy"
So you can create an Object which has over attributes. Using ObjectMapper for deserialize the list:
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(json, new TypeReference<ArrayList<T>>() {})
After have a list object you can loop for change any attribute or change attribute of an specific item you want.