OkHttp - Get failed response body - java

The API for an app I'm currently working on uses JSON as a main way of communicating data - including error messages in failed response scenario (response code != 2xx).
I'm migrating my project to use Square's OkHttp networking library. But am having difficulties to parse said error messages. For OkHttp's response.body().string(), apparently, only returns request code "explanation" (Bad Request, Forbidden, etc) instead of the "real" body content (in my case: a JSON describing the error).
How to get the real response body instead? Is this even possible when using OkHttp?
As an illustration, here's my method for parsing JSON response:
private JSONObject parseResponseOrThrow(Response response) throws IOException, ApiException {
try {
// In error scenarios, this would just be "Bad Request"
// rather than an actual JSON.
String string = response.body().toString();
JSONObject jsonObject = new JSONObject(response.body().toString());
// If the response JSON has "error" in it, then this is an error message..
if (jsonObject.has("error")) {
String errorMessage = jsonObject.get("error_description").toString();
throw new ApiException(errorMessage);
// Else, this is a valid response object. Return it.
} else {
return jsonObject;
}
} catch (JSONException e) {
throw new IOException("Error parsing JSON from response.");
}
}

I feel dumb. I know now why above code won't work:
// These..
String string = response.body().toString();
JSONObject jsonObject = new JSONObject(response.body().toString());
// Should've been these..
String string = response.body().string();
JSONObject jsonObject = new JSONObject(response.body().string());
TL;DR It should've been string() and not toString().

Related

How to remove this error -> Json parsing error: Value success at response of type java.lang.String can't be converted to JSONArray

I'm getting JSON parsing error while running my app
Below mentioned the code where I'm facing the error and the json url https://zactra.com/blackboard/teacher/auth/email/check/numankhan2754#gmail.com
MyHttpHandler myhttp = new MyHttpHandler();
String Newurl = url + "auth/email/check/"+email+"/";
// call MyServiceCall method from Myhttphandler class
String jsonstng = myhttp.MyServiceCall(Newurl);
Log.e(TAG, "Response From URL: " + jsonstng);
if (jsonstng != null) {
try {
JSONObject jsonObject = new JSONObject(jsonstng);
//getting JSON array node
JSONArray jsonArray = jsonObject.getJSONArray("response");
// Looping through all data from json
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject loopjsonObject = jsonArray.getJSONObject(i);
myid = loopjsonObject.getString("response");
// tmp hash map for single contact
HashMap<String, String> mydata = new HashMap<>();
// adding each child node to HashMap key => value
mydata.put("response", myid);
mydatalist.add(mydata);
}
} catch (final JSONException e) {
Log.e(TAG, "Json parsing error: " + e.getMessage());
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(StartMainActivity.this, "JSON parsing error", Toast.LENGTH_SHORT).show();
}
});
}
} else {
Log.e(TAG, "Couldn't get json from server.");
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(StartMainActivity.this, "Couldn't get json from server. Check LogCat for possible errors!", Toast.LENGTH_SHORT).show();
}
});
}
Response From URL: {"response":"success"}
Json parsing error: Value success at response of type java.lang.String cannot be converted to JSONArray
{"response":"success"} is a JSONObject but you are treating it as JSONArray.
JSON array is always wrapped with []
Example : ["a", "b", "c"] OR something like array of JSONObjects . For example : [{"key":"value"}, {"key","value"}] . Many combinations are possible but most importantly it should start with []
Well
'success'
is not a json array.
an example of a json array is the following
"cars":[ "Ford", "BMW", "Fiat" ]
that is why it cannot be parsed.
the upper example 'cars' array has String values. so String Objects.
In your example you have after the jsonArray a for loop for the jsonArray
for (int i = 0; i < jsonArray.length(); i++)
there you say that you expect JSONObject
so the format that you are waiting is
{"response":[ {"response":"success"},{"response":"success"},{"response":"success"} ]}
which i believe is not the one you finally want :P.
You also create a new HashMap<>() inside the loop. (read about HashMap because your implementation does not support the same key usage ex. cannot have a hashmap with two string objects with same key 'response')
do not make only checks for null checks, do also checks if the string is blank.
First, define the correct format of the response from your service, then the correct implementation for you to capture your data and search the web so that the response to be parsed to an object by the use of a library like jackson.
Regards!
Ps if you want to handle this response,
then
String jsonstng = "{\"response\":\"success\"}";//your service response
String responseValue = "fail";
if (jsonstng != null) {
try {
JSONObject jsonObject = new JSONObject(jsonstng);
if (jsonObject.length() > 0 && jsonObject.has("response")) {
responseValue = jsonObject.getString("response");
}
} catch (final JSONException e) {
//log and handle error
}
}
System.out.println(responseValue);
may be enough

How to fix 'JsonNull cannot be cast to JsonObject'

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

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.

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