Why does JSONTokener/Object keep randomizing my json data? - java

I've been trying to debug this problem for hours and have Googled it and can't even find someone who's having the same problem. For some reason JSONObject/JSONTokener is doing bizarre things.
The following code:
JSONObject jsonObj = (JSONObject) new JSONTokener(sourceJson).nextValue();
Log.d(" ", sourceJson + "\n");
Log.d(" ", jsonObj.toString());
Produces this output:
{
"2012":{
"federal":[[10822,0.15],[42707,0.22],[85414,0.26],[132406,0.29]],
"provincial":{
"AB":[[17282,0.1]],
"BC":[[11354,0.0506],[37013,0.077],[74028,0.105],[84993,0.1229],[103205,0.147]],
"MB":[[8634,0.108],[31000,0.1275],[67000,0.174]],
"NB":[[9203,0.091],[38190,0.121],[76380,0.124],[124178,0.143]],
"NL":[[8237,0.077],[32893,0.125],[65785,0.133]],
"NS":[[8481,0.0879],[29590,0.1495],[59180,0.1667],[93000,0.175],[150000,0.21]],
"NT":[[13280,0.059],[38679,0.086],[77360,0.122],[125771,0.1405]],
"NU":[[12211,0.04],[40721,0.07],[81442,0.09],[132406,0.115]],
"ON":[[9405,0.0505],[39020,0.0915],[78043,0.1116],[500000,0.1216]],
"PE":[[7708,0.098],[31984,0.138],[63969,0.167]],
"QC":[[10925,0.16],[40100,0.2],[80200,0.24]],
"SK":[[14942,0.11],[42065,0.13],[120185,0.15]],
"YT":[[10822,0.0704],[42707,0.0968],[85414,0.1144],[132406,0.1276]]
}
}
}
{"2012":{"provincial":{"ON":[[9405,0.0505],[39020,0.0915],[78043,0.1116],[500000,0.1216]],"AB":[[17282,0.1]],"BC":[[11354,0.0506],[37013,0.077],[74028,0.105],[84993,0.1229],[103205,0.147]],"NL":[[8237,0.077],[32893,0.125],[65785,0.133]],"QC":[[10925,0.16],[40100,0.2],[80200,0.24]],"NU":[[12211,0.04],[40721,0.07],[81442,0.09],[132406,0.115]],"SK":[[14942,0.11],[42065,0.13],[120185,0.15]],"PE":[[7708,0.098],[31984,0.138],[63969,0.167]],"NT":[[13280,0.059],[38679,0.086],[77360,0.122],[125771,0.1405]],"NS":[[8481,0.0879],[29590,0.1495],[59180,0.1667],[93000,0.175],[150000,0.21]],"YT":[[10822,0.0704],[42707,0.0968],[85414,0.1144],[132406,0.1276]],"NB":[[9203,0.091],[38190,0.121],[76380,0.124],[124178,0.143]],"MB":[[8634,0.108],[31000,0.1275],[67000,0.174]]},"federal":[[10822,0.15],[42707,0.22],[85414,0.26],[132406,0.29]]}}
The nicely formatted data above is identical to the data.json file that I used to populate sourceJson and the very long line has had the order of the provinces mysteriously rearranged (but not the data within each province's 2D array).
I've also tried:
JSONObject jsonObj = new JSONObject(sourceJson); // same problem
and
JSONTokener jsonTk = new JSONTokener(sourceJson);
Log.d(" ", jsonTk.toString()); // result = " at character 0 of " + sourceJson;
Log.d(" ", jsonTk.nextValue().toString()); // output same as original problem
I also tried to using a breakpoint to trace the call to nextValue() but couldn't find the cause of the problem. The behavior suggests that the JSONObject(String) constructor may call nextValue(), since both methods give the same output.
So the question is: Does anyone know why JSONObject/JSONTokener.nextValue() behaves this way? And, more importantly, do you know how to get it to parse the JSON data without reorganizing it? (I need to iterate through the data, even if the data file changes in the future)
Thanks a bunch!

JSON objects (nodes) are not ordered. It is definition of json format. In Java are JSON nodes implemented as HashMap and HashMap is not ordered too.
If you really need something ordered in JSON, you need to use JSON Array. Example:
{
"2012":{
"federal":[[10822,0.15],[42707,0.22],[85414,0.26],[132406,0.29]],
"provincial":{
["code":"AB", data:[[17282,0.1]]],
["code":"BC", data:[[11354,0.0506],[37013,0.077],[74028,0.105],[84993,0.1229],[103205,0.147]]],
["code":"MB", data:[[8634,0.108],[31000,0.1275],[67000,0.174]]]
.
.
.

Related

Java/Android JSONArray inside JSONObject returning null

I'm developing an app for android that communicates with a server and receives JSON responses from it. Recently I changed the responses structure to contain more information about the requests.
Initially my responses where just the response from a mysqli_query encoded to JSON by the php function json_encode, and looked like this:
[
{"id":"31","description":"Hello"},
{"id":"32","description":"World"},
]
And to retrieve the objects, I would just create a new JSONArray object by calling my_json_array=new JSONArray(response) and iterate over it.
But now, my new responses contain extra data, like this:
{
"error":false,
"idCode":0,
"message":[
{
"id":"32",
"description":"Hello"
},
{
"id":"31",
"description":"World"
}
]
}
So now, as far as I understand, I need to convert this response to a JSONObject, and then extract the message as a JSONarray object by calling my_json_object.getJSONArray("message");.
I can extract the data from the "error" and the "idCode" fields normally, but when I try to extract the JSONArray from "message" it returns null, and no exceptions are thrown except for the NullPointerException.
I've validated the JSON string here, escaped the characters that could be problematic for java like the double quotes, removed uppercases, written the response as a single line, removed the double quotes surrounding the "id" value, used single quotes instead of double quotes, used harcoded string instead of the response from the server, checked the unicode representation of the string to see if contains any invalid characters (and it looks like it doesn't) and I don't know what else to do. Something to notice: the method toString() on the object returns the string "null", and based on the toString() method of the JSONObjects, it seems like the problem comes from the JSONStringer library, and going deeper on the classes it looks like the exception that there is a nesting problem, but I can't find any problem in my JSON string.
The important part of the code:
public String getResponse(){
web_helper.sendRequest();
//everything fine over here
return web_helper.getResponse();
}
public void printData(){ throws JSONExpection
JSONObject my_json_object=new JSONObject(getResponse());
System.out.println("error: "+my_json_object.getBoolean("error"));
System.out.println("idCode: "+my_json_object.getInt("idCode"));
JSONArray my_json_array=my_json_object.getJSONArray("message");
//not sure if the next part works because my_json_array is null
for(int i=0; i<my_json_array.length(); i++){
JSONObject obj=my_json_array.getJSONObject(i);
System.out.println("id: "+obj.getInt("id"));
System.out.println("description: "+obj.getString("description"));
}
}
Any help is appreciated, thank you in advance!.

Processing: how to check if JSON Objects are bound

Since the Processing forum is down I hope one of you guys can help me out.
I made a Processing sketch that pulls data from an API (test here: http://www.europeana.eu/portal/api/console.html ) in JSON-format and reads some fields of this data for visualization. Everything works fine so far except when there are fields that are not bound to every JSONObject.
This is the code for the retrieval of the data:
JSONObject json;
json = loadJSONObject("data.json"); // loading my JSON file into the object
JSONArray CHOData = json.getJSONArray("items"); // array of the items I want data from
for (int i = 0; i < CHOData.size(); i++) {
JSONObject CHO = CHOData.getJSONObject(i); // get a specific item
JSONArray previewObj = CHO.getJSONArray("edmPreview"); // this field is an array, so I need to store it in a JSONArray object first
String[] previewArray = previewObj.getStringArray(); // here I store it in my actual string array
String preview = previewArray[0]; // I only need the first element
}
As you can see, I want the first string of the "edmPreview" array in the object. When I run the sketch, I get an error: "JSONObject["edmPreview"] not found."
This is of course because not every item has such an object. But how can I test if there is an object with this name in an item? I tried with if(CHO.getJSONObject("edmPreview") != null), but same error. Is there a way to look into the JSONObject and check the data values for something called "edmPreview"? There is no such function explained in the Processing reference.
The JSON file essentially looks as follows:
{
"items": [
{
"id": "someID",
"edmPreview": [
"http://europeanastatic.eu/api/image?uri=someimage.jpg"
],
// some other fields
}, // some other items
]
}
I'm new to this JSON-stuff, so maybe I miss something important... Thanks for the help!
So I found the answer myself, but not in the Processing reference, but in the actual reference for the JSONObject class in Java (http://www.json.org/javadoc/org/json/JSONObject.html). I tried some of the methods there and found that hasKey() (which is actually something I came up with myself, combining the method "has()" with the term "key", pure coincidence) as a boolean value works very well:
String preview = "";
if (CHO.hasKey("edmPreview")) {
JSONArray previewObj = CHO.getJSONArray("edmPreview");
String[] previewArray = previewObj.getStringArray();
preview = previewArray[0];
}
So now I learned that Processing is essentially just Java and sometimes not every method is written in the Reference. :-)

How to write multiple records to JSON in file on Java

I need to write multiple json in one file, the problem is that every time that inserts inserted as follows:
{"1":"{\"id\":\"1\"}"**}{**"2":"{\"id\":\"2\"}"**}{**"3":"{\"id\":\"3\"}"}
and I need the chain follows to that can be read for JSON:
{"1":"{\"id\":\"1\"}"**,**"2":"{\"id\":\"2\"}"**,**"3":"{\"id\":\"3\"}"}
my code is:
public void writeMci(String mci, String nombreMci) throws Exception{
FileReadWrite a=new FileReadWrite();
JSONObject vjo = new JSONObject();
vjo.put(nombreMci, mci);
try {
BufferedWriter write=new BufferedWriter(new FileWriter("c:\\JSON.json", true));
write.write(vjo.toString());
write.flush();
write.close();
} catch (IOException e) {
//manejar error
}
System.out.print(vjo);
}
The line you want
{"1":"{\"id\":\"1\"}"**,**"2":"{\"id\":\"2\"}"**,**"3":"{\"id\":\"3\"}"}
isn't legal either, I assume you mean (at least) something like this:
{"1":"{\"id\":\"1\"}","2":"{\"id\":\"2\"}","3":"{\"id\":\"3\"}"}
Note that this is not a JSON array, it's an object with string fields respectively called 1 2 and 3 that happen to contain JSON syntaxed string values. Although not illegal, it's highly questionable you actually want that
Now, could it be that you mean
{"1":{"id":"1"},"2":{"id":"2"},"3":{"id":"3"}}
Still an object but with object fields respectively called 1 2 and 3, where the object has just 1 field called id? Anyways (disclaimer: not an org.json library user myself - see below - so not giving any guarantees wrt the accuracy of the code :) ) :
// Create the outer container
JSONObject outer = new JSONObject();
// Create a container for the first contained object
JSONObject inner1 = new JSONObject();
inner1.put("id",1);
// and add that to outer
outer.put("1",inner1);
// Create a container for the second contained object
JSONObject inner2 = new JSONObject();
inner2.put("id",2);
// and add to outer as well
outer.put("2",inner2);
// Create a container for the third contained object
JSONObject inner3 = new JSONObject();
inner3.put("id",3);
// and add that to outer
outer.put("3",inner3);
// at this point
outer.toString()
// should return the JSON String from my last step.
if you actually want it to be an array, you need to put the objects in a JSONArray, and wrap that array as a named field inside an object. The end result will look more or less like this:
{"data": [{"id":"1"},{"id":"2"},{"id":"3"}]}
Code for the inner objects is the same as above, but there's a new layer (the array) between the inner and outer object:
JSONArray middle = new JSONArray();
...
middle.add(inner1);
...
middle.add(inner2);
...
middle.add(inner3);
...
outer.put("data",middle);
Still not sure if that's what you actually want, but I think it's a first step towards a solution. That being said, I would recommend you to switch to a nicer JSON Java library than the one from json.org you are apparently using. Look here for some feedback on different libraries that are available, for my projects I've been using Jackson since quite some time now and I'm very happy with it, but the SO question I linked to talks about several other, excellent alternatives.
You should write both objects, as below:
write.write(vjo.toString());
write.newLine();
write.write(conb.toString());
write.newline();
write.flush();
write.close();

Java JSONArray from Javascript JSONArray

I am passing a json object from javascript to a java servlet using ajax.
var jsonObj = JSON.stringify(objArray); //Then I pass it to Java using ajax.
In my Java I am getting the json string from the request, then creating a jsonarray, then looping through that array and i'm getting errors when trying to pull one of the json objects from the array.
String dataObj = request.getParameter("obj");
String sql = request.getParameter("sql");
ArrayList<Object> returnArray = new ArrayList<Object>();
int key;
//Get type of object being passed.
JSONArray jsonArray = JSONArray.fromObject(dataObj);
for(int i=0; i<jsonArray.size(); i++) {
String obj = new Gson().toJson(jsonArray.getJSONObject(i)); //This is where i'm getting an error
String className = getClassName(jsonArray.getJSONObject(i));
Class targetClass = null;
try {
targetClass = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//Create Object
Object data = new Gson().fromJson(obj, targetClass);
I'm posting the relevant code, the for loop isn't closed because the rest of the code is quite long, and this is the part where i'm getting the error.
net.sf.json.JSONException: JSONArray[0] is not a JSONObject.
Here is what the json array looks like when its passed in from javascript. This is a println of the jsonArray object.
[{"number":"(123) 456-7050","type":"Home","contactId":1,"id":16662,"className":"beans.PhoneNumber","position":0}]
With one object in it, this code works. But as soon as I get 2 or more, my error comes up.
[[{"number":"(123) 456-7050","type":"Home","contactId":1,"id":16662,"className":"beans.PhoneNumber","position":1},{"number":"(555) 555-1233","type":"Mobile","contactId":1,"id":16656,"className":"beans.PhoneNumber","position":0},{"number":"(999) 999-9999","type":"Home","contactId":1,"id":16664,"className":"beans.PhoneNumber","position":3},{"number":"(222) 222-2222","type":"Home","contactId":1,"id":16666,"className":"beans.PhoneNumber","position":4}]]
It almost looks like when i'm passing more than one object, it create an array of an array, which could be why its not working. But how do I avoid doing that when i'm passing a jsonarray from javascript? Using just the dataObj I have no access to size or get to loop through it.
[
[
{
"number":"(123) 456-7050","type":"Home",
"contactId":1,
"id":16662,
"className":"beans.PhoneNumber",
"position":1
},
{
"number":"(555) 555-1233",
"type":"Mobile",
"contactId":1,
"id":16656,
"className":"beans.PhoneNumber",
"position":0
},
{
"number":"(999) 999-9999",
"type":"Home",
"contactId":1,
"id":16664,
"className":"beans.PhoneNumber",
"position":3
},
{
"number":"(222) 222-2222",
"type":"Home",
"contactId":1,
"id":16666,
"className":"beans.PhoneNumber",
"position":4
}
]
]
This is not an array of objects. This is an array of arrays of objects. According to your description, you are expecting something like the following to be fed to your Java:
[{"foo":"bar"}, {"bar":"baz"}]
But you are really trying to parse:
[[{"foo":"bar"}, {"bar":"baz"}]]
I am not completely sure, because you have not shared the json that you are trying to parse, but the most probable error you have is just what it says: the first element of the array is not JSONObject. Note that string values, lons and booleans are not JSONObjects. I would suggest you to use the more genereal JSONArray.get and check instance of what class it is. Maybe this can head you to the problem with the json you have. If I got it completely wrong - write back and I will try to help. In such a case it will be still useful to share the results of the proposed experiment.
EDIT:
This is double array -> maybe you using getJSONArray(int index) will help you. as the other answer mentioned - this is array of arrays. Also consider changing the javascript to reduce the level of arrays included.

Can't parse JSON property "null"

I faced with one trouble when tried to parse JSON "null" property, please help me to understand what's the real problem. I had a following JSON:
{
"properties" : {
"null" : {
"value" : false
}
}
}
I used http://jsonlint.com to validate that this JSON is valid. I tried to parse it from java:
import net.sf.json.JSONObject;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
String st = "{" +
" 'properties' : {" +
" 'null' : {" +
" 'value' : false" +
" }" +
" }" +
"}";
JSONObject.fromObject(st);
}
}
But got the exception:
Exception in thread "main" java.lang.ClassCastException: JSON keys must be strings.
at net.sf.json.JSONObject._fromJSONObject(JSONObject.java:927)
at net.sf.json.JSONObject.fromObject(JSONObject.java:155)
at net.sf.json.JSONSerializer.toJSON(JSONSerializer.java:108)
at net.sf.json.AbstractJSON._processValue(AbstractJSON.java:238)
at net.sf.json.JSONObject._processValue(JSONObject.java:2655)
at net.sf.json.JSONObject.processValue(JSONObject.java:2721)
at net.sf.json.JSONObject.element(JSONObject.java:1786)
at net.sf.json.JSONObject._fromJSONTokener(JSONObject.java:1036)
at net.sf.json.JSONObject._fromString(JSONObject.java:1201)
at net.sf.json.JSONObject.fromObject(JSONObject.java:165)
at net.sf.json.JSONObject.fromObject(JSONObject.java:134)
I used json-lib-2.4-jdk15.jar from http://json-lib.sourceforge.net to parse it. Could anybody please clarify this? Why this library throws exception, but online validator said that it's valid JSON? It is a bug in the library or I made something wrong?
JSON-lib initially parses and populates a Java Map with the input JSON. Unfortunately, JSON-lib then checks whether every JSON object element name is a JSON null. It's null check is performed in the JSONNull.equals(Object) method. This method returns true for a "null" JSON string, which of course is not actually a JSON null value.
I recommend filing a bug with the JSON-lib project for this issue. The implementation of JSONNull.equals(Object) is flawed.
Unfortunately, it's not possible to handle this with a custom PropertyNameProcessor.
Options available for a more immediate solution include altering the JSON-lib code yourself, or switching libraries.
If you can switch libraries, I highly recommend Jackson. Following is an example of using it to deserialize the example JSON in the original question.
/*
{
"properties" : {
"null" : {
"value" : false
}
}
}
*/
String json = "{\"properties\":{\"null\":{\"value\":false}}}";
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.readValue(json, Map.class);
System.out.println(map);
// output: {properties={null={value=false}}}
Map<String, Object> propertiesMap = (Map) map.get("properties");
System.out.println(propertiesMap);
// output: {null={value=false}}
Map<String, Object> nullMap = (Map) propertiesMap.get("null");
System.out.println(nullMap);
// output: {value=false}
The first JSON posted is valid JSON: the JSON in the Java, however, is not valid -- only " is valid for the [required] key quote. From json.org:
A string is a sequence of zero or more Unicode characters, wrapped in double quotes, using backslash escapes....
However, that sounds like a bug, assuming it was not triggered by the invalid JSON fed to it (the library can do whatever it wants with invalid JSON)... one would have to look at the source (or bug reports / user experience) to say conclusively if this is indeed a "bug". I have added some suggestions of things to try below which may either show expected behavior or outline the cause/issue in further detail.
Consider this minimal test-case (with valid JSON):
String st = "{ \"null\": \"hello world!\" }";
This may also shed more light, depending on if the first item is "null" or null when extracted:
String st = "[ \"null\" ]";
Happy coding.
The gson library link is:
http://code.google.com/p/google-gson/
I normally usr gson to generate the josn string,so I found some example someone else posted in stackoverflow to parse json string with gson,see the link:
Converting JSON to Java
suggest you to use Gson,
and construct the json string using java Map and List,
then use Gson to output the Map or List object

Categories