I'm using the org.json.simple.JSONObject library to read some text and form it into JSON.
The code I have is as follows:
public class PerfMetrics {
private static String filePath = "Shell_Pricing_Metrics.json";
private static String jsoncontent;
public static void clearFileContents(String filePath) throws IOException {
File f1 = new File(filePath);
new FileWriter(f1);
}
public static void metricAsJSON(String testName, long testTime) {
Date date = new Date();
Timestamp ts = new Timestamp(date.getTime());
JSONObject obj = new JSONObject();
obj.put("testname", testName);
obj.put("Duration", testTime);
obj.put("Timestamp", ts.toString());
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonParser jp = new JsonParser();
JsonElement je = jp.parse(obj.toJSONString());
jsoncontent = gson.toJson(je);
JsonArray jsonArray = new JsonArray();
jsonArray.add(je);
jsoncontent = gson.toJson(jsonArray);
}
public static void writeJsonToFile() {
try {
File f1 = new File(filePath);
if (!(f1.exists())) {
f1.createNewFile();
}
FileWriter fw1 = new FileWriter(f1, true);
PrintWriter pw1 = new PrintWriter(fw1);
if (f1.exists() && f1.isFile()) {
pw1.println(jsoncontent);
pw1.flush();
pw1.close();
fw1.close();
} else {
System.out.println("Please provide a valid path to destination Json file");
}
} catch(Exception e){
e.printStackTrace();
}
}
}
Writes to a file as:
[
{
"Duration": 30,
"testname": "Upload Data click to Model Prices dropdown display time:",
"Timestamp": "2019-10-15 09:47:53.804"
}
]
I need the data as:
[
{
"testname": "Shopping dropdown display time:",
"Duration": 2156,
"Timestamp": "2019-10-10 14:29:01.945"
},
{
"testname": "Clothing dropdown display time:",
"Duration": 3567,
"Timestamp": "2019-10-10 14:30:01.534"
},
{
"testname": "Electrical dropdown display time:",
"Duration": 2098,
"Timestamp": "2019-10-10 14:33:01.532"
},
{
"testname": "Toys dropdown display time:",
"Duration": 4562,
"Timestamp": "2019-10-10 14:35:01.435"
}
]
I can get around this clunkily with my limited Java skills but wondered what is the best library / practice to support the transformation of the object strings into a Json Array?
It looks like you're using the function once per JSONObject, and writing the file each time - if that's the case then you could instead return the JSONObject from that method:
/*... obj.put(key, value); obj.put('Timestamp') ... */
return obj;
And then where you call .metricAsJSON now, append it to a JSONArray object like so:
JSONArray arr = new JSONArray();
for (... metric in some other array ...) {
JSONObject obj = GetMetrics.metricAsJSON(key, value);
arr.put(obj);
}
String jsonString = arr.toString();
/* Write jsonString to file */
If you need to add values dynamically and write multiple times, you could store the JSONArray as a method variable, or load the file into a JSONArray object each time you need to append something to the end.
You need to do this
public class GetMetrics {
public static void clearFileContents(String filePath) throws IOException {
File f1 = new File(filePath);
new FileWriter(f1);
}
public static void metricAsJSON(String key, long value, String filePath) {
Date date = new Date();
Timestamp ts = new Timestamp(date.getTime());
JSONObject obj = new JSONObject();
obj.put(key, value);
obj.put("Timestamp", ts.toString());
try {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonParser jp = new JsonParser();
JsonElement je = jp.parse(obj.toJSONString());
String jsoncontent = = gson.toJson(je);
File f1 = new File(filePath);
if (!(f1.exists())) {
f1.createNewFile();
}
FileWriter fw1 = new FileWriter(f1, true);
PrintWriter pw1 = new PrintWriter(fw1);
if (f1.exists() && f1.isFile()) {
pw1.println(jsoncontent);
pw1.flush();
pw1.close();
fw1.close();
} else {
System.out.println("Please provide a valid path to destination Jsonfile");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Related
I try to generate csv file from json type data. These are my json test data.
{
"realtime_start":"2020-09-25",
"realtime_end":"2020-09-25",,
"units": "Percent",
"seriess": [
{
"name": "James",
"age": 29,
"house": "CA"
},
{
"name": "Jina",
"age": 39,
"house": "MA",
"notes": "Million tonne punch"
},
}
The problem is json array type "seriess" does not contain "notes" node in all every nodes.
I made the below java codes to change this json data to csv file with header columns
JSONObject json = getJsonFileFromURL(...)
JSONArray docsArray = json.getJSONArray("seriess");
docsArray.put(json.get("realtime_start"));
docsArray.put(json.get("realtime_end"));
docsArray.put(json.get("units"));
JsonNode jsonTree = new ObjectMapper().readTree(docsArray.toString());
Builder csvSchemaBuilder = CsvSchema.builder();
for(JsonNode node : jsonTree) {
node.fieldNames().forEachRemaining(fieldName -> {csvSchemaBuilder.addColumn(fieldName);} );
}
CsvSchema csvSchema = csvSchemaBuilder.build().withHeader();
CsvMapper csvMapper = new CsvMapper();
csvMapper.writerFor(JsonNode.class).with(csvSchema).writeValue(new File("test.csv"), jsonTree);
But the incorrect results are shown like below,
realtime_start,realtime_end,units,names,age,house,realtime_start,realtime_end,units,names,age,house,notes, realtime_start,.....
The generated header columns does not contain distinct values. The header columns are added in duplicate. How can I generate the distinct header like below
realtime_start,realtime_end,units,names,age,house, notes
Any idea?
Update Part
I try to extract data from the FRED (FEDERAL RESERVE BANK OF ST. LOUIS). FRED provide simple and convenient Python api like below,
from fredapi import Fred
import pandas as pd
fred = Fred(api_key='abcdefghijklmnopqrstuvwxyz0123456789')
data_unemploy = fred.search('Unemployment Rate in California')
data_unemploy.to_csv("test_unemploy.csv")
But the java apis are deprecated, so I have to develop simple Java api which convert json values to csv file. I found the below Java codes with googling
JSONObject json = getJsonFileFromURL("https://api.stlouisfed.org/fred/series/search?search_text=Unemployment+Rate+in+California&api_key=abcdefghijklmnopqrstuvwxyz0123456789&file_type=json");
JSONArray docsArray = json.getJSONArray("seriess");
docsArray.put(json.get("realtime_start"));
docsArray.put(json.get("realtime_end"));
JsonNode jsonTree = new ObjectMapper().readTree(docsArray.toString());
JsonNode firstObject = jsonTree.elements().next(); // I am struggling with this line
firstObject.fieldNames().forEachRemaining(fieldName -> {csvSchemaBuilder.addColumn(fieldName);} );
CsvSchema csvSchema = csvSchemaBuilder.build().withHeader();
CsvMapper csvMapper = new CsvMapper();
csvMapper.writerFor(JsonNode.class).with(csvSchema).writeValue(new File("test.csv"), jsonTree);
To extract columns from json data JsonNode firstObject = jsonTree.elements().next(); return the first json node. But this line does not return notes column. because the first line does not contain the notes key value.
So I change this code line to following lines
for(JsonNode node : jsonTree) {
node.fieldNames().forEachRemaining(fieldName -> {
csvSchemaBuilder.addColumn(fieldName);
} );
}
But these lines throws the results which I do not expect. The repeated duplicated columns like below
realtime_start,realtime_end,units,names,age,house,realtime_start,realtime_end,units,names,age,house,notes, realtime_start,.....
I am totally stuck with this part.
Most probably it is easiest to write a bin type class like below :
public class CsvVo {
private String realtime_start;
private String realtime_end;
private String units;
private String name;
private String age;
private String house;
private String notes;
public void setRealtime_start(String realtime_start) {
this.realtime_start = realtime_start;
}
//Other getters and Setters
Then you can Write :
public class ConvertJsonToCSVTest {
public static void main(String[] args) throws JSONException {
String jsonArrayString = "{\n" +
"\t\"realtime_start\": \"2020-09-25\",\n" +
"\t\"realtime_end\": \"2020-09-25\",\n" +
"\t\"units\": \"Percent\",\n" +
"\t\"seriess\": [{\n" +
"\t\t\t\"name\": \"James\",\n" +
"\t\t\t\"age\": 29,\n" +
"\t\t\t\"house\": \"CA\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"name\": \"Jina\",\n" +
"\t\t\t\"age\": 39,\n" +
"\t\t\t\"house\": \"MA\",\n" +
"\t\t\t\"notes\": \"Million tonne punch\"\n" +
"\t\t}\n" +
"\t]\n" +
"}";
JSONObject inJson;
List<CsvVo> list = new ArrayList<>();
inJson = new JSONObject(jsonArrayString);
JSONArray inJsonSeries = inJson.getJSONArray("seriess");
for (int i = 0, size = inJsonSeries.length(); i < size; i++){
CsvVo line = new CsvVo();
line.setRealtime_start(inJson.get("realtime_start").toString());
line.setRealtime_end(inJson.get("realtime_end").toString());
line.setUnits(inJson.get("units").toString());
JSONObject o = (JSONObject)inJsonSeries.get(i);
line.setName(o.get("name").toString());
line.setAge(o.get("age").toString());
line.setHouse(o.get("house").toString());
try {
line.setNotes(o.get("notes").toString());
}catch (JSONException e){
line.setNotes("");
}
list.add(line);
}
String[] cols = {"realtime_start", "realtime_end", "units", "name", "age", "house", "notes"};
CsvUtils.csvWriterUtil(CsvVo.class, list, "in/EmpDetails.csv", cols);
}
}
csvWriterUtil is like below :
public static <T> void csvWriterUtil(Class<T> beanClass, List<T> data, String outputFile, String[] columnMapping){
try{
Writer writer = new BufferedWriter(new FileWriter(outputFile));
ColumnPositionMappingStrategy<T> strategy = new ColumnPositionMappingStrategy<>();
strategy.setType(beanClass);
strategy.setColumnMapping(columnMapping);
StatefulBeanToCsv<T> statefulBeanToCsv =new StatefulBeanToCsvBuilder<T>(writer)
.withMappingStrategy(strategy)
.build();
writer.write(String.join(",",columnMapping)+"\n");
statefulBeanToCsv.write(data);
writer.close();
} catch (IOException e) {
e.printStackTrace();
} catch (CsvRequiredFieldEmptyException e) {
e.printStackTrace();
} catch (CsvDataTypeMismatchException e) {
e.printStackTrace();
}
}
Full example is available in GitRepo
You can do it with a library Apache Commons IO
pom.xml
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
ConvertJsonToCSVTest.java
import java.io.File;
import org.apache.commons.io.FileUtils;
import org.json.*;
public class ConvertJsonToCSVTest {
public static void main(String[] args) throws JSONException {
String jsonArrayString = "{\"fileName\": [{\"first name\": \"Adam\",\"last name\": \"Smith\",\"location\": \"London\"}]}";
JSONObject output;
try {
output = new JSONObject(jsonArrayString);
JSONArray docs = output.getJSONArray("fileName");
File file = new File("EmpDetails.csv");
String csv = CDL.toString(docs);
FileUtils.writeStringToFile(file, csv);
System.out.println("Data has been Sucessfully Writeen to "+ file);
System.out.println(csv);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
Output
Data has been Sucessfully Writeen to EmpDetails.csv
last name,first name,location
Smith,Adam,London
This is "test.json" before I run my code:
{
"example1": {
"example2": {
"example3": 30
}
}
}
When I run this code:
public static void test() throws IOException {
Path fileName = Paths.get("src/test.json");
try (BufferedReader reader = Files.newBufferedReader(fileName);
BufferedWriter writer = Files.newBufferedWriter(fileName, StandardOpenOption.WRITE)) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonObject value = gson.fromJson(reader, JsonObject.class);
JsonObject object1 = new JsonObject();
JsonObject object2 = new JsonObject();
value.add("example1", object1);
object1.add("example2", object2);
object2.addProperty("example4", 40);
gson.toJson(value, writer);
}
}
Then this happens to "test.json":
{
"example1": {
"example2": {
"example4": 40
}
}
}
How can I add the data from "example4" to "example2" without removing "example3"?
I have the following json
"notes": {"note": [
{
"content": "Having wisdom teeth removed.",
"from": "employee"
},
{
"content": "Get well soon",
"from": "manager"
}
]},
the issue is that the value coud also be
"notes": "",
or
"notes": {"note": {
"content": "This is a test note.",
"from": "employee"
}},
and storing it in these
public class Notes
{
#SerializedName ("note")
public List<Note> note;
}
public class Note
{
#SerializedName ("content")
public String content;
#SerializedName ("from")
public String from;
}
I believe I solved the issue of not being an array but being an single object by doing this
public class Json {
private static Gson gson;
private static class MyNoteClassTypeAdapter implements JsonDeserializer<List<RequestsDTO.Note>> {
public List<RequestsDTO.Note> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) {
List<RequestsDTO.Note> vals = new ArrayList<RequestsDTO.Note>();
if (json.isJsonArray()) {
for (JsonElement e : json.getAsJsonArray()) {
vals.add((RequestsDTO.Note) ctx.deserialize(e, RequestsDTO.Note.class));
}
} else if (json.isJsonObject()) {
vals.add((RequestsDTO.Note) ctx.deserialize(json,RequestsDTO.Note.class));
} else {
throw new RuntimeException("Unexpected JSON type: " + json.getClass());
}
return vals;
}
}
public static Gson getGson()
{
if (gson == null)
{
Type ListType = new TypeToken<List<RequestsDTO.Note>>() {}.getType();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(DateTime.class, new DateTimeSerializer());
builder.registerTypeAdapter(ListType, new MyNoteClassTypeAdapter());
gson = builder.create();
}
return gson;
}
}
And now I am stuck on when the whole thing just comes back as a string....
Refer the code snippet below to deserialize your json using Gson library without exceptions.
String jsonStr = "your json string ";
Gson gson = new Gson();
JsonObject jsonObj = gson.fromJson (jsonStr, JsonElement.class).getAsJsonObject();
JsonElement elem = jsonObj.get("note");
if(elem.isJsonArray()) { //**Array**
List<Note> notelist = gson.fromJson(elem.toString(), new TypeToken<List<Note>>(){}.getType());
} else if(elem.isJsonObject()) { //**Object**
Note note = gson.fromJson(elem.toString(), Note.class);
} else { //**String**
String note = elem.toString();
}
The idea is try to get "note" field (from "notes" JSONObject) as JSONArray first and if it throws exception that will mean that there is no "note" JSONArray into "notes" JSONObject and that will mean that "note" is JSONObject. The same way we can figure out situation when note field is String.
try {
//String jsonString="{\"notes\": {\"note\": [{\"content\": \"Having wisdom teeth removed.\",\"from\": \"employee\" }, {\"content\": \"Get well soon\", \"from\": \"manager\"} ] }}";
//String jsonString="{\"notes\": { \"note\": {\"content\": \"This is a test note.\",\"from\": \"employee\"}}}";
String jsonString="{\"notes\": { \"note\": \"\"}}";
JSONObject jsonObject=new JSONObject(jsonString);
JSONObject jsonObjectNotes=jsonObject.getJSONObject("notes");
try{
JSONArray jsonArrayNote=jsonObjectNotes.getJSONArray("note");
for (int i = 0; i < jsonArrayNote.length(); i++) {
JSONObject jsonObject2= jsonArrayNote.getJSONObject(i);
String stringContent=jsonObject2.getString( "content");
String stringFrom= jsonObject2.getString( "from");
Log.e(getClass().getName(), "content="+stringContent +"; from="+stringFrom);
}
}
catch(JSONException e){
//that means that jsonObjectNotes has no jsonArray with name "notes" and "notes" is jsonObject
try{
JSONObject jsonObject3=jsonObjectNotes.getJSONObject("note");
String stringContent=(String) jsonObject3.get( "content");
String stringFrom=(String) jsonObject3.get( "from");
Log.e(getClass().getName(), "content="+stringContent +"; from="+stringFrom);
}
catch(JSONException ex){
//that means that jsonObjectNotes has no jsonObject with name "notes" and "notes" is empty String
String stringNote=jsonObjectNotes.getString("note") ;
Log.e(getClass().getName(), "note is string ="+ stringNote);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
In my example code another get operations can also throw jsonExceptions but I think you get the idea.
Have a look at Genson library http://code.google.com/p/genson/.
If your classes are inner classes make them static.
The following code should solve your problem.
Genson genson = new Genson.Builder().withDeserializerFactory(new NotesDeserializerFactory()).create();
Notes notes = genson.deserialize(in, Notes.class);
// Define a factory so you can delegate the deserialization to existing mechanisms for lists and beans
class NotesDeserializerFactory implements Factory<Deserializer<Notes>> {
#Override
public Deserializer<Notes> create(Type type, Genson genson) {
Converter<List<Note>> noteListConverter = genson.provideConverter(new GenericType<List<Note>>() {}.getType());
Converter<Note> noteConverter = genson.provideConverter(Note.class);
return new NotesDeserializer(noteListConverter, noteConverter);
}
}
// define an implementation for you Notes class so you can handle the different cases
class NotesDeserializer implements Deserializer<Notes> {
private final Converter<List<Note>> noteListConverter;
private final Converter<Note> noteConverter;
public NotesDeserializer(Converter<List<Note>> noteListConverter,
Converter<Note> noteConverter) {
this.noteListConverter = noteListConverter;
this.noteConverter = noteConverter;
}
#Override
public Notes deserialize(ObjectReader reader, Context ctx) throws TransformationException,
IOException {
Notes notes = new Notes();
if (reader.getValueType() == ValueType.ARRAY) notes.note = noteListConverter.deserialize(reader, ctx);
else if (reader.getValueType() == ValueType.OBJECT) notes.note = Arrays.asList(noteConverter.deserialize(reader, ctx));
else { // it is a litteral (string, numeric, boolean, null)
notes.note = new ArrayList<Note>();
}
return notes;
}
}
I am trying to write an automated Java test where the code will go to a specified URL, read the JSON data and print it up.
Here is the JSON I am trying to access;
{
"status": "success",
"records": [
{
"timestamp": 1381222871868,
"deviceId": "288",
"temperature": 17
},
{
"timestamp": 1381222901868,
"deviceId": "288",
"temperature": 17
},
{
"timestamp": 1381222931868,
"deviceId": "288",
"temperature": 17
},
]}
As you can see I only have 3 elements, Timestamp, DeviceId and Temperature.
What I am ultimately aiming for it to be able to get 2 Timestamp values and take one value away from the other, if that is possible.
Anyway I have been trying to do this all day and am having no luck whatsoever. I was recommended to use Gson and I have included the jar files into my classpath.
If anyone knows anything or can help me in any way it would be much appreciated as I have exhausted Google and myself trying to work this out.
Here is the code I have to display the full list, but I do not fully understand it and so far can't manipulate it to my advantage;
public static void main(String[] args) throws Exception
{
String jsonString = callURL("http://localhost:8000/eem/api/v1/metrics/temperature/288");
System.out.println("\n\njsonString: " + jsonString);
// Replace this try catch block for all below subsequent examples
/*try
{
JSONArray jsonArray = new JSONArray(jsonString);
System.out.println("\n\njsonArray: " + jsonArray);
}
catch (JSONException e)
{
e.printStackTrace();
}*/
try
{
JSONArray jsonArray = new JSONArray(jsonString);
int count = jsonArray.length(); // get totalCount of all jsonObjects
for(int i=0 ; i< count; i++)
{ // iterate through jsonArray
JSONObject jsonObject = jsonArray.getJSONObject(i); // get jsonObject # i position
System.out.println("jsonObject " + i + ": " + jsonObject);
}
}
catch (JSONException e)
{
e.printStackTrace();
}
}
public static String callURL(String myURL)
{
//System.out.println("Requested URL:" + myURL);
StringBuilder sb = new StringBuilder();
URLConnection urlConn = null;
InputStreamReader in = null;
try
{
URL url = new URL(myURL);
urlConn = url.openConnection();
if (urlConn != null)
{
urlConn.setReadTimeout(60 * 1000);
}
if (urlConn != null && urlConn.getInputStream() != null)
{
in = new InputStreamReader(urlConn.getInputStream(),
Charset.defaultCharset());
BufferedReader bufferedReader = new BufferedReader(in);
if (bufferedReader != null)
{
int cp;
while ((cp = bufferedReader.read()) != -1)
{
sb.append((char) cp);
}
bufferedReader.close();
}
}
in.close();
}
catch (Exception e)
{
throw new RuntimeException("Exception while calling URL:"+ myURL, e);
}
return sb.toString();
}
Cheers
I had read the values from file but you can read from URL, the extracting process code is present inside extractJson() method.
public static void main(String [] args)
{
try
{
FileInputStream fis=new FileInputStream("testjson.json");
int b=0;
String val="";
while((b=fis.read())!=-1)
{
val=val+(char)b;
}
extractJson(val);
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void extractJson(String json)
{
try
{
JSONObject jobject=new JSONObject(json);
System.out.println("Json object Length: "+jobject.length());
System.out.println("Status: "+jobject.getString("status"));
JSONArray jarray=new JSONArray(jobject.getString("records"));
System.out.println("Json array Length: "+jarray.length());
for(int j=0;j<jarray.length();j++)
{
JSONObject tempObject=jarray.getJSONObject(j);
System.out.println("Timestamp: "+tempObject.getString("timestamp"));
System.out.println("Device Id: "+tempObject.getString("deviceId"));
System.out.println("Temperature: "+tempObject.getString("temperature"));
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
You could use ArrayList to store the values which will be available inside for loop. From your question you need to pass jsonString this variable to the extractJson() method. Use org.json jar file to process json. If you could alter this for gson then it'll be good for your requirement.
here's how to do it via Google-Gson
class MyRecord
{
private long timestamp;
private String deviceId;
private Integer temperature;
//Getters & setters
}
public static void main(String... args){
String myJsonString=callUrl("http://mydomain.com/x.json");
JsonParser jp = new JsonParser();
JsonElement ele = jp.parse(myJsonString);
Gson gg = new Gson();
Type type = new TypeToken<List<MyRecord>>() {
}.getType();
List<MyRecord> lst= gg.fromJson(ele.getAsJsonObject().get("records"), type);
//Now the json is parsed in a List of MyRecord, do whatever you want to with it
}
An "high-level" Gson parsing answer:
package stackoverflow.questions.q19252374;
import java.util.List;
import com.google.gson.Gson;
public class Q19252374 {
class Record {
Long timestamp;
String deviceId;
Long temperature;
}
class Container {
List<Record> records;
}
public static void main(String[] args) {
String json = "{ \"status\": \"success\", \"records\": [{\"timestamp\": 1381222871868,\"deviceId\": \"288\",\"temperature\": 17 },{\"timestamp\": 1381222901868,\"deviceId\": \"288\",\"temperature\": 17 },{\"timestamp\": 1381222931868,\"deviceId\": \"288\",\"temperature\": 17 } ]} ";
Gson g = new Gson();
Container c = g.fromJson(json, Container.class);
for (Record r : c.records)
System.out.println(r.timestamp);
}
}
Of course this is the result:
1381222871868
1381222901868
1381222931868
I have the following json
"notes": {"note": [
{
"content": "Having wisdom teeth removed.",
"from": "employee"
},
{
"content": "Get well soon",
"from": "manager"
}
]},
the issue is that the value coud also be
"notes": "",
or
"notes": {"note": {
"content": "This is a test note.",
"from": "employee"
}},
and storing it in these
public class Notes
{
#SerializedName ("note")
public List<Note> note;
}
public class Note
{
#SerializedName ("content")
public String content;
#SerializedName ("from")
public String from;
}
I believe I solved the issue of not being an array but being an single object by doing this
public class Json {
private static Gson gson;
private static class MyNoteClassTypeAdapter implements JsonDeserializer<List<RequestsDTO.Note>> {
public List<RequestsDTO.Note> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) {
List<RequestsDTO.Note> vals = new ArrayList<RequestsDTO.Note>();
if (json.isJsonArray()) {
for (JsonElement e : json.getAsJsonArray()) {
vals.add((RequestsDTO.Note) ctx.deserialize(e, RequestsDTO.Note.class));
}
} else if (json.isJsonObject()) {
vals.add((RequestsDTO.Note) ctx.deserialize(json,RequestsDTO.Note.class));
} else {
throw new RuntimeException("Unexpected JSON type: " + json.getClass());
}
return vals;
}
}
public static Gson getGson()
{
if (gson == null)
{
Type ListType = new TypeToken<List<RequestsDTO.Note>>() {}.getType();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(DateTime.class, new DateTimeSerializer());
builder.registerTypeAdapter(ListType, new MyNoteClassTypeAdapter());
gson = builder.create();
}
return gson;
}
}
And now I am stuck on when the whole thing just comes back as a string....
Refer the code snippet below to deserialize your json using Gson library without exceptions.
String jsonStr = "your json string ";
Gson gson = new Gson();
JsonObject jsonObj = gson.fromJson (jsonStr, JsonElement.class).getAsJsonObject();
JsonElement elem = jsonObj.get("note");
if(elem.isJsonArray()) { //**Array**
List<Note> notelist = gson.fromJson(elem.toString(), new TypeToken<List<Note>>(){}.getType());
} else if(elem.isJsonObject()) { //**Object**
Note note = gson.fromJson(elem.toString(), Note.class);
} else { //**String**
String note = elem.toString();
}
The idea is try to get "note" field (from "notes" JSONObject) as JSONArray first and if it throws exception that will mean that there is no "note" JSONArray into "notes" JSONObject and that will mean that "note" is JSONObject. The same way we can figure out situation when note field is String.
try {
//String jsonString="{\"notes\": {\"note\": [{\"content\": \"Having wisdom teeth removed.\",\"from\": \"employee\" }, {\"content\": \"Get well soon\", \"from\": \"manager\"} ] }}";
//String jsonString="{\"notes\": { \"note\": {\"content\": \"This is a test note.\",\"from\": \"employee\"}}}";
String jsonString="{\"notes\": { \"note\": \"\"}}";
JSONObject jsonObject=new JSONObject(jsonString);
JSONObject jsonObjectNotes=jsonObject.getJSONObject("notes");
try{
JSONArray jsonArrayNote=jsonObjectNotes.getJSONArray("note");
for (int i = 0; i < jsonArrayNote.length(); i++) {
JSONObject jsonObject2= jsonArrayNote.getJSONObject(i);
String stringContent=jsonObject2.getString( "content");
String stringFrom= jsonObject2.getString( "from");
Log.e(getClass().getName(), "content="+stringContent +"; from="+stringFrom);
}
}
catch(JSONException e){
//that means that jsonObjectNotes has no jsonArray with name "notes" and "notes" is jsonObject
try{
JSONObject jsonObject3=jsonObjectNotes.getJSONObject("note");
String stringContent=(String) jsonObject3.get( "content");
String stringFrom=(String) jsonObject3.get( "from");
Log.e(getClass().getName(), "content="+stringContent +"; from="+stringFrom);
}
catch(JSONException ex){
//that means that jsonObjectNotes has no jsonObject with name "notes" and "notes" is empty String
String stringNote=jsonObjectNotes.getString("note") ;
Log.e(getClass().getName(), "note is string ="+ stringNote);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
In my example code another get operations can also throw jsonExceptions but I think you get the idea.
Have a look at Genson library http://code.google.com/p/genson/.
If your classes are inner classes make them static.
The following code should solve your problem.
Genson genson = new Genson.Builder().withDeserializerFactory(new NotesDeserializerFactory()).create();
Notes notes = genson.deserialize(in, Notes.class);
// Define a factory so you can delegate the deserialization to existing mechanisms for lists and beans
class NotesDeserializerFactory implements Factory<Deserializer<Notes>> {
#Override
public Deserializer<Notes> create(Type type, Genson genson) {
Converter<List<Note>> noteListConverter = genson.provideConverter(new GenericType<List<Note>>() {}.getType());
Converter<Note> noteConverter = genson.provideConverter(Note.class);
return new NotesDeserializer(noteListConverter, noteConverter);
}
}
// define an implementation for you Notes class so you can handle the different cases
class NotesDeserializer implements Deserializer<Notes> {
private final Converter<List<Note>> noteListConverter;
private final Converter<Note> noteConverter;
public NotesDeserializer(Converter<List<Note>> noteListConverter,
Converter<Note> noteConverter) {
this.noteListConverter = noteListConverter;
this.noteConverter = noteConverter;
}
#Override
public Notes deserialize(ObjectReader reader, Context ctx) throws TransformationException,
IOException {
Notes notes = new Notes();
if (reader.getValueType() == ValueType.ARRAY) notes.note = noteListConverter.deserialize(reader, ctx);
else if (reader.getValueType() == ValueType.OBJECT) notes.note = Arrays.asList(noteConverter.deserialize(reader, ctx));
else { // it is a litteral (string, numeric, boolean, null)
notes.note = new ArrayList<Note>();
}
return notes;
}
}