How to fix 'JsonNull cannot be cast to JsonObject' - java

I call a post API which responds with details on specific addresses, however some of the responses that get returned have no data so they'll be returned as null. How do I stop the casting error in my code?
I currently only get the data as a Json Object and I'm not sure how to rework my code that so when a JsonNull Element gets returned I can handle that data.
JsonElement element = new JsonParser().parse(jsonString);
JsonObject jsonObject = element.getAsJsonObject();
jsonObject = jsonObject.getAsJsonObject("response"); // This is either an object or it is null
String buildName = jsonObject.get("buildingName").getAsString();
String buildNum = jsonObject.get("premisesNumber").getAsString();
String streetName = jsonObject.get("streetName").getAsString();
What I expect to be returned would be either the address details for valid addresses or no information at all for the invalid addresses.
The error that gets produced is this:
java.lang.ClassCastException: com.google.gson.JsonNull cannot be cast to com.google.gson.JsonObject

Before getAsString() check for isJsonNull(). It'll return true if object is Null.
You can rewrite your code as below
String buildName= (jsonObject.get("buildingName").isJsonNull ? null : jsonObject.get("buildingName").getAsString());

Normally is a good idea validate the data is JSON valid
public static boolean isJSONValid(String test) {
try {
new JSONObject(test);
} catch (JSONException ex) {
try {
new JSONArray(test);
} catch (JSONException ex1) {
return false;
}
}
return true;
}
Function above will return you true in case the string is a valid JSON object(could be an object or an array of objects).
After that you can continue parsing using Jackson lib or the GSON lib

Related

Iterate all json object and replace values

I have following JSON:
{
"data":{
"attributes":{
"external-event-url":"http://example.com",
"is-sponsors-enabled":"true",
"is-ticketing-enabled":"true",
"timezone":"UTC",
"name":"${name_variable}",
"ends-at":"2020-01-02T23:59:59.123456+00:00",
"starts-at":"2020-01-01T23:59:59.123456+00:00"
},
"type":"event"
}
}
I have to iterate through json objects and replace the value of variable starts with ${ e.g. ${name_variable}
and new json should be in same format(with replace value of variable mentioned ${})
How do i iterate such complex Json object and replace the values in variables
I've tried below code but not working as expected:
public Map<String, String> mapfillData(String jsonstr) {
Map<String, String> map = new HashMap<String, String>();
try {
JSONObject jsonObject = new JSONObject(jsonstr);
String[] keys = JSONObject.getNames(jsonObject);
for (String key : keys) {
try {
if (jsonObject.get(key).toString().startsWith("${")) {
map.put(key, System.getProperty(jsonObject.get(key).toString()
.replace("${", "").replace("}", "")));
} else {
if(isJSONValid(jsonObject.get(key).toString())){
mapfillData(jsonObject.get(key).toString());
}else{
map.put(key, jsonObject.get(key).toString());
}
}
} catch (Exception e) {
}
}
} catch (JSONException e) {
System.err.printf(jsonstr + " is not valid Json", e);
}
return map;
}
To check whether its a valid JSON Object
public boolean isJSONValid(String test) {
try {
new JSONObject(test);
} catch (JSONException ex) {
// edited, to include #Arthur's comment
// e.g. in case JSONArray is valid as well...
try {
new JSONArray(test);
} catch (JSONException ex1) {
return false;
}
}
return true;
}
Your problem is that while you are trying to recursively process the JSON, at each level of recursion, you're processing a different JSON document and writing data into a different Map.
Your function takes a string and then parses it into a JSONObject. You create a Map to hold some data. The first time through mapfillData, you're only going to find one key, data. Then, assuming that your if logic works correctly (I didn't try to run it), you're going to render the contents of data into another string and recursively call mapfillData.
Now you're in the second call to mapfillData, and you create another Map. This time through you find attributes and call mapfillData a third time. In this third invocation, you find some variables and replace them when writing the values to Map. At the end of the function, you return the Map, but the caller (the second invocation of mapfillData) doesn't do anything with the returned Map, and all your data is lost.
I would:
Parse the JSON once, then recurse through the JSONObject structure. In other words, the recursive function should take JSONObject.
Just replace the JSON elements in-place.
Or, if you want to flatten the elements and collect them into a Map, then instantiate the Map up-front and pass it into the recursive function.
To convert more easily, you can use the Jackson lib to do the hard stuff:
ObjectMapper mapper = new ObjectMapper();
String jsonString = "{
"data":{
"attributes":{
"external-event-url":"http://example.com",
"is-sponsors-enabled":"true",
"is-ticketing-enabled":"true",
"timezone":"UTC",
"name":"${name_variable}",
"ends-at":"2020-01-02T23:59:59.123456+00:00",
"starts-at":"2020-01-01T23:59:59.123456+00:00"
},
"type":"event"
}
}";
// considering JSONObject matches the Json object structure
JSONObject jsonObject = mapper.readValue(jsonString , JSONObject.class);
Then a little bit of reflection to handle any JSON object fields dynamically:
// with parsed JSON to Object in hands
Class<?> clazz = jsonObject.getClass();
for(Field field : clazz.getDeclaredFields()) {
if(!field.getType().getName().equals("String"))
break;
field.setAccessible(true);
String fieldValue = field.getValue().toString();
if(fieldValue.startsWith("${"))
field.set(jsonObject, fieldValue.replace("${", "").replace("}", ""));
else
// desired treatment
}

Java - a better way to ignore invalid records when parsing JSON

I know that it's a bad practice to use Exceptions for flow control. But I faced the following situation: I need to parse JSON file, and if there are corrupted values for the key of a record I want to just log it and continue to parse another object from jsonArray. And even if the value is null I want to ignore it and go on.
So in my current implementation I use a try/catch block with continue. What would be a more correct approach here?
Here is how I've implemented it:
public static void parseMetrics(JSONParser parser, File jsonFile,
String metricKey, List<String> metricsList) throws IOException, ParseException {
JSONArray jsonArray = (JSONArray) parser.parse(new InputStreamReader(new FileInputStream(jsonFile)));
for (Object obj : jsonArray) {
try {
JSONObject jsonObject = (JSONObject) obj;
String metricValue = (String) jsonObject.get(metricKey);
Long metricDate = parseDate(jsonObject);
metricsList.add(new Metric(metricValue, metricDate));
} catch (java.text.ParseException e) {
continue;
log.error("Error when parsing JSON", e);
}
}
}
Actually you want to log with the error level the parsing problem.
So throwing a exception makes sense.
If the parsing error is an abnormal situation you should keep your way but just without the continue that is not convenient here :
for (Object obj : jsonArray) {
try {
JSONObject jsonObject = (JSONObject) obj;
String metricValue = (String) jsonObject.get(metricKey);
Long metricDate = parseDate(jsonObject);
metricsList.add(new Metric(metricValue, metricDate));
} catch (java.text.ParseException e) {
log.error("Error when parsing JSON", e);
}
}
But if you consider that the parsing problem is not an issue to log but a normal scenario that may happen, indeed you don't have to propagate the exception from parseDate() but you could return something like OptionalLong instead of Long.
It would give from the client side :
for (Object obj : jsonArray) {
JSONObject jsonObject = (JSONObject) obj;
String metricValue = (String) jsonObject.get(metricKey);
OptionalLong metricDate = parseDate(jsonObject);
metricDate.ifPresent(d -> metricsList.add(new Metric(metricValue, d));
}
You could also add a log in debug or info level if it makes sense.

How to check if a key exists in Json Object and get its value [duplicate]

This question already has answers here:
How to check if a JSON key exists?
(13 answers)
Closed 5 years ago.
Let say this is my JSON Object
{
"LabelData": {
"slogan": "AWAKEN YOUR SENSES",
"jobsearch": "JOB SEARCH",
"contact": "CONTACT",
"video": "ENCHANTING BEACHSCAPES",
"createprofile": "CREATE PROFILE"
}
}
I need to know that either 'video` exists or not in this Object, and if it exists i need to get the value of this key. I have tried following, but i am unable to get value of this key.
containerObject= new JSONObject(container);
if(containerObject.hasKey("video")){
//get Value of video
}
Use below code to find key is exist or not in JsonObject. has("key") method is used to find keys in JsonObject.
containerObject = new JSONObject(container);
//has method
if (containerObject.has("video")) {
//get Value of video
String video = containerObject.optString("video");
}
If you are using optString("key") method to get String value then don't worry about keys are existing or not in the JsonObject.
Use:
if (containerObject.has("video")) {
//get value of video
}
From the structure of your source Object, I would try:
containerObject= new JSONObject(container);
if(containerObject.has("LabelData")){
JSONObject innerObject = containerObject.getJSONObject("LabelData");
if(innerObject.has("video")){
//Do with video
}
}
Please try this one..
JSONObject jsonObject= null;
try {
jsonObject = new JSONObject("result........");
String labelDataString=jsonObject.getString("LabelData");
JSONObject labelDataJson= null;
labelDataJson= new JSONObject(labelDataString);
if(labelDataJson.has("video")&&labelDataJson.getString("video")!=null){
String video=labelDataJson.getString("video");
}
} catch (JSONException e) {
e.printStackTrace();
}
containerObject = new JSONObject(container);
if (containerObject.has("video")) {
//get Value of video
}
Try
private boolean hasKey(JSONObject jsonObject, String key) {
return jsonObject != null && jsonObject.has(key);
}
try {
JSONObject jsonObject = new JSONObject(yourJson);
if (hasKey(jsonObject, "labelData")) {
JSONObject labelDataJson = jsonObject.getJSONObject("LabelData");
if (hasKey(labelDataJson, "video")) {
String video = labelDataJson.getString("video");
}
}
} catch (JSONException e) {
}
JSONObject class has a method named "has".
Returns true if this object has a mapping for name. The mapping may be NULL.
http://developer.android.com/reference/org/json/JSONObject.html#has(java.lang.String)
JSONObject root= new JSONObject();
JSONObject container= root.getJSONObject("LabelData");
try{
//if key will not be available put it in the try catch block your program
will work without error
String Video=container.getString("video");
}
catch(JsonException e){
if key will not be there then this block will execute
}
if(video!=null || !video.isEmpty){
//get Value of video
}else{
//other vise leave it
}
i think this might help you

unhandled exception org.json.jsonexception

I'm working on an android app, and the app must save a java object in json format into the SQLite database. I wrote the code for this operation, then they must extract the Json object and reconvert it into a Java Object.
When I try to call the method for deserializing the json object in to a string, I found this error in Android Studio:unhandled exception org.json.jsonexception
When I try to catch JSONException e the program runs but don't deserialize the json object.
This is the code for the method:
private void read() throws JSONException {
SQLiteDatabase db = mMioDbHelper.getWritableDatabase();
String[] columns = {"StringaAll"};
Cursor c = db.query("Alle", columns, null, null, null, null,null );
while(c.moveToNext()) {
String stringaRis = c.getString(0);
JSONObject jObj = new JSONObject(stringaRis);
String sPassoMed = jObj.getString("passoMed");
final TextView tView = (TextView) this.findViewById(R.id.mainProvaQuery);
tView.setText(sPassoMed);
// }
}
}
Can you help me please?
Yes, you need to catch the exception.
But when you catch it, you should not just throw it on the floor. Your application needs to do something about the exception. Or if you / it is not expecting an exception to occur at runtime, then at least you should report it. Here's a minimal example (for an Android app)
try {
...
JSONObject jObj = new JSONObject(stringaRis);
...
} catch (JSONException e) {
Log.e("MYAPP", "unexpected JSON exception", e);
// Do something to recover ... or kill the app.
}
Of course, this does not solve your problem. The next thing you need to do is to figure out why you are getting the exception. Start by reading the exception message that you have logged to logcat.
Re this exception message:
org.json.JSONException: Value A of type java.lang.String cannot be converted to JSONObject
I assume it is thrown by this line:
JSONObject jObj = new JSONObject(stringaRis);
I think that it is telling you is that stringaRis has the value "A" ... and that cannot be parsed as a JSON object. It isn't JSON at all.

Issue with JSON parser for android, which works well for java

I have the following json parsing code which works fine when tested as a java application. But on using it with in an android platform and running , returned the following error
"Unexpected token END OF FILE at position 0"
Here is my code
public boolean parseJSON(String content) {
boolean retvalue=false;
String jsonString=null;
JSONParser parser=new JSONParser();
Object obj;
try {
System.out.println("in the parse json");
obj = parser.parse(content);
JSONArray array=(JSONArray)obj;
JSONObject obj2=(JSONObject)array.get(0);
jsonString=(String) obj2.get("user_id");
System.out.println("in the parse json "+jsonString);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (null != jsonString) {
retvalue = true;
}
return retvalue;
}
The input string for the method is the following
[{"user_id":"1","username":"arvind","password":"somu","firstname":"Arvind somu","accountNumber":"1234567","lastname":"","address":"","email":"sample#gmail.com"}]
I have got the value 1 printed, when tried with java, but no idea why this issue is coming with android. Can body suggest what is wrong with the code.The parser I am using is json-simple1.1.1
Use this:
JSONObject obj2;
obj2 = array.optJSONObject(0);
The method optJSONObject returns a JSONObject and you dont have to cast it, where as get() returns an Object. Try this i think this may solve it.

Categories

Resources