So I have an object with some fields...
protected String name;
protected String relativePathAndFileName;
protected DateTime next_Run;
protected ArrayList<String> hosts;
Which gets serialized to JSON like this:
public void serialize(){
Gson gson = Converters.registerDateTime(new GsonBuilder()).setPrettyPrinting().create();
String json = gson.toJson(this);
try {
FileWriter writer = new FileWriter(this.relativePathAndFileName);
writer.write (json);
writer.close();
} catch (IOException e) {
logger.error("Error while trying to write myAlert to json: ", e);
}
}
Later when I need to read in this json file, I try to do so like this:
try {
for (File f : alertConfigFiles) {
Gson gson = new Gson();
JsonReader reader = new JsonReader(new FileReader(f));
Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> myMap = gson.fromJson(reader, type);
Alert tempAlert = new Alert(myMap);
myAlerts.add(tempAlert);
logger.debug("Imported: " + f.toString());
}
The error that I'm getting is:
Unhandled exception when trying to import config files:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 28 column 13 path $.
The JSON inside the file is something to the effect of:
{
"name": "Logs Per Host - past 24 hours",
"relativePathAndFileName": "./Elk-Reporting/Alerts/logs_per_host24h.json",
"next_Run": "2017-06-07T22:24:56.682-04:00",
"hosts": [
"app-12c",
"app1-18",
"wp-01",
"app-02",
"wp-02",
"cent-04",
"app-06",
"app-05"
]
}
It seems to be choking when it tries to import the ArrayList of hosts, but it was able to write them out without issues.
Can anyone offer some advice on how to get my import working without issues?
try to keep it simple. Using maps and so on, is a way to have issues.
Here is a working code to deserialise / serialise :
package com.rizze.beans.labs.sof;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import com.google.gson.Gson;
public class SOFGson {
public String json = "{ \"name\": \"Logs Per Host - past 24 hours\", \"relativePathAndFileName\": \"./Elk-Reporting/Alerts/logs_per_host24h.json\", \"next_Run\": \"2017-06-07T22:24:56.682-04:00\", \"hosts\": [ \"bos-qa-app-12c\", \"bos-qa-app1-18\", \"bos-qa-wp-01\", \"bos-lt-app-02\", \"bos-qa-wp-02\", \"bos-dev-cent-04.americanwell.com\", \"bos-qa-app-06\", \"bos-qa-app-05\" ]}";
public class MyObj{
protected String name;
protected String relativePathAndFileName;
protected String next_Run;
protected String[] hosts;
}
#Test
public void test() {
Gson gson = new Gson();
MyObj obj = gson.fromJson(json, MyObj.class);
assertTrue(obj!=null);
assertTrue(obj.hosts.length==8);
System.out.println(gson.toJson(obj));
}
}
here is the class in gist : https://gist.github.com/jeorfevre/7b32a96d4ddc4af68e40bf95f63f2c26
Those two lines seem to be the problem:
Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> myMap = gson.fromJson(reader, type);
You serialize your object of some specific class. You then deserialize it to type. But your JSON does not fit into a Map. Better do it like this, so you can use your own class.
YourClass myMap = gson.fromJson(reader, YourClass.class);
If you want to use this approach, you might want to change your Java class to hold an array of strings instead of an ArrayList of strings.
Maybe this page helps you a bit. Especially the first case fits your situation.
Another option is a custom Deserialzer as described here.
Related
I have a JSON Data which is a collection of objects like the one given below. I have to deserialize the below given data into a list of objects
[{\"Name\": \"Initialize\", \"Library\": \"BKS\", \"Type\": \"setup\", \"Status\": \"PASS\", \"StartTime\": \"20190429 15:06:36.020\", \"EndTime\": \"20190429 15:06:39.476\", \"Environment\": \"CLC-ER\", \"ScenarioName\": \"BKS-DISVAS\", \"ElapsedTime\": 456.0},{\"Name\": \"Initialize\", \"Library\": \"BKS\", \"Type\": \"setup\", \"Status\": \"PASS\", \"StartTime\": \"20190429 15:06:36.020\", \"EndTime\": \"20190429 15:06:39.476\", \"Environment\": \"CLC-ER\", \"ScenarioName\": \"BKS-DISVAS\", \"ElapsedTime\": 456.0}]
I have tried the following code snippet, but I am getting the following error.
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING
at com.google.gson.Gson.fromJson(Gson.java:822) ~[gson-2.3.1.jar:na]
at com.google.gson.Gson.fromJson(Gson.java:875) ~[gson-2.3.1.jar:na]
My Model class is given below
public class KeywordDetails {
public KeywordDetails() {
}
#JsonProperty("Name")
public String Name;
#JsonProperty("Type")
public String Type;
#JsonProperty("Library")
public String Library;
#JsonProperty("StartTime")
public String StartTime;
#JsonProperty("EndTime")
public String EndTime;
#JsonProperty("Status")
public String Status;
#JsonProperty("ScenarioName")
public String ScenarioName;
#JsonProperty("Environment")
public String Environment;
#JsonProperty("ElapsedTime")
public double ElapsedTime;
}
The deserialization code is given below,
Gson serializer = new Gson();
Type listType = new TypeToken<ArrayList<KeywordDetails>>() {
}.getType();
JsonParser parser = new JsonParser();
JsonElement kwJson = parser.parse(ser.getKeywordStats());
System.out.println(kwJson);
List<KeywordDetails> keywordDetails = serializer.fromJson(kwJson, listType);
The ser.getKeywordStats() method is giving the above JSON.
I should be able to deserialize the JSON into the list or array of objects.
As I am new to Java, I am not able to find the root cause or fix for this issue, can anyone help me with this issue?
Why JsonProperty instead of SerializableName? Are you mixing Jackson and Gson?
What is the output of ser.getKeywordStats()?
Because I have tested your code by hardcoding that json-string instead of ser.getKeywordStats(), and it worked without any issue.
Here is a working snippet,
private static final String ESCAPED_STRING =
"[{\"Name\": \"Initialize\", \"Library\": \"BKS\", \"Type\": \"setup\", \"Status\": \"PASS\", \"StartTime\": \"20190429 15:06:36.020\", \"EndTime\": \"20190429 15:06:39.476\", \"Environment\": \"CLC-ER\", \"ScenarioName\": \"BKS-DISVAS\", \"ElapsedTime\": 456.0},{\"Name\": \"Initialize\", \"Library\": \"BKS\", \"Type\": \"setup\", \"Status\": \"PASS\", \"StartTime\": \"20190429 15:06:36.020\", \"EndTime\": \"20190429 15:06:39.476\", \"Environment\": \"CLC-ER\", \"ScenarioName\": \"BKS-DISVAS\", \"ElapsedTime\": 456.0}]";
public static void main(String[] args) throws JsonProcessingException {
Gson gson = new Gson();
Type t= new TypeToken<List<KeywordDetails>>(){}.getType();
JsonParser parser = new JsonParser();
JsonElement jsonElements = parser.parse(ESCAPED_STRING);
System.out.println(jsonElements);
List<KeywordDetails> kd = gson.fromJson(jsonElements, t);
System.out.println(kd);
}
This has to do something with your String, the string must be void of the \ slashes to make it a valid JSON. So, I have used JsonParser to construct a valid JSON from the escaped String.
Use Gson or JsonParser not both.
Try with this code:
Gson serializer = new Gson();
Type listType = new TypeToken<ArrayList<KeywordDetails>>() {}.getType();
List<KeywordDetails> keywordDetails = serializer.fromJson(ser.getKeywordStats(), listType);
I don't know #JsonProperty annotation. You can use (or not) #SerializedName instead.
Then you can simply deserialize your json like this.
String json = ...
Gson gson = new Gson();
List< KeywordDetails > keywords = gson.fromJson(json, new TypeToken<List< KeywordDetails >>(){}.getType());
I have a JsonObject named "mapping" with the following content:
{
"client": "127.0.0.1",
"servers": [
"8.8.8.8",
"8.8.4.4",
"156.154.70.1",
"156.154.71.1"
]
}
I know I can get the array "servers" with:
mapping.get("servers").getAsJsonArray()
And now I want to parse that JsonArray into a java.util.List...
What is the easiest way to do this?
Definitely the easiest way to do that is using Gson's default parsing function fromJson().
There is an implementation of this function suitable for when you need to deserialize into any ParameterizedType (e.g., any List), which is fromJson(JsonElement json, Type typeOfT).
In your case, you just need to get the Type of a List<String> and then parse the JSON array into that Type, like this:
import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;
JsonElement yourJson = mapping.get("servers");
Type listType = new TypeToken<List<String>>() {}.getType();
List<String> yourList = new Gson().fromJson(yourJson, listType);
In your case yourJson is a JsonElement, but it could also be a String, any Reader or a JsonReader.
You may want to take a look at Gson API documentation.
Below code is using com.google.gson.JsonArray.
I have printed the number of element in list as well as the elements in List
import java.util.ArrayList;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class Test {
static String str = "{ "+
"\"client\":\"127.0.0.1\"," +
"\"servers\":[" +
" \"8.8.8.8\"," +
" \"8.8.4.4\"," +
" \"156.154.70.1\"," +
" \"156.154.71.1\" " +
" ]" +
"}";
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
JsonParser jsonParser = new JsonParser();
JsonObject jo = (JsonObject)jsonParser.parse(str);
JsonArray jsonArr = jo.getAsJsonArray("servers");
//jsonArr.
Gson googleJson = new Gson();
ArrayList jsonObjList = googleJson.fromJson(jsonArr, ArrayList.class);
System.out.println("List size is : "+jsonObjList.size());
System.out.println("List Elements are : "+jsonObjList.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
OUTPUT
List size is : 4
List Elements are : [8.8.8.8, 8.8.4.4, 156.154.70.1, 156.154.71.1]
I read solution from official website of Gson at here
And this code for you:
String json = "{"client":"127.0.0.1","servers":["8.8.8.8","8.8.4.4","156.154.70.1","156.154.71.1"]}";
JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
JsonArray jsonArray = jsonObject.getAsJsonArray("servers");
String[] arrName = new Gson().fromJson(jsonArray, String[].class);
List<String> lstName = new ArrayList<>();
lstName = Arrays.asList(arrName);
for (String str : lstName) {
System.out.println(str);
}
Result show on monitor:
8.8.8.8
8.8.4.4
156.154.70.1
156.154.71.1
I was able to get the list mapping to work with just using #SerializedName for all fields.. no logic around Type was necessary.
Running the code - in step #4 below - through the debugger, I am able to observe that the List<ContentImage> mGalleryImages object populated with the JSON data
Here's an example:
1. The JSON
{
"name": "Some House",
"gallery": [
{
"description": "Nice 300sqft. den.jpg",
"photo_url": "image/den.jpg"
},
{
"description": "Floor Plan",
"photo_url": "image/floor_plan.jpg"
}
]
}
2. Java class with the List
public class FocusArea {
#SerializedName("name")
private String mName;
#SerializedName("gallery")
private List<ContentImage> mGalleryImages;
}
3. Java class for the List items
public class ContentImage {
#SerializedName("description")
private String mDescription;
#SerializedName("photo_url")
private String mPhotoUrl;
// getters/setters ..
}
4. The Java code that processes the JSON
for (String key : focusAreaKeys) {
JsonElement sectionElement = sectionsJsonObject.get(key);
FocusArea focusArea = gson.fromJson(sectionElement, FocusArea.class);
}
Kotlin Extension
for Kotlin developers you can use this extension
inline fun <reified T> String.convertToListObject(): List<T>? {
val listType: Type = object : TypeToken<List<T?>?>() {}.type
return Gson().fromJson<List<T>>(this, listType)
}
Given you start with mapping.get("servers").getAsJsonArray(), if you have access to Guava Streams, you can do the below one-liner:
List<String> servers = Streams.stream(jsonArray.iterator())
.map(je -> je.getAsString())
.collect(Collectors.toList());
Note StreamSupport won't be able to work on JsonElement type, so it is insufficient.
I create a java URL class which contain my Json data and have some function to obtain back my json data for doing some data comparison, I found out it's might not support by JSONObject for passing the data into the JSONObject. Do I need to use JSONArray in my case because my JSON data have array structure as well?
try
{
JSONObject obj = new JSONObject ();
obj.readJsonFromUrl(theUrl);
System.out.println(obj.toString());
}
catch(MalformedURLException e)
{
System.out.print("your problem here ...1");
}
}
else
{
System.out.print("Can't Connect");
}
I am sure that this is the place give me the error message because it return me this error in my compiler
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method readJsonFromUrl(URL) is undefined for the type JSONObject
there are also some warning message for that the JSONObject readJsonFromUrl method
private static JSONObject readJsonFromUrl(URL theUrl) throws IOException, JSONException {
Anyone can provide me the explaination of how the JSON data work in java? I saw quite number of Java class for JSON which make me confuse for it such as JSONObject, JSONArray , JSONValue. I search some information online but I also not very clear about it since I am very new to JSON data processing This is my sample json data and the data I need is scan_result only
{
"data_id":"a71a3c2588c6472bb4daea41a0b58835",
"file_info":{
"display_name":"",
"file_size":242,
"file_type":"Not available",
"file_type_description":"Not available",
"md5":"aa69ba384f22d0dc0551ace2fbb9ad55",
"sha1":"09ceb54e65df3d3086b222e8643acffe451a6e8a",
"sha256":"dcb46d6ae2a187f789c12f19c44bbe4b9a43bd200a3b306d5e9c1fcf811dc430",
"upload_timestamp":"2016-11-18T09:09:08.390Z"
},
"process_info":{
"blocked_reason":"",
"file_type_skipped_scan":false,
"post_processing":{
"actions_failed":"",
"actions_ran":"",
"converted_destination":"",
"converted_to":"",
"copy_move_destination":""
},
"profile":"File scan",
"progress_percentage":100,
"result":"Allowed",
"user_agent":""
},
"scan_results":{
"data_id":"a71a3c2588c6472bb4daea41a0b58835",
"progress_percentage":100,
"scan_all_result_a":"No Threat Detected",
"scan_all_result_i":0,
"scan_details":{
"Ahnlab":{
"def_time":"2016-11-08T15:00:00.000Z",
"location":"local",
"scan_result_i":0,
"scan_time":1,
"threat_found":""
},
"Avira":{
"def_time":"2016-11-08T00:00:00.000Z",
"location":"local",
"scan_result_i":0,
"scan_time":133,
"threat_found":""
},
"ClamAV":{
"def_time":"2016-11-08T10:28:00.000Z",
"location":"local",
"scan_result_i":0,
"scan_time":94,
"threat_found":""
},
"ESET":{
"def_time":"2016-11-08T00:00:00.000Z",
"location":"local",
"scan_result_i":0,
"scan_time":38,
"threat_found":""
}
},
"start_time":"2016-11-18T09:09:08.405Z",
"total_avs":4,
"total_time":250
},
"vulnerability_info":{
}
}
As mentioned here, there are many ways to solve this. Either you have to implement the read, parse operations yourself (#Roland Illig 's answer)
//you have to implement the readJSON method
InputStream is = new URL(url).openStream();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText = readAll(rd);
JSONObject json = new JSONObject(jsonText);
return json;
} finally {
is.close();
}
Or you could use a library. The most well-known and widely used libraries are jackson and gson.
The big picture is that you try to "map" your json Object to a class.
You have your json file:
{
"id":1,
"name":"eirini",
"hobbies":["music","philosophy","football"]
}
and a class that represents this file and will store the values (depending on the library that you use there might be different requirements, for example getters, setters etc..)
public class Person {
public int id;
public String name;
public List<String> hobbies = new ArrayList<String>();
public String toString() {
return name +" has the id: " + id + " the following hobbies" + hobbies.get(0) + " " + hobbies.get(2);
}
}
Finally in your main method:
public static void main(String[] args) throws IOException, ParseException {
ObjectMapper mapper = new ObjectMapper();
InputStream input = this.getClass().getResourceAsStream(FILE); //read your file. There are many ways to achieve this.
ObjectMapper mapper = new ObjectMapper(); // just need one
Person eirini = mapper.readValue(input, Person.class);
System.out.println(eirini.toString());
You cannot pass json in url, you can pass it in body. Writing Json to stream body and post it using regular java method.
Here is oracle community url of explanation of your problem.
Required Jar can be downloaded from here.
Test Code Follows:
URL url = new URL("https://graph.facebook.com/search?q=java&type=post");
try (InputStream is = url.openStream();
JsonReader rdr = Json.createReader(is)) {
JsonObject obj = rdr.readObject();
JsonArray results = obj.getJsonArray("data");
for (JsonObject result : results.getValuesAs(JsonObject.class)){
System.out.print(result.getJsonObject("from").getString("name"));
System.out.print(": ");
System.out.println(result.getString("message", ""));
System.out.println("-----------");
}
}
In my Android project I'm trying to create a list of MyType using gson. For this I use the following code:
String result = "[{\"text\": \"lala\", \"created\": \"123456\"}, {\"text\": \"lele\", \"created\": \"123456\"}]";
class ReceivedMessage {
String text;
String created;
}
List<ReceivedMessage> receivedMessages = new Gson().fromJson(result, new TypeToken<List<ReceivedMessage>>(){}.getType());
for (ReceivedMessage mess : receivedMessages) {
Log.wtf("This is it", mess.created);
}
Unfortunately I get a nullpointerexception. Does anybody know what I'm doing wrong here?
Defining the class "outside" worked pretty well:
public class ReceivedMessage {
String text;
String created;
}
public static void main(String[] args) {
String result = "[{\"text\": \"lala\", \"created\": \"123456\"}, "
+"{\"text\": \"lele\", \"created\": \"123456\"}]";
List<ReceivedMessage> receivedMessages = new Gson().fromJson(result,
new TypeToken<List<ReceivedMessage>>() {}.getType());
for (ReceivedMessage mess : receivedMessages) {
System.out.println("This is it " + mess.created);
}
....
}
Note: Gson uses reflection and so it needs access to the class.
Please try this :
Type listType = new TypeToken<ArrayList<ReceivedMessage>>() {}.getType();
List<ReceivedMessage> receivedMessages= new Gson().fromJson(result, listType);
Google Gson - deserialize list<class> object? (generic type)
I have a JsonObject named "mapping" with the following content:
{
"client": "127.0.0.1",
"servers": [
"8.8.8.8",
"8.8.4.4",
"156.154.70.1",
"156.154.71.1"
]
}
I know I can get the array "servers" with:
mapping.get("servers").getAsJsonArray()
And now I want to parse that JsonArray into a java.util.List...
What is the easiest way to do this?
Definitely the easiest way to do that is using Gson's default parsing function fromJson().
There is an implementation of this function suitable for when you need to deserialize into any ParameterizedType (e.g., any List), which is fromJson(JsonElement json, Type typeOfT).
In your case, you just need to get the Type of a List<String> and then parse the JSON array into that Type, like this:
import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;
JsonElement yourJson = mapping.get("servers");
Type listType = new TypeToken<List<String>>() {}.getType();
List<String> yourList = new Gson().fromJson(yourJson, listType);
In your case yourJson is a JsonElement, but it could also be a String, any Reader or a JsonReader.
You may want to take a look at Gson API documentation.
Below code is using com.google.gson.JsonArray.
I have printed the number of element in list as well as the elements in List
import java.util.ArrayList;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class Test {
static String str = "{ "+
"\"client\":\"127.0.0.1\"," +
"\"servers\":[" +
" \"8.8.8.8\"," +
" \"8.8.4.4\"," +
" \"156.154.70.1\"," +
" \"156.154.71.1\" " +
" ]" +
"}";
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
JsonParser jsonParser = new JsonParser();
JsonObject jo = (JsonObject)jsonParser.parse(str);
JsonArray jsonArr = jo.getAsJsonArray("servers");
//jsonArr.
Gson googleJson = new Gson();
ArrayList jsonObjList = googleJson.fromJson(jsonArr, ArrayList.class);
System.out.println("List size is : "+jsonObjList.size());
System.out.println("List Elements are : "+jsonObjList.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
OUTPUT
List size is : 4
List Elements are : [8.8.8.8, 8.8.4.4, 156.154.70.1, 156.154.71.1]
I read solution from official website of Gson at here
And this code for you:
String json = "{"client":"127.0.0.1","servers":["8.8.8.8","8.8.4.4","156.154.70.1","156.154.71.1"]}";
JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
JsonArray jsonArray = jsonObject.getAsJsonArray("servers");
String[] arrName = new Gson().fromJson(jsonArray, String[].class);
List<String> lstName = new ArrayList<>();
lstName = Arrays.asList(arrName);
for (String str : lstName) {
System.out.println(str);
}
Result show on monitor:
8.8.8.8
8.8.4.4
156.154.70.1
156.154.71.1
I was able to get the list mapping to work with just using #SerializedName for all fields.. no logic around Type was necessary.
Running the code - in step #4 below - through the debugger, I am able to observe that the List<ContentImage> mGalleryImages object populated with the JSON data
Here's an example:
1. The JSON
{
"name": "Some House",
"gallery": [
{
"description": "Nice 300sqft. den.jpg",
"photo_url": "image/den.jpg"
},
{
"description": "Floor Plan",
"photo_url": "image/floor_plan.jpg"
}
]
}
2. Java class with the List
public class FocusArea {
#SerializedName("name")
private String mName;
#SerializedName("gallery")
private List<ContentImage> mGalleryImages;
}
3. Java class for the List items
public class ContentImage {
#SerializedName("description")
private String mDescription;
#SerializedName("photo_url")
private String mPhotoUrl;
// getters/setters ..
}
4. The Java code that processes the JSON
for (String key : focusAreaKeys) {
JsonElement sectionElement = sectionsJsonObject.get(key);
FocusArea focusArea = gson.fromJson(sectionElement, FocusArea.class);
}
Kotlin Extension
for Kotlin developers you can use this extension
inline fun <reified T> String.convertToListObject(): List<T>? {
val listType: Type = object : TypeToken<List<T?>?>() {}.type
return Gson().fromJson<List<T>>(this, listType)
}
Given you start with mapping.get("servers").getAsJsonArray(), if you have access to Guava Streams, you can do the below one-liner:
List<String> servers = Streams.stream(jsonArray.iterator())
.map(je -> je.getAsString())
.collect(Collectors.toList());
Note StreamSupport won't be able to work on JsonElement type, so it is insufficient.