I am trying to parse a JSON object like the following with GSON:
{
"key1":"someValue",
"key2":{
"anotherKey1":"212586425",
"anotherKey2":"Martin"
}
}
This is the code:
Data data = new Gson().fromJson(json, Data.class);
Here is the Data class:
public class Data {
public String key1;
public Map key2; //This will break everything.
}
What I expect (I am new to GSON) is that it produces the value of key2 as a Map object.
However, I get an error Expected BEGIN_OBJECT but was STRING which makes me think that I am passing a String, where I should be passing a JSON object.
Isn't GSON parsing the whole JSON string I pass in the beginning? So eventually, I would like the new data source to be a Map Object. Is that feasible ?
Let Gson do the work. I defined Data as
package stackoverflow.questions.q19228349;
public class Data {
#Override
public String toString() {
return "Data [key1=" + key1 + ", key2=" + key2 + "]";
}
public String key1;
public Object key2;
}
and then I can parse both cases for key2:
package stackoverflow.questions.q19228349;
import com.google.gson.Gson;
public class Q19228349 {
public static void main(String[] args){
String json =
"{\"key1\":\"someValue\","+
"\"key2\":{ "+
" \"anotherKey1\":\"212586425\","+
" \"anotherKey2\":\"Martin\""+
" }"+
" }";
String json2 =
"{\"key1\":\"someValue\","+
"\"key2\":\"aString\""+
" }";
Gson g = new Gson();
Data d = g.fromJson(json, Data.class);
System.out.println("First: " +d);
Data d2 = g.fromJson(json2, Data.class);
System.out.println("Second: "+d2);
}
}
This is the result:
First: Data [key1=someValue, key2={anotherKey1=212586425,
anotherKey2=Martin}] Second: Data [key1=someValue, key2=aString]
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 have class with some properties, for example:
public class MyClass {
public int number;
public String s;
}
and I want to convert Map of this class to json. for example:
Map<String, MyClass> map = new HashMap();
map.put("sss", new MyClass(1, "blabla");
json j = new json(map);
and I want the output to be like:
{"sss":{"number":"1","s":"blabla"}}
someone know how to do that in JAVA? I tried with JSONObject and with Gson but did not work for me.
you can use toJson() method of Gson class to convert a java object to json ,see the example below ,
public class SomeObject {
private int data1 = 100;
private String data2 = "hello";
private List<String> list = new ArrayList<String>() {
{
add("String 1");
add("String 2");
add("String 3");
}
};
//getter and setter methods
#Override
public String toString() {
return "SomeObject [data1=" + data1 + ", data2=" + data2 + ", list="
+ list + "]";
}
}
i will convert the above class' object to json , getter and setter methods are useful when you are converting the json back to java object .
public static void main(String[] args) {
SomeObject obj = new SomeObject();
Gson gson = new Gson();
// convert java object to JSON format,
// and returned as JSON formatted string
String json = gson.toJson(obj);
System.out.println(json);
}
output :
{"data1":100,"data2":"hello","list":["String 1","String 2","String 3"]}
Using Gson:
Gson gson = new GsonBuilder().create();
String json = gson.toJson(map);
You have to fix, parenthesis issue.
map.put("sss", new MyClass(1,"test")); //observe 2 braces at the end!
Following code should do the trick for you,
Gson gson = new Gson();
String myJson = gson.toJson(map);
Output:
{"sss":{"number":1,"s":"test"}}
Implement some custom toJSON() method for each class as shown below:
public class MyClass1 {
String number;
String name;
public MyClass1(String number, String name){
this.number = number;
this.name = name;
}
public JSONObject toJSON() throws JSONException {
return new JSONObject("{\"number\" : \""+this.number+"\", \"name\":\""+this.name+"\"}");
}
}
And then just use it to convert your map to jsonObject:
public class MapToJSON {
public static void main(String[] args) throws JSONException {
Map<String, JSONObject> map = new HashMap<String, JSONObject>();
map.put("sss", new MyClass1("1", "Hello").toJSON());
System.out.println(new JSONObject(map));
}
}
I found the way how to do that:
import com.google.gson.Gson;
import org.json.JSONObject;
Gson gson = new Gson();
map.put("sss", new JSONObject(gson.toJson(new MyClass(1, "Hello"))));
map.put("aaa", new JSONObject(gson.toJson(new MyClass(2, "blabla"))));
String output = new JSONObject(map).toString();
and now the output is correct.
Thanks a lot to all the people that tried to help me with this problem...
I have a JSON file like this:
{"id" : "1", "name" : "David"} // this represent testdata for the class Person
{"accountid" : "1188", "accountnumber" : "119295567"} // this represent testdata for the class account
{"id" : "22", "date" : "22.11.2013"} // this represent testdata for the class transaction
Now, I have three Java classes (with suitable attributes like in the JSON file and get- and set methods)
Person
Account
Transaction
I have written a Junit Test and will use the JSON file. I will generate three different objects by using only one JSON file.
How can I do this using Gson? This is what I tried so far to deserialize a Person object.
Gson gson = new GsonBuilder().create();
String jsonTestFile = FileUtils.readFileToString(new File(this.pathForJsonTestFile
+ "testFile.json"));
Person person = gson.fromJson(jsonTestFile,
Person.class);
But how can I explicit create the account object or the transaction object or the person object depending from the JSON?
If you had a field in your JSON that tells you what kind of object you are trying to parse, it will be "easier", however, since in your data your can distinguish object by field structure, you can parse your JSON according to it. I mean, if you have accountid field, it's an Account class, and so on.
So, what your have to do, is to look into your JSON and decide what kind of class you want to use to deserialize. To do something like that, you can use JsonParser class that returns you a browsable tree of objects and then fire a standard Gson deserialization.
I prepared a code that you can copy&run in your IDE to show how to do it.
package stackoverflow.questions.q19997365;
import com.google.gson.*;
public class Q19997365 {
public static class Person {
String id;
String name;
#Override
public String toString() {
return "Person [id=" + id + ", name=" + name + "]";
}
}
public static class Account {
String accountid;
String accountnumber;
#Override
public String toString() {
return "Account [accountid=" + accountid + ", accountNumber=" + accountnumber + "]";
}
}
public static class Transaction {
String id;
String date;
#Override
public String toString() {
return "Transaction [id=" + id + ", date=" + date + "]";
}
}
/**
* #param args
*/
public static void main(String[] args) {
String json1 = "{\"id\" : \"1\", \"name\" : \"David\"}"; // this represent testdata for the class Person
String json2 = "{\"accountid\" : \"1188\", \"accountnumber\" : \"119295567\"}"; // this represent testdata for the class account
String json3 = "{\"id\" : \"22\", \"date\" : \"22.11.2013\"}"; // this represent testdata for the class transaction
System.out.println(extractFromJson(json1));
System.out.println(extractFromJson(json2));
System.out.println(extractFromJson(json3));
}
private static Object extractFromJson(String json) {
Gson g = new Gson();
JsonObject e = new JsonParser().parse(json).getAsJsonObject();
if (e.get("name") != null)
return g.fromJson(json, Person.class);
if (e.get("accountid") != null)
return g.fromJson(json, Account.class);
if (e.get("date") != null)
return g.fromJson(json, Transaction.class);
return null;
}
}
and this is my execution:
Person [id=1, name=David]
Account [accountid=1188, accountnumber=119295567]
Transaction [id=22, date=22.11.2013]
The key part is extractFromJson method that does all the job. It uses a JsonParser to snoop into the JSON string and then calls a Gson instance to do the right deserialization.
Three final notes
the method instantiates Gson every time, is not efficient, but here I want to show you the concept, you can easily improve this.
your date field is not a kind of date that Gson can parse by default, you need change date format for that, see this for example
extractFromJson method is something like a factory pattern, in this pattern you cannot know what kind of object will be returned. So Object is the return type, you need an instanceof + cast to manage it correctly.
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 + '}';
}
}
How can I parse the JSON below with Gson?
Now I use:
private AttachChildDataModel parseSuccess(String content){
Gson gson = new Gson();
return gson.fromJson(content, AttachChildDataModel.class);
}
Where AttachChildDataModel has these member variables:
private Integer adultId;
private Integer childId;
private PlatformEnum platform;
private String regId;
private Date loginDate;
private Date logoutDate;
private ClientApp clientApp;
The Json string I'm trying to parse is:
{"log":
{
"childId":2,
"adultId":1,
"logoutDate":null,
"platform":"IPHONE",
"regId":null,
"loginDate":1325419200000,
"clientApp":"CHILD_APP"
}
}
When I put the object into the Spring ModelView, I add it under name log. The problematic thing is when I try to parse it with Gson. Right now, I manually remove the "log" prefix and the "}" postfix with String#substring, but I think there's a better solution.
To solve your problem, just create a "foo" class like this:
package stackoverflow.questions.q15614008;
public class Foo {
public AttachChildDataModel log;
}
and use it as base class for parsing in Gson:
package stackoverflow.questions.q15614008;
import com.google.gson.*;
public class Q15614008 {
public static void main(String[] arg) {
String testString = "{\"log\": "
+ " {"
+ "\"childId\":2," + "\"adultId\":1,"
+ "\"logoutDate\":null,"
+ "\"platform\":\"IPHONE\","
+ "\"regId\":null,"
+ "\"loginDate\":1325419200000,"
+ "\"clientApp\":\"CHILD_APP\"}"
+ "}";
Gson gson = new Gson();
Foo foo = gson.fromJson(
testString, Foo.class);
System.out.println("Result: " + foo.log.toString());
}
}
Then use only the log member variable of the Foo class.