Get JSON string from Android JSONException - android-volley

My Volley request can come back as either JSONArray (valid) or JSONObject (error message) and in order to correctly display the error response, I want to parse the failed JSONArray string as JSONObject. It appears that JSONException objects wrap the original text. Is it possible to get just the failed text in order to parse it differently?
Example:
org.json.JSONException: Value {"error":"User has not signed up to be a customer"} of type org.json.JSONObject cannot be converted to JSONArray
and I want to get just the JSON string component because it's a valid JSONObject.

Because your response is either JSONArray (valid) or JSONObject (error message), so you can refer to the following code:
// Check the response if it is JSONObject or JSONArray
Object json = new JSONTokener(response).nextValue();
if (json instanceof JSONObject) {
// do something...
} else if (json instanceof JSONArray) {
// do something...
}
Hope it helps!

I don't think it's actually possible to retrieve just the JSON string from inside a JSONException so in the end I took the answer from BNK and did what is probably the easiest solution in this situation.
The trick seems to be to receive a StringRequest and do the JSON processing once you know there's a valid string response. Here's how that looks in my project.
StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
activity.hideProgress();
try {
Object json = new JSONTokener(response).nextValue();
if (json instanceof JSONArray) {
// an array is a valid result
dataModel.loadData((JSONArray)json);
} else if (json instanceof JSONObject) {
// this is an error
showErrorMessageIfFound((JSONObject)json);
}
} catch (JSONException error) {
error.printStackTrace();
}
refreshTable();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
activity.hideProgress();
showVolleyError(error);
// check for a JSONObject parse error
}
});
First there's a StringRequest to retrieve the response. The error response displays the error with my custom error processor. The success response parses the JSON and uses the end result to display the correct thing to the end user.

Related

Scatter & Gather using Spring Webclient

I am new to reactive programming concepts and trying to build one service that sends requests to a two backend service in parallel and combine those results.
Those two backend service has a different response structure and i have created a mapper method to convert all that into a common Response structure.
This is what i have right now and it is working when both the services return results.
public Mono<List<Response>> getRecords(String input){
List<Response> response = new ArrayList<>();
Mono<FirstApiResponse> gResp = this.firstWebClient.get().uri(uriBuilder -> uriBuilder
.path("/")
.queryParam("q", input)
.build()).retrieve()
.bodyToMono(FirstApiResponse.class).log()
.timeout(Duration.ofSeconds(50L));
Mono<SecondApiResponse> iResp = this.secondWebClient.get().uri(uriBuilder -> uriBuilder
.path("/search")
.queryParam("term", input)
.build()).retrieve()
.bodyToMono(SecondApiResponse.class).log().timeout(Duration.ofSeconds(50L));
return Mono.zip(firstResp,secResp).map(objects ->{
if(firstResp != null)
response.addAll(Mapper.convert(objects.getT1()));
if(secResp != null);
response.addAll(Mapper.convert(objects.getT2()));
return response;
});
}
public List<Response> convert(FirstApiResponse resp){
////
Mapping to Response object
////
return response;
}
public List<Response> convert(SecondApiResponse resp){
////
Mapping to Response object
////
return response;
}
I don't know if this is the right way to do it. Moreover, i want to make it in such a way that if there is any errors from any of this service, then it should still return the results from the other service. Right now it throws the exception and I am not able to figure out how to handle it properly
How to handle these errors in a proper way ?
This is a pretty valid scenario and there are many ways to handle it. One crude way would be to use onErrorReturn a new Model which you can handle. It could be either an empty response or a wrapper around your model whichever seems fit for your scenario.
Mono<Wrapper<FirstApiResponse>> gResp = this.firstWebClient.get().uri(uriBuilder -> uriBuilder
.path("/")
.queryParam("q", input)
.build()).retrieve()
.bodyToMono(FirstApiResponse.class).log()
.map( response -> new Wrapper().withResponse(response))
.timeout(Duration.ofSeconds(50L))
.doOnError(throwable -> logger.error("Failed", throwable))
.onErrorReturn(new Wrapper().withError( YourDefaultErrorReponse(...));
Mono<SecondApiResponse> iResp = this.secondWebClient.get().uri(uriBuilder -> uriBuilder
.path("/search")
.queryParam("term", input)
.build())
.retrieve()
.bodyToMono(SecondApiResponse.class).log()
.map( response -> new Wrapper().withResponse(response))
.timeout(Duration.ofSeconds(50L))
..doOnError(throwable -> logger.error("Failed", throwable))
.onErrorReturn(new Wrapper().withError( YourDefaultErrorReponse(...))
Again there are ways to return a default response. A simple one would be to use something like a wrapper
public final class Wrapper<T> {
private T response ;
private Error error;
public Wrapper<T> withResponse ( T response ){
this.response = response;
return this;
}
public Wrapper<T> withError( Error error) {
this.error = error;
return this;
}
public Boolean hasError(){
return error != null ;
}
public T getResponse(){
return response;
}
}

Uncaught SystaxError while sending JSONArray converted to String as parameter in Parse Cloud Function

TL:DR; How do I send JSONArray as parameter in Parse Cloud Functions?
I'm requesting a Parse Cloud Function. Whenever I try to convert JSONArray to String and send as params, I get this exception
Uncaught SyntaxError: Unexpected token u in <unknown file>:1
Below is my code, this is the same as given in sample code in Parse Guide:
// create a JSONObject
JSONObject singleJsonObj= new JSONObject();
singleJsonObj.put("time", "2017-01-01T06:00:00Z");
singleJsonObj.put("title", "Adib");
singleJsonObj.put("profile", "AbCdIj76");
// add JSONObject to JSONArray
JSONArray jsonArray = new JSONArray();
jsonArray.put(singleJsonObj);
// put as parameter
HashMap<String, Object> params = new HashMap<>();
params.put("form", formId);
params.put("records", jsonArray.toString());
ParseCloud.callFunctionInBackground("someFunctionName", params, new FunctionCallback<Float>() {
#Override
public void done(Float object, ParseException e) {
if (e == null) {
// Yay!
} else {
// Damn!!
}
}
});
If I don't send it as String, it shows another error as InvalidArgumentException: Invalid type for ParseObject: JSONArray. I haven't found any official documentation on how to send JSONArray as parameter in Parse Cloud Function.
There are multiple overloaded version of callFunctionInBackground. If its a cloud function you should use this one: https://github.com/ParsePlatform/Parse-SDK-Android/blob/master/Parse/src/main/java/com/parse/ParseCloud.java#L17
And define the callback as: new FunctionCallback()
Hope it helps.

How to post a file along with parameter to webapi method?

I am new to ASP.NET Web API. I have a sample FileUpload web api (from some site) to upload files to the server.
Following works fine for uploading a file.
public async Task<HttpResponseMessage> FileUpload()
{
// Check whether the POST operation is MultiPart?
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
// Prepare CustomMultipartFormDataStreamProvider in which our multipart form
// data will be loaded.
//string fileSaveLocation = HttpContext.Current.Server.MapPath("~/App_Data");
string fileSaveLocation = HttpContext.Current.Server.MapPath("~/UploadedFiles");
CustomMultipartFormDataStreamProvider provider = new CustomMultipartFormDataStreamProvider(fileSaveLocation);
List<string> files = new List<string>();
try
{
// Read all contents of multipart message into CustomMultipartFormDataStreamProvider.
await Request.Content.ReadAsMultipartAsync(provider);
foreach (MultipartFileData file in provider.FileData)
{
files.Add(Path.GetFileName(file.LocalFileName));
}
// Send OK Response along with saved file names to the client.
return Request.CreateResponse(HttpStatusCode.OK, files);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
// We implement MultipartFormDataStreamProvider to override the filename of File which
// will be stored on server, or else the default name will be of the format like Body-
// Part_{GUID}. In the following implementation we simply get the FileName from
// ContentDisposition Header of the Request Body.
public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public CustomMultipartFormDataStreamProvider(string path) : base(path) { }
public override string GetLocalFileName(HttpContentHeaders headers)
{
return headers.ContentDisposition.FileName.Replace("\"", string.Empty);
}
}
But, I want to send a parameter called as 'token' of type string to the following method using [FromBody] is it possible?
Required:
public async Task<HttpResponseMessage> FileUpload([FromBody] string token)
{
//somecode here
}
So, basically can we send multiple Content-Type data to the web api? Please suggest. I am using Fiddler for testing webapi.
Eg:
Request Body(json):
{"token":"FV00VYAP"}
You can pass extra content in through query string and then read it from your CustomMultipartFormDataStreamProvider.
// Read all contents of multipart message into CustomMultipartFormDataStreamProvider.
await Request.Content.ReadAsMultipartAsync(provider);
Then you can use provider.FormData to read the extra values you passed along.
// Show all the key-value pairs.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
Trace.WriteLine(string.Format("{0}: {1}", key, val));
}
}
See http://www.asp.net/web-api/overview/advanced/sending-html-form-data,-part-2 for more details.

How do I download a file from a Byte[] array in a Web Api2 method that returns IHttpActionResult?

Below is the method I've got in my ApiController class.
The _fileContents dictionary is populated in another WebApi2 method BuildContent(params).
When the user makes an ajax call to the BuildContent(params) method, the method builds
the string end of the dictionary, which contains full HTML content including a table tag and passes back a the Guid, end of the dictionary. The javascript in turn does the following:
window.location = 'api/MyController/DownloadFile/' + guid;
ApiController static:
private static Dictionary<Guid, String> _fileContents = new Dictionary<Guid, String>();
ApiController method:
public IHttpActionResult DownloadFile(Guid guid)
{
try
{
if (_fileContents.ContainsKey(guid))
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var content = Encoding.ASCII.GetBytes(_fileContents[guid]);
using (var stream = new MemoryStream(content))
{
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "MyFile.bin";
}
return Ok(result);
}
else
{
return NotFound();
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
return BadRequest();
}
The calling sequence works perfectly but the DownloadFile() method throws the following exception:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'System.Net.Http.StreamContent' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
</ExceptionMessage>
<ExceptionType>
System.Runtime.Serialization.InvalidDataContractException
</ExceptionType>
Can anyone tell me what is going on and how to accomplish my goal of downloading a simple html file?

Getting different data in ajax response froms second time

I am encountering a problem which I am not able to find out why.
I am using spring mvc and I am sending ajax request to one of my controller.
$.get("<c:url value="/createcomment" />", {id: pageid , newcomment : newcomment})
.done(function(data){
$("#newcomment"+data.pageId).val('');
var html = '<tr><td>'+
'<div class="pull-left">'+
'<img class="img-rounded" src="resources/profile-pics/male/small.jpg" alt="">'+
'</div><div class="span4"><ul class="nav nav-stacked">'+
'<li><font size="2"><i class="icon-user"></i>'+data.account.firstName+' '+data.account.lastName+'</font></li>'+
'<li><font size="2">'+data.text+'</font></li><li><font size="1">'+data.postingDate+
'</font></li></ul></div></td></tr>';
$(html).inserAfter($("#tr"+data.pageId));
}
When i refresh the page and send the request i get the following desired object.
and when I send it second time again i get Some Document Object.
I don't understand what is happening wrong.
#RequestMapping(value="/createcomment",method=RequestMethod.GET)
public #ResponseBody Comment createComment(#RequestParam(value="id")final String pageId,#RequestParam(value="newcomment")final String text,
final HttpServletRequest request ,final WebRequest req){
final Comment comment = new Comment();
comment.setId(GenerateUID.generate());
comment.setText(text);
comment.setPostingDate(new Date());
comment.setPageId(Long.valueOf(pageId));
try {
return comment;
} catch (NumberFormatException e) {
return null;
} catch (SignInNotFoundException e) {
return null;
}
}
Just for additonal information i am using jQuery JavaScript Library v1.7.1
You might want to check if your method throws a NumberFormatException or SignInNotFoundException, in which case it returns null. Your network log shows that 0 bytes of data have been transferred.

Resources