I've seen multiple posts about this topic, but none of them seem to be the solution to my problem.
The problem is that the JSON response from the server is getting cut off and therefore I'm getting a JSONException when trying to get the response into a JSONArray.
json = new JSONArray(EntityUtils.toString(response.getEntity()));
Here is the whole code:
private class AsyncFetchForms extends AsyncTask<String, Void, JSONArray> {
private HttpClient mClient = new DefaultHttpClient();
private AsyncTaskCompleteListener<JSONArray> listener;
private String serverUrl;
private String credentials;
private ProgressDialog progressDialog;
private HttpGet httpGet;
private String response;
private BasicResponseHandler responseHandler;
private boolean showDialog;
private JSONArray json;
public AsyncFetchForms(String url, String message, AsyncTaskCompleteListener<JSONArray> listener, boolean showDialog)
{
serverUrl = Utils.getServerUrl(context) + url;
credentials = Utils.getUserCredentials(context);
this.listener = listener;
this.showDialog = showDialog;
httpGet = new HttpGet(serverUrl);
httpGet.setHeader("Authorization", "Basic " + credentials);
httpGet.setHeader("Accept", "application/json");
httpGet.setHeader("Accept-Encoding", "gzip");
httpGet.setHeader("Connection", "keep-alive");
responseHandler = new BasicResponseHandler();
if(showDialog)
{
progressDialog = new ProgressDialog(context);
progressDialog.setMessage(message);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show();
}
}
#Override
protected JSONArray doInBackground(String... params) {
try {
HttpResponse response = mClient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == 200) {
json = new JSONArray(EntityUtils.toString(response.getEntity()));
return json;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(JSONArray result) {
System.out.println(result.toString());
}
}
Can anyone see the problem?
Logcat can only show about 4000 characters. So you will have to implement a recursive function to see the entire log. Use below function to see the entire log:
public static void longInfo(String str) {
if (str.length() > 4000) {
Log.d("", str.substring(0, 4000));
longInfo(str.substring(4000));
} else
Log.d("", str);
}
If you (or your team) implement the server side yourself, first thing I'd check is if the server is returning the correct HTTP response. In particular, if you transfer the data by HTTP, you need to have correct Content-Length or otherwise your data will be cut off. Also, Content-Length must be the length of data after any Transfer Encodings are applied, in other words, after the length of the data after being gzipped. Alternatively, use chunked transfer.
Second, make sure that your server is generating valid JSON. Maybe you missed a closing parentheses or so. Maybe you need to parse JSON Object rather JSON Array.
Also, if you receive exceptions, please always post the the entire traceback.
First of all, try to log the EntityUtils.toString(response.getEntity()) response and make sure that it starts with "[" not "{" ie. it's a jsonArray not jsonObject.
Then try to open the url in your browser ,if avilable, and make sure that there are no encoding issues.
Finally, if the problem is still exists please send us the error log output.
This answer is completely out of the subject but :
What are you trying do here ? Do you know that there are libraries which are doing all this boring job for you ?
When I talk about boring job, I'm talking about managing all the background running stuff (like AsyncTask), JSON decoding and HTTP response. I know that it's sometimes a pain in the a** (I've been there) but now I've choose to not worry anymore and use a dedicated library : http://square.github.io/retrofit/
This little baby will contact the Webservice of your choice, download the JSON and put it into a custom java class with all the attributes you want to deal with.
If you plug it with something like ORMLite, it can even save your JSON response object into a SQLite DB that you can access in the same way (it "populates" a java class object by setting all the attributes for you).
Personally I can't imagine myself doing all this stuff by hand anymore, it's just trouble without the benefits =)
Related
I've answered my own question here. See the first code block where I use php://input to get the posted data.
I'm trying to send a post request from my app to a webserver, and I'm checking for the post vars using PHP:
if( isset( $_POST['name'] ) ){
echo json_encode(['status' => 1]);
}else if( $posted_data = (string) #file_get_contents('php://input') ) {
echo json_encode(['status' => 2]);
}else{
echo json_encode($_POST);
}
The request always returns and empty json encoded array.
I'm using the latest Android Studio, and the latest OkHttp, com.squareup.okhttp3:okhttp:3.4.1. For me, this is like the "Hello World" of OkHttp in Android Studio.
In MainActivity.java:
public void postSomething(View view) {
String url = "https://example.com/json_api_test.php";
String json = "{\"name\":\"cholula\"}";
OkHttpPostHandler handler = new OkHttpPostHandler();
String result = "";
try {
result = handler.execute(url, json).get();
} catch (Exception e) {
e.printStackTrace();
}
displayPostResponse(result + "\n");
}
My OkHttpPostHandler.java:
public class OkHttpPostHandler extends AsyncTask<String, Void, String> {
OkHttpClient client = new OkHttpClient();
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
#Override
protected String doInBackground(String... params) {
RequestBody body = RequestBody.create(JSON, params[1]);
Request request = new Request.Builder()
.url(params[0])
.post(body)
.build();
try {
Response response = client.newCall(request).execute();
return response.body().string();
}
catch( Exception e ){
return "HTTP Request Error";
}
}
}
When I debug, I can see that the params[1] value is the expected json-like string, but that's the last time I see it.
I've tried forming the json in a number of ways, so I'm not sure if that's the problem. I just don't understand why I can't see the posted vars when the post request gets to the server.
How can I see the posted vars on the webserver? What am I doing wrong? I've only been using Android Studio and Java for less than a week, so I have no clue. I've really looked around the internet a lot for the answer, and so posting here is the last resort.
Thanks!
It turns out that one must use php://input to get the posted data.
I need a little help with this, I've used HTTP requests before but through JavaScript when I was using AJAX, it looks similar but I'm not entirely sure how to do all of it properly. I've seen some people's codes and stuff, but I'm not sure about two things. First, I want to send an int through the POST in order to identify which query should be called and what data should be sent back through the response. Second, I'm not sure about the URL, do I need a domain? I just need to connect to a server on my machine which I'm using with XAMPP. I'm not entirely sure how to do this? Do I just place a URL with my machine's IP with a port or something?
So here's what I've attempted:
public class Request {
private static Request instance;
private static String URL;
private String requestResult;
private String error;
private Request(){
this.URL = "http://IPAddress or Server Address/Android Webservice/webservice.php"; /* not sure what I should use here, I'm using an apache server */
this.error = new String();
this.requestResult = new String();
}
public static Request getRequest(){
if(instance == null){
instance = new Request();
}
return instance;
}
public void sendHttpPostRequest(String option){
HttpClient client = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(URL);
HttpResponse serverResponse;
String jsonToSend = "message={identifer:" + option + "}";
NameValuePair parameter = new BasicNameValuePair("data", jsonToSend);
try {
StringEntity entity = new StringEntity(jsonToSend);
postRequest.addHeader("content-type", "application/x-www-form-urlencoded");
postRequest.setEntity(entity);
serverResponse = client.execute(postRequest);
} catch (Exception e){
}
}
public String getURL() {
return this.URL;
}
public String getResult(){
return this.requestResult;
}
}
I've got it in a class, because I want to be able to call it anywhere, plus I need to call it in multiple views in my android application. I would say the most important part in here is the `sendHttpPostRequest. However I'm not sure how to go about using that response to do anything. Normally with AJAX I'd just get the response text and go from there, but that doesn't work here. I've seen various examples but I'm having a hard time getting them, and some of them do a lot of stuff that I'm not sure I need.
For instance this is my PHP file:
<?php
$obj = json_decode($_POST['message']);
$obj = json_decode($dataReceived,true);
$data = array("data","some other data","the last piece of data");
json_encode('data'=>$data);
echo $data;
?>
For now it looks like this because this is a simple test, but what the end goal should be is to return an an associative array which would be the result of a query from my database. I know how to do that easily, but I'm not sure how to send the request to get this file to return that stuff. I don't know how to parse a JSON within Java, especially an associative array and I'm also not sure how my server should be configured to allow connections from android devices.
So what exactly needs to go in the URL to connect to my PC? How do I parse JSON response and then convert it into data that I can place in my android application? How do I go about moving anywhere with this device, and retrieving this data from a location far from my server?
I'm hoping that this doesn't require payment of any sort, I mean the server is on my computer after all.
I am working on a project in which I am making a call to one of my servers using RestTemplate which is running a restful service and getting the response back from them.
The response that I will be getting from my server can be either of these error responses (that's all I have for error response) if something has gone wrong -
{"warning": "user_id not found", "user_id": some_user_id}
{"error": "user_id for wrong partition", "user_id": some_user_id, "partition": some_partition}
{"error": "missing client id", "client_id":2000}
or below successful response (it can be any random json string key can also be different) -
{"#data": {"oo":"1205000384","p":"2047935"}
If I am getting any error response as mentioned above, then I am deserializing it (my bad :( ) so that I can log them as an error with a specific error or warning I got front the server which can be for example - user_id not found or missing client id.
If it is a successful response then also I am deserializing it which I don't need for my use case as we don't have any POJO and I just need to return the response as it is which I have got from the server.
In my use case, I don't need to deserialize my response string if it is a successful response as we don't have any POJO for that and we are returning the response string as it is which we have got from the server. But just for logging specific error messages (if I am getting error response from the server) I am deserializing it which I am thinking is unnecessary. There might be better solution for my use case.
Below is my Java client which is calling Callable task using future.get -
public class TestingClient implements IClient {
private ExecutorService service = Executors.newFixedThreadPool(10);
private RestTemplate restTemplate = new RestTemplate();
#Override
public String executeSync(ClientKey keys) {
String response = null;
try {
ClientTask ClientTask = new ClientTask(keys, restTemplate);
Future<String> future = service.submit(ClientTask);
response = handle.get(keys.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
} catch (Exception e) {
}
return response;
}
}
And now below is my ClientTask class which implements Callable interface. In the call method, I am generating an URL and then hit the server using RestTemplate and get the response back -
class ClientTask implements Callable<String> {
private ClientKey cKeys;
private RestTemplate restTemplate;
public ClientTask(ClientKey cKeys, RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.cKeys = cKeys;
}
#Override
public String call() throws Exception {
// .. some code here
String url = "some_url";
String response = restTemplate.getForObject(url, String.class);
String test = checkJSONResponse(response);
return test;
}
private String checkJSONResponse(final String response) throws Exception {
// may be there are some better way of doing it for my scenario instead of using GSON
Gson gson = new Gson();
String str = null;
JsonObject jsonObject = gson.fromJson(response, JsonObject.class); // parse it, may be performance issues here/
if (jsonObject.has("error") || jsonObject.has("warning")) {
final String error = jsonObject.get("error") != null ? jsonObject.get("error").getAsString() : jsonObject
.get("warning").getAsString();
// log specific `error` here using log4j
str = response;
} else {
str = response;
}
return str;
}
}
As you can see in my above code we are deserializing the JSON string only to log specific error messages if we are getting any error response back. But for successful response we don't need any deserialization but still we are doing it.
Is there any better way of solving this problem? Because currently I am seeing some performance issues with the GSON deserialization.
The only way I can identify successful response along with error response is with error or warning in the response so I am thinking of using regular expressions which can identify error or warning as the key in the response string. If they contain error or warning in the response string then extract the specific error or warning message and log it. But not sure whether this will have any performance benefit or not.
Is there any other better way of solving this problem without using GSON deserialization.
It is a good practice to use HTTP status codes for your responses (e.g. BAD_REQUEST, NOT_FOUND). Return one of them from the server and then check on the client. It will allow to parse response only if some error code is returned:
String result = restTemplate.execute("url", HttpMethod.GET, null, new HttpMessageConverterExtractor<String> {
#Override
public MyEntity extractData(ClientHttpResponse response)
throws IOException {
String result = super.extractData(response);
if (response.getStatusCode() != HttpStatus.OK) {
// parse message and log only for some error code
JsonObject errorJson = parse(result);
log.warn("Got {} status error, with message [{}]", response.getStatusCode(), errorJson.get("warning"));
}
return result;
}
});
You do not need to deserialize to a POJO.
A simple JSON parser such as the one found on json.org will provide minimal JSON parsing an return a JSONObject that you can query.
I very much doubt that
you can come up with a faster parsing of your json responses using regular expressions or otherwise, without taking the risk of failing in corner cases
given the size of your response strings, that the JSON parsing is the performance bottleneck in your code
Unless you have done some serious profiling, I would play safe and follow the first rule of program optimization
Now I'm learning how to use Gson library to set and get data from webservice in Json format, but its best practices and strategies are a bit dark for me so I will be very delightful if somebody would explain more about it.
I've created an Entity class to get response entity from server:
public class Response
{
#SerializedName("Type")
public String Type;
#SerializedName("result")
public String result;
}
and in AsyncTask class I've used:
Response _Response = new Response();
try
{
String _url = Global.Url_Request ;
Map<String, String> Params = new HashMap<String, String>();
Params.put("PhoneNumber", this.User_PhoneNumber);
String json = new GsonBuilder().create().toJson(Params, Map.class);
HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(_url);
httpPost.setEntity(new StringEntity(json));
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
HttpResponse getResponse = httpclient.execute(httpPost);
HttpEntity returnEntity = getResponse.getEntity();
is = returnEntity.getContent();
Gson gson = new Gson();
Reader reader = new InputStreamReader(is);
_Response = gson.fromJson(reader, Response.class);
}
catch (Exception e)
{
_Response.Type= "Error";
_Response.result= "Data Is Wrong";
}
return _Response;
It works fine with creating an Entity Object for every different http POST call, but my questions are:
What is the best practice for handling webservices with different response objects?
How can I handle this situation: if data sent ok then return specific Jsonarray; if not, return a Response object to detect something is wrong. Should I use Custom typeAdapter?(sample code would be great)
If webservice returns an empty response gson.fromJson would throw an **IllegalStateException: Expected a string but was BEGIN_OBJECT** how can i prevent this?
Thanks in advance
1. What is the best practice for handling webservices with different response objects?
I think that this depends on the kind of control you have. If you code also the webservice, you could create a big container object that has may fields. Each of these fields is one of the possible responses you can pass between client and server. If you have not control on what the server can reply, and it can differ a lot, JsonParser is your best friend. You can use it to snoop inside JSON and decide the right strategy to handle the response.
Let's do an example for case one. I declare these classes:
public static class GenericResponse{
public ServerException exception;
public StandardResponse1 responseType1;
public StandardResponse2 responseType2;
#Override
public String toString() {
return "GenericResponse [exception=" + exception + ", responseType1=" + responseType1 + ", responseType2=" + responseType2 + "]";
}
}
public static class ServerException{
public int error;
public String message;
}
public static class StandardResponse1{
public List<Integer> list;
public Date now;
}
With this kind of classes, I can parse:
{"responseType1":{"list":[1,2],"now":"Nov 25, 2013 9:26:51 PM"}}
or
{"exception":{"error":-1,"message":"Don\u0027t do this at home"}}
For example, if I get from server the second type of response, this code:
GenericResponse out = g.fromJson(fromServerStream, GenericResponse.class);
System.out.println(out);
will return me:
GenericResponse [exception=stackoverflow.questions.Q20187804$ServerException#1e9d085, responseType1=null, responseType2=null]
All you have to do is to check your fields to see what actually the server replied.
Case two. You cannot control the JSON, so the server can reply
[13,17]
or
{"error":-1,"message":"Don\u0027t do this at home"}
In this case you cannot pass directly the class type to Gson as before, but you have to check things. I would solve this problem with a JsonParser.
Gson g = new Gson();
JsonParser jp = new JsonParser();
JsonElement o = jp.parse(s);
if (o.isJsonArray()){
List<Integer> list = (List) g.fromJson(o, listType1);
System.out.print(list);
}
else{
ServerException e = g.fromJson(s, ServerException.class);
System.out.print(e);
}
Using JsonObject/JsonArray and so on, is what happens inside a TypeAdapter. In the adapter you start with the JsonElement that is already parsed. There are many good example of it on SO, this for example.
How can I handle this situation: if data sent ok then return specific Jsonarray; if not, return a Response object to detect something is wrong. Should I use Custom typeAdapter?(sample code would be great)
Do you mean you want to parse this kind of response? Examples of point 1 show this.
If webservice returns an empty response gson.fromJson would throw an **IllegalStateException: Expected a string but was BEGIN_OBJECT how can i prevent this?**
JsonParser/TypeAdapter is again the solution. You can check if JsonElement is null or if is a primitive type (String, Integer, Boolean) and deal it.
I'm writing some small android application that works with REST services.
The base structure of the response is:
{
result: "ok/error",
message: "some string",
entity: "either object or error description"
}
The entity type is different each time whether the response is ok or error.
Now, I'm calling the service from AsyncTask and I need to return the result to the UI thread.
I'm using gson library to desirialize the JSON from the server. The problem is that I do not have the ability to know what type of response I've got (ok or error).
Also, the AsyncTask can return only single type to the UI thread. Below is an example for what I could come up with. I need to state that I'm not a java programmer and I may not know all the patterns and maybe I miss something.
Anyway, I'll be glad for any help.
public class RegisterProxyAsync extends AsyncTask<User, String, Object> {
#Override
protected Object doInBackground(User... params) {
try {
Gson gson = new Gson();
String request = gson.toJson(params[0]);
HttpClient client = new DefaultHttpClient();
HttpPost postAction = new HttpPost("http://SomeServiceEndpoint/register");
postAction.addHeader(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
postAction.setEntity(new StringEntity(request));
HttpResponse response = client.execute(postAction);
if (response != null) {
InputStream stream = response.getEntity().getContent();
String strResult = CharStreams.toString(new InputStreamReader(stream));
try {
UserResponse userResponse = gson.fromJson(strResult, UserResponse.class);
return userResponse;
} catch (Exception e) {
ErrorResponse errorResponse = gson.fromJson(strResult, ErrorResponse.class);
return errorResponse;
}
Log.e("debug", strResult);
}
} catch (Exception e) {
// TODO:Handle exception
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Object result) {
// TODO: execute some work
}
}
EDIT:
I've changed the server to return proper HttpCodes (200 for success, 400 for error) but, I still have the problem of returning two different types of object from the doinbackground method, one for error and another for success.
A proper REST service should include an HTTP response code indicating the status of the processed request. If you have control over the service then I would recommend altering it to return a variant of 40x or 50x codes, to signal that an error has occurred. The service should only return a 200 OK if the request succeeded. On your client side, you would then parse the response based on the status code (normal entity for 200 ok, error entity for anything else). Pseudocode:
if(response.getStatusLine().getStatusCode() == 200) {
UserResponse userResponse = gson.fromJson(strResult, UserResponse.class);
} else {
ErrorResponse errorResponse = gson.fromJson(strResult, ErrorResponse.class);
}
If you can't change the server side for whatever reason, then on your client side you will have to use a generic JsonObject to parse the response. Pseudocode:
JSONObject jsonObj = new JSONObject(strResult);
if("ok".equals(jsonObj.get("result")) {
return gson.fromJson(jsonObj.toString(), UserResponse.class);
} else {
return gson.fromJson(jsonObj.toString(), ErrorResponse.class);
}