I have a struts action receiving following JSON:
{
"commandId":"tC",
"id":"123",
"def":""
}
Following code works just fine:
JSONObject command = null;
String commandId = null;
String deviceId = null;
try {
command = new JSONObject(json);
commandId = command.getString("commandId");
}
Since "def" can be empty, non declared or can contain another array of elements I tried doing this:
JSONObject def = command.getJSONObject("def");
in order to get this JSON object defined in the element def
This only works if def isn't empty like in this example:
{
"commandId":"tC",
"id":"123",
"def":{"1":"aaa", "2":"bbb"}
}
When def is empty or not defined my program stops working on the line JSONObject def = command.getJSONObject("def"); and noticed that it doesn't continue the execution?!
If I put JSONObject def = command.getJSONObject("def"); try / catch block I get _JSONObject["def"] is not a JSONObject _ exception, but execution doesn't continue
How does JSONObject.getJsonObject(String) behave?
I would expect it to return an empty JSONObject and continue the execution.
What I want is to check if there is anything defined in def and then in a if, else decide what to do in my program according to the value found there... I can't find a way to make my program work if a client's json comes with def empty or not defined.
my suggestion is to define "def" either be defined as null or {}:
"def":null or "def":{} to align with its usage agreement
quotes is really just used to indicate the value is a string. following the standard might save you and others from confusion in the future.
Likely it is because it is trying to get a Object and finding a string. In your JSON (if you control it), for an empty object I would do {}. This should allow Java to think it is retrieving an object.
If def is intended to be an object is it not suppose to look like this when empty?
{
"commandId":"tC",
"id":"123",
"def":{}
}
I think having "def":"" will cause the value to be attempted to be parsed as a string value and not an object value.
Maybe this will help someone. I had to solve the same problem. In my case the web service was returning empty JSON objects if it couldn't find the requested record.
Note: the data names have been changed to protect the innocent...
Note 2: this example uses javax.json
import javax.json.*;
JsonObject _jObj = _myRootObj.getJsonObject("someDataNode");
// at this point in execution _jObj could equal {"DataReturn":""}
// or {"DataReturn":"<some valid data>"}
// we want to test the existence of DataReturn before trying to
// use it
JsonValue jv = _jObj.getOrDefault("DataReturn", null);
String js = jv.toString();
// cover all the bases. test the value
if (js == null || js.isEmpty() || js.compareTo("\"\"") == 0)
{
throw new Exception("Error: DataReturn object null. Cannot proceed.");
}
// the object exists, so it's ok to get it
JsonObject jObjDate = _jObj.getJsonObject("DataReturn");
If you're using org.json.JSONObject you can use .isNull(String key) to do this, something like:
if (command.isNull("def") {
// Handle 'def' not being there
} else {
JSONObject def = command.getJSONObject("def");
}
Related
I am using Kotlin in a webserver app and I have a line of code as follows:
.onComplete { jsonResult: AsyncResult<JsonObject>? ->
Now what I want to do is change the underlying JsonObject wrapped in the AsyncResult, so that it is going to be reflected further downstream.
var res: JsonObject? = jsonResult?.result()
if (res != null) {
if (res.getInteger("files_uploaded") > 0) {
res.put("URL", "Some URL")
}
}
I was then imagining to update the underlying JSON object in the result but not sure how to do that.
please take note that single quotes are missing and ` appear as \` because the code formatting. I tried to leave what seemed least confusing...
You should be able to make changes in the conditional statement
if (res !=null) {
res being the JsonObject:
console.log(res);
would show you what's in there. You may need to use
let resXmodifiedX = JSON.parse(res);
One approach is to write a function and pass res to that function which you can do if it is in the console.log(res).
Some notes on what's below:
place the function somewhere consistent maybe at the bottom of the file...
objects often have multiple levels res.person.name, res.contact.email, or whatever...
use multiple for loops:
let level = res[key]; for(child in level) {
you don't need to do this if you know exactly what object attributes you need to update.
you can set the value directly but you always want to test for it before trying to set it to avoid errors that stop execution.
let toBe = toBe =>`${toBe}`;
let update = (res)?toBe(update(res)):toBe('not Found');
This option is really only if you know for sure that data will be there and you can't proceed without it. Which is not uncommon but also not how JSON is designed to be used.
The code below is a concise way to make some simple changes but may not be an ideal solution. To use it xModify(res) replaces console.log(res) above.
function xModify(x) {
let resXmodifiedX = JSON.parse(x);
let res = resXmodifiedX;
for (key in res) {
res[key] = key=='name'? \`My change ${res[key]}\`: key=='other'? \`My Change ${res[key]}\`:res[key];
resXmodifiedX = JSON.stringify(res);
return resXmodifiedX;
}
That will update res.name and res.other otherwise res[key] is unchanged. If you do not need to parse res change let res = xModifiedx; to let res = x; remove the first line and change the last two lines to return res;
function xModify(x) {
let res = x;
for (key in res) {
res[key] = key=='name'? \`My change ${res[key]}\`: key=='other'? \`My Change ${res[key]}\`:res[key];
return res;
}
If your data is numeric which is not generally the case in a web server response scenario this is a terrible approach. Because it is probably a string I used the template variable as a way to easily add a complex pattern in place of a string. My change ${res[key]} not a real world example. Any valid JS code can go in the ${ } (template variable). I've been defaulting to the first pattern more and more.
let me = (bestCase)?`${'the best version'} of myself`:`${'someone'} I'm ok with`;
I'm processing deeply nested JSON data. Here is a shortened example:
{
"timestamp":"123",
"layers":{
"frame_raw":"123",
"frame":{
"frame_frame_interface_id":"0",
"frame_interface_id_frame_interface_name":"asd",
...
},
"eth_raw":"123",
"eth":{
"eth_eth_dst_raw":"asd",
"eth_eth_dst":"asd",
...
},
"ip_raw":"123",
"ip":{
"ip_ip_version_raw":"4",
"ip_ip_version":"4",
"ip_ip_addr_raw":[
"asd",
"asd"
],
"ip_ip_addr":[
"1.1.1.1",
"1.1.1.1"
],
"ip_ip_dst_host":"1.1.1.1"
}
...
}
...
}
I have a list of structures that I explicitly allow. All others should be deleted from the JSON. An example for the list:
###frame###
layers.frame_raw
###eth###
layers.eth.eth_eth_dst
layers.eth.eth_eth_src
###ip###
layers.ip.ip_ip_src
layers.ip.ip_ip_dst
layers.ip.ip_ip_src_host
layers.ip.ip_ip_dst_host
layers.ip.ip_ip_version
layers.ip.ip_ip_hdr_len
layers.ip.ip_ip_dsfield
My problem is that I can only navigate through the JSON structure using "getJSONObject(key)".
How can I generate the path of the lowest elements of my JSON structure in the form "key.key.key..." so that I can match it with my list?
JSON object has a method called .has which will return a boolean value. So the logic is like to check whether the JSON object exists. If so check the child node for more existence of your data. If there is an array you have to get the array and migrate through the array using any loop and do the same. For example:
if (json.has("ip")) {
JSONObject jsonObject = getJSONObject.getString("ip")
String ip_ip_version_raw = jsonObject.getString("ip_ip_version_raw"));
if (jsonObject.has("ip_ip_addr_raw")){
JSONArray ip_ip_addr_raw = jsonObject.getJSONArray("ip_ip_addr_raw");
for (String s : ip_ip_addr_raw) {
...
}
}
}
For reference :
http://developer.android.com/reference/org/json/JSONObject.html#has(java.lang.String)
If you want to check the existence of a property of a JSONObject there is a method called has. This is the link to the official documentation.
I found a solution because the structure in my special case is always layers.layer.property, so the depth of the structure is always the same and not variable.
For interested people:
for (Iterator<String> layersIterator = jsonObject.getJSONObject("layers").keys(); layersIterator.hasNext(); ) {
String layer = layersIterator.next();
for (Iterator<String> propertyIterator = jsonObject.getJSONObject("layers").getJSONObject(layer).keys(); propertyIterator.hasNext(); ) {
String property = propertyIterator.next();
System.out.println("layers."+layer+"."+property);
}
}
I've been writing a method to "flatten" a codehaus JSONObject in Java. Unfortunately, I'm seeing a StackOverflowError in the recursion through the object nests, but I'm finding it difficult to debug. Here is the error I'm seeing:
Exception in thread "main" java.lang.StackOverflowError
at java.util.LinkedHashMap$LinkedHashIterator.<init>(LinkedHashMap.java:345)
at java.util.LinkedHashMap$LinkedHashIterator.<init>(LinkedHashMap.java:345)
at java.util.LinkedHashMap$KeyIterator.<init>(LinkedHashMap.java:383)
at java.util.LinkedHashMap$KeyIterator.<init>(LinkedHashMap.java:383)
at java.util.LinkedHashMap.newKeyIterator(LinkedHashMap.java:396)
at java.util.HashMap$KeySet.iterator(HashMap.java:874)
at org.codehaus.jettison.json.JSONObject.keys(JSONObject.java:533)
at org.codehaus.jettison.json.JSONObject.toString(JSONObject.java:1079)
at org.codehaus.jettison.json.JSONObject.valueToString(JSONObject.java:1210)
I'm using Iterator to loop the keys, and using hasNext() and next() to ensure that I should only be able to access specific object keys.
I started testing with a simple JSONObject of:
JSONObject json = new JSONObject("outer":{"field1":"value","inner":{"field2":12345,"field3":"example#example.com"}});
/*
"outer":{
"field1":"value",
"inner":{
"field2":12345,
"field3":"example#example.com"
}
}
*/
This should result in a single nest containing fields1|2|3.
Here is the code I have so far:
private static JSONObject flatten(JSONObject object, JSONObject flattened){
if(flattened == null){
flattened = new JSONObject();
}
Iterator<?> keys = object.keys();
while(keys.hasNext()){
String key = (String)keys.next();
try {
if(object.get(key) instanceof JSONObject){
flattened.put(key, flatten(object.getJSONObject(key), flattened));
} else {
flattened.put(key, object.get(key));
}
} catch(JSONException e){
System.out.println(e);
}
}
return flattened;
}
I have been debugging this for a while now, but haven't been able to make any headway - so I'd appreciate any pointers with this. Thanks in advance for any help - if any more info is needed, just leave a comment.
Replace
flattened.put(key, flatten(object.getJSONObject(key), flattened));
by
flatten(object.getJSONObject(key), flattened);
Here it gives me {"field1":"value","field2":12345,"field3":"example#example.com"} and I think that's what you want
Notice that when you call the function recursively, you pass the "flattened" object into the function, and then it returns it back to you, which you then add to "flattened". Thus you are adding the object to itself, creating a circular reference
When you do the recursive call, don't add the result back into the object. Just do:
flatten(object.getJSONObject(key), flattened);
I have this:
String object = "";
try {
object = data.getString("url");
System.out.println("Url Object:" + object);
}
catch (JSONException e) {
e.printStackTrace();
}
System.out.println("object is:" + object);
if (object!= null ) {
// doSomething
} else {
// is Null
}
and although this is printed:
object is: null
The code enters the if condition and not the else.
What am I missing?
EDIT: where data is a JSONObject. I now want to test the case that url is null. Therefore, I know that data is null and I can see it printed.
Your code is an anti pattern. Move the code that processes 'string' inside the 'try' block. Don't just catch exceptions and then continue as though they didn't happen, and have to sort out again whether you're in a valid state. That's what the 'try' block is for. If you're still in it, you're in a valid state.
Please note that getString(..) is returning "null" (as a String, when ob.toString() do that). So when you assign it to object, it is a String: "null", not null.
To correct your code one way would be:
if (!object.equals("null")) {
// doSomething
} else {
// is Null
}
Another solution would be setting object to be null if getString() returns "null":
if (data.getString("url").equals("null"))
object = null;
Don't initialize your String object to "" if you want it to be null if the json parsing bits fail.
Change your top line to:
String object = null;
More to the point, check out https://stackoverflow.com/a/21246501/599075
The only explanation to your case is that the data.getString("url"); is returning a "null" String value.By the way I recommend you these points :
Initialize your object by a null reference (String object = null;)
Change the if condition (if(object!=null) && !object.isEmpty())
Otherwise, try to print entirely the content of the data object to the console so you can check the json content you are trying to parse.
(Sorry if I made some language mistakes)
I am getting a JSONObject from a webservice call.
JSONObject result = ...........
When i am accessing like result.getString("fieldName");
If the fieldName exist in that JSONObject then it is working fine.If that is not exist i am getting exception JSONObject["fieldName"] not found.
I can use try catch for this.But i have nearly 20 fields like this.Am i need to use 20 try catch blocks for this or is there any alternative for this.Thanks in advance...
There is a method JSONObject#has(key) meant for exactly this purpose. This way you can avoid the exception handling for each field.
if(result.has("fieldName")) {
// It exists, do your stuff
} else {
// It doesn't exist, do nothing
}
Also, you can use the JSONObject#isNull(str) method to check if it is null or not.
if(result.isNull("fieldName")) {
// It doesn't exist, do nothing
} else {
// It exists, do your stuff
}
You can also move the logic to a common method (for code reusability), where you can pass any JSONObject & the field name and the method will return if the field is present or not.
Assuming that you're using org.json.JSONObject, you can use JSONObject#optString(String key, String defaultValue) instead. It will return defaultValue, if key is absent:
String value = obj.optString(fieldName, defaultValueIfNull);
Way better solution is to use optString instead of getString.
String name = jsonObject.optString("fieldName");
// it will return an empty string ("") if the key you specify doesn't exist
Check if your JsonObject implementation contains method called "has". It could be checks if property exist in object.
Many JsonObject implementations contains this method.
I use this code to do so, it returns undefined or a specified defaultValue instead of rising exception
/* ex: getProperty(myObj,'aze.xyz',0) // return myObj.aze.xyz safely
* accepts array for property names:
* getProperty(myObj,['aze','xyz'],{value: null})
*/
function getProperty(obj, props, defaultValue) {
var res, isvoid = function(x){return typeof x === "undefined" || x === null;}
if(!isvoid(obj)){
if(isvoid(props)) props = [];
if(typeof props === "string") props = props.trim().split(".");
if(props.constructor === Array){
res = props.length>1 ? getProperty(obj[props.shift()],props,defaultValue) : obj[props[0]];
}
}
return typeof res === "undefined" ? defaultValue: res;
}