Invalid JSON formatting in Volley post request - java

I am trying to pass
data={"process" : "ExampleProcess", "phone" : "123456"}
As a post request in volley, thus far I have managed to create a(very basic) method that will send
the required information out to the server, but I am getting a failed response.
I added logs to the program for which I can see
ERROR:: com.android.volley.ParseError: org.json.JSONException: End of input at character 2 of
But I believe it has to do with the way I am trying to send my information over. Upon debugging I also came to realize that I was getting an error indicating
Method threw 'java.lang.NullPointerException' exception. Cannot evaluate org.json.JSONObject.toString();
For which I do not know what to do, even if I change the:
total.put("data", data.toString());
to
total.put("data", data);
The error will persist. At this point I have no clue as to how can I go about sending the correct JSON post request to my URL(which has been taken out from the example btw)
public void volleyConnector(String url) {
final JSONObject data = new JSONObject();
final JSONObject total = new JSONObject();
try {
data.put("process", "ExampleProcess");
data.put("phone" , "123456789");
total.put("data", data.toString());
} catch(JSONException e) {
Log.v("JSON ERROR: ", e.toString());
}
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest( url, total, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.v("--------------","---------------------------");
Log.v("RESPONSE: ", "-----> " + response.toString());
Log.v("<----- BTW------>", total.toString());
Log.v("--------------","---------------------------");
}
}, new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error) {
Log.v("--------------","---------------------------");
Log.v("RESPONSE: " , "xXxX FAIL X_____X FAIL XxXx");
Log.v("|>>>ERROR: ", error.toString());
//Log.v("|>>>ERROR: ", error.getLocalizedMessage());
Log.v("<----- BTW------>", total.toString());
Log.v("--------------","---------------------------");
} // end of onErrorREsponse
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json; charset=utf-8");
return headers;
}
};
Volley.newRequestQueue(this).add(jsonObjectRequest);
} // end of volley connector method
My complete error log(upon the failed request) reads:
V/RESPONSE:: xXxX FAIL X_____X FAIL XxXx
V/|>>>ERROR:: com.android.volley.ParseError: org.json.JSONException: End of i
V/<----- BTW------>: {"data":"{\"process\":\"ExampleProcess\",\"phone\":\"123456789\"}"}
I am not too sure as to what is going on and I am not getting anywhere by reading the docs and debugging with Android studio. As far as I am concerned, one of the parameters is a JSONObject and I am passing in one albeit it might be wrongly formatted.
Any help/pointers will be greatly appreciated.

You are doing correct but try code once by making one small change in your code that is-
JSONObject data= new JSONObject();
data.accumulate("username", "mobileGps");
data.accumulate("password", "9565551236");
JSONObject total= new JSONObject();
total.put("data",data);
json = jsonObjectNew.toString();
And pass this "json" to method and check once. Looking same but try once.

Related

Unable to create file on Onedrive through Microsoft Graph Rest API

I am creating an Android app that uploads basic text files to a user's onedrive by using the Microsoft Graph API.
I have discovered by using https://developer.microsoft.com/en-us/graph/graph-explorer to create files using a PUT request with the link "https://graph.microsoft.com/v1.0/me/drive/root:/Test.txt:/children", With the header "Content-Type" "text/plain", and filling the request body with the text to go into the text file. Using the graph explorer, this works without any issues, however when testing my code with all of these things, it always gives me an error 400.
public void saveOpportunityToServer (final String textToSave, String fileName)
{
try
{
StringRequest request = new StringRequest(Request.Method.PUT, "https://graph.microsoft.com/v1.0/me/drive/root:/" + fileName + ":/content",
new Response.Listener<String>() {
#Override
public void onResponse(String response)
{
Log.d ("PAST QUOTES SAVE", "Created file on server");
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error)
{
Log.e ("PAST QUOTES SAVE", "Failed to create file on server: " + error.toString());
}
})
{
#Override
public byte[] getBody() throws AuthFailureError {
return textToSave.getBytes();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put ("Authorization", "Bearer " + mAccessToken);
headers.put ("Content-Type", "text/plain");
return headers;
}
};
serverRequest.getInstance().addToRequestQueue(request, "Create past quote file request");
}catch (Exception e){
Log.e ("PAST QUOTES SAVE", "Failed to create file on server");
}
}
Where serverRequest is an instance of Volley.RequestQueue.
If the function "getBody()" in String Request is left untouched, or the "textToSave" string is empty, the server responds with a success, creates the requested file, but as expected, the file is empty.
Does anyone have a solution, or at least a reason for why the plain text isn't being accepted?
Edit: Request & Response Headers and Body
Headers:
"Authorization" "Bearer [AccessToken]"
"Content-Type" "text/plain"
Body:
"This is a test"
I'm certain the authorization is working, but I guess there is a chance that the server is not properly interpreting the content-type header, however it works on the mentioned website, so I am not sure why it wouldn't in my program.
The response is an empty Error 400, which is stated as a Malformed Request by Microsoft, which leads me to believe the above, however I cant see a way to fix it.
Finally, I found where the issue is.
Due to how volley works, you cannot simply add a "Content-Type" header to the "getHeaders()" function. To change the body content type, you must override a separate function, "geyBodyContentType()"
Here is my final request code, for anyone wondering in the future how to solve this problem.
StringRequest request = new StringRequest(Request.Method.PUT, "https://graph.microsoft.com/v1.0/me/drive/root:/ " + fileName + ":/content",
new Response.Listener<String>() {
#Override
public void onResponse(String response)
{
Log.d ("PAST QUOTES SAVE", "Created file on server");
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error)
{
Log.e ("PAST QUOTES SAVE", "Failed to create file on server: " + error.toString());
}
})
{
#Override
public byte[] getBody() throws AuthFailureError {
return textToSave.getBytes();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put ("Authorization", "Bearer " + mAccessToken);
return headers;
}
#Override
public String getBodyContentType ()
{
return ("text/plain");
}
};

send json to Laravel using postman and android

i am trying to send json using postman to Lavavel but i facing this error.
enter image description here
this is my json code:
{
"email":"test#test.com",
"password":"testtest"
}
and this is Laravel codes :
Route::get('/r','test#store');
and
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use DB;
use Log;
class test extends Controller
{
public function store(Request $request)
{
$email = $request->input('email');
$password = $request->input('password');
Log::info('test');
Log::info($email);
Log::info($password);
DB::table('login')->insert([
['email' => $email],
['password' => $password]
]);
}
}
also i trying using android for send data using volley and so checked Laravel logs :
Column 'email' cannot be null (this is Laravel logs)
and on android Logs:
E/Volley: [299] BasicNetwork.performRequest: Unexpected response code 500 for http://192.168.1.4:8000/r
D/error: com.android.volley.ServerErro
my android code is :
public class ApiService {
private final Context context;
public ApiService(Context context){
this.context=context;
}
public void loginUser(String email, String password, final OnLoginResponse onLoginResponse){
JSONObject requestJsonObject=new JSONObject();
try {
requestJsonObject.put("email",email);
requestJsonObject.put("password",password);
JsonObjectRequest request=new JsonObjectRequest(Request.Method.GET, "http://192.168.1.4:8000/r",requestJsonObject , new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("response",response.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("error",error.toString());
}
}) {
#Override
public Map getHeaders() throws AuthFailureError {
HashMap headers = new HashMap();
headers.put("Content-Type", "application/json");
return headers;
}
};
request.setRetryPolicy(new DefaultRetryPolicy(18000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
Volley.newRequestQueue(context).add(request);
} catch (JSONException e) {
Log.e(TAG, "loginUser: "+e.toString());
}
}
public interface OnLoginResponse{
void onResponse(boolean success);
}
}
I hope this helps people trying to search on how to send JSON data to laravel not only specific to android applications but to all. The goal of this solution is to identify whether you can send a JSON data to laravel or not.
First of all you have to download postman from https://www.getpostman.com/ to test if your API is really working or not.
Create a post request using postman. Be sure that you follow the example data below
Be sure that you set your Routes that would associate to the controller
This is the controller part that will show the JSON data you sent if it was successfully accepted or not.
And also, if ever you are trying to send POST data to laravel, by default they provided a CSRF Token which is applicable for the forms if you are going to use the MVC of laravel. For the meantime, we are going to take this down and comment it out. Just go to app/http/kernel.php
and now you'll get the following result from the code earlier
$json = json_decode($request['json']);
echo $json->{'email'};
echo "\n";
echo $json->{'password'};
We tested that we were able to send data to laravel. I hope this truly helps.
Wen you want to send data, you will want to use POST or PUT method on your postman, specially if you are sending a body, that means that you are sending data. Get method is used to retrieve data from a service.
Take a look into CRUD functions for more information.
Your postman should look something like this
Last in your android code try to change this line
JsonObjectRequest request=new JsonObjectRequest(Request.Method.GET, "http://192.168.1.4:8000/r",requestJsonObject , new Response.Listener<JSONObject>() {
to use Request.Method.POST

How to get data from MongoDB with Android AsyncHttpClient

Background:
I'm working on an Android project that was handed off to me and there are some things I'm still trying to learn. The people on the project before me left no documentation, so forgive me.
Question:
Basically I want to know how to get data back from our MongoDB (I think). Using AsyncHttpClient params are put sent via post
private AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("authorization", getSharedPreferences("Prefs", Context.MODE_PRIVATE).getString("authToken", ""));
params.put("name", name);
params.put("email", email);
client.post(Utilities.getBaseURL() + "session/updateProfile", params, new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, cz.msebera.android.httpclient.Header[] headers, JSONObject response) {
HashMap<String, String> profile = new HashMap<>();
profile.put("user_name", name);
profile.put("user_email", email);
Utilities.updateAllDetails(profile);
}
#Override
public void onFailure(int statusCode, cz.msebera.android.httpclient.Header[] headers, Throwable throwable, JSONObject response) {
Utilities.showUserDialog(context, "Profile Change Error", "Attention, there was an error in updating your profile, please try again.");
}
});
So the above code is basically updating a profile and sending the params via http post.
Later there is a get on the client:
client.get(Utilities.getBaseURL() + "session/getUserId", new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, cz.msebera.android.httpclient.Header[] headers, JSONObject response) {
try {
userId = response.getString("responseString");
startActivityForResult(intent, PICK_IMAGE);
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(int statusCode, cz.msebera.android.httpclient.Header[] headers, Throwable throwable, JSONObject response) {}
});
What I don't understand is where "session/updateProfile" and "session/getUserId" come from. Is this an API call, if so how can I find what is available and also how to add to it?
Update
Found this code in a JavaScript file for the website. Maybe this can lead someone to help me put everything together?
JsonRoutes.add('get', '/api/v1/session/getUserId', function(req, res, next) {
var authToken = req.headers["authorization"];
var userObj = verifyUser(authToken);
var response = {};
if (userObj) {
response.responseString = userObj._id;
JsonRoutes.sendResult(res, 200, response);
} else {
response.responseString = "user not found";
JsonRoutes.sendResult(res, 200, response);
}
});
Do I need to add to this JS file to expand the API?
where [do] "session/updateProfile" and "session/getUserId" come from? Is this an API call
Yup, REST API call to wherever Utilities.getBaseURL() points to.
how can I find what is available?
Well, if that server is yours, then you'll need to go find some code / documentation for that. Otherwise, if it's some other external service, you'll still have to find some API documentation or contact someone who does know about it. You've mentioned in the comments that it is DigitalOcean, so it isn't an external service. There is additional server side code to inspect.
how to add to it?
If it were an external service, you probably couldn't. Since this DigitalOcean server could be running literally any service, it entirely depends on the server side programming language. You've mentioned that Javascript file along with MongoDB, so I'm guessing it's some NodeJS variant. You mention MeteorJS in the comments, so that's the documentation you need to add new features.
Do I need to add to this JS file to expand the API?
Simply: yes.
I want to know how to get data back from our MongoDB
Essentially this line is doing that. Of course, the response code shouldn't always be 200 and the content of the response string can be anything you want, but probably should be JSON, or at least something Android can parse
JsonRoutes.sendResult(res, 200, response);

Volley JsonObjectRequest Put is not working

I am making JsonObjectRequest with Put method but it is not working and getting "{"detail":"Method \"GET\" not allowed."}" error message.
It is working fine on Postman. See attached screenshots for more information.
I didn't modify JsonObjectRequest. I copy this code from google sample code from here "http://developer.android.com/training/volley/request.html".
I don't think this could be a bug in Volley. Please go through my code and let me know what I am doing wrong.
JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.PUT, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
hideDialog();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
hideDialog();
}
})
{
#Override
public Map getHeaders() throws AuthFailureError {
Map headers = new HashMap();
headers.put("Authorization", "Token " + dm.readString("auth_token"));
return headers;
}
};
AppController.getInstance().addToRequestQueue(jsObjRequest);
Edit: I know in the screenshot it shows 400 bad request. It is because i need to pass 2 params ie {"dg_id":"80","delivery_ids":["90936"]}. With this params also i am getting the same error in Volley.
Sample auth_token Value: MTIzNDU2NzIzNDM6ZGVsaXZlcnlndXk=
Sample Body value: {"dg_id":"80","delivery_ids":["90936"]}
Add "/" at end of DELETE, PUT interface url,do check out the following snippet.
If a client issues a GET request to "/testdir/" (i.e., at the
directory).......It is interesting to take note that if a client issue
a GET request to "/testdir" (without specifying the directory path
"/"), the server returns a "301 Move Permanently" with a new
"Location" of "/testdir/", as follows.

Method returned a value but the value not passed correctly

I need to return some data from a remote server to my app using Volley request, but after some time testing it I'm unable to get it working.
I have a code that looks like this:
String recipientUsername = foo;
picture = retrievedPicture(recipientUsername);
Log.i(TAG, "String picture: " + picture);
recipientPicture = (NetworkImageView) findViewById(R.id.chat_image_circle_pic);
recipientPicture.setImageUrl(picture, imageLoader);
So picture is declared globally to retrieve a value from a method with Volley inside. In my log when the above lines are read look like this:
I/ChatActivity: String picture: null
Which gets more confusing when the method itself is actually returning something. The method looks like this:
public String retrievedPicture(final String username) {
// Tag used to cancel request
String tag_string_req = "req_update_user";
StringRequest stringRequest = new StringRequest(Request.Method.POST,
AppConfig.URL_RETRIEVE, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "User is retrieving on MySQL: " + response.toString());
try {
JSONObject jObj = new JSONObject(response);
boolean error = jObj.getBoolean("error");
if (!error) {
// Do no changes on SQLite at the moment
JSONObject userObj = jObj.getJSONObject("user");
picture = userObj.getString("picture");
Log.d(TAG, "Picture retrieved from MySQL: " + picture);
} else {
// Error occurred in updating user's data. Get the error message from php node:
String errorMsg = jObj.getString("error_msg");
Log.e(TAG, errorMsg);
//Toast.makeText(getActivity(), errorMsg, Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Error in retrieving user's data: " + error);
}
}) {
#Override
protected Map<String, String> getParams() {
// Posting the params to php (nodes, data to be changed)
Map<String, String> params = new HashMap<>();
params.put("tag", "retrievepic");
params.put("username", username);
return params;
}
};
// Adding request to the request queue
AppController.getInstance().addToRequestQueue(stringRequest, tag_string_req);
return picture;
}
And the log shows the method does work:
D/ChatActivity: User is retrieving on MySQL: {"tag":"retrievepic","error":false,"uid":19,"user":{"username":"test07","picture":"http:\/\/192.168.0.3\/worka\/uploads\/test07_05112015_155304.jpg"}}
D/ChatActivity: Picture retrieved from MySQL: http://192.168.0.3/worka/uploads/test07_05112015_155304.jpg
So what I could guess is that I'm not passing anything from the try catch block of the method. If so, what can I do to get the value passed correctly? The try catch block is already nested inside a void method that seems fixed. I'm really hoping there's a solution to this so I can make the method into a utility class too. Thanks for reading guys!
Your problem is that picture is always null when you return it as a result from your method.
Volley request are asynchronous - they are executed on a worker thread and return a result sometime in the future. You are notified that the result is there in onResponse(). This is why you see the correct thing in your logcat.
At the time you return picture as a result from the method, the request has not been executed yet and the value of picture is null.
As a solution, you should change the return type of the method, executing the request to void and move the image loading logic to onResponse().
So what I could guess is that I'm not passing anything from the try
catch block of the method.
You are returning the current value of picture. You are doing the wrong assumption that the UI Thread is waiting for
AppController.getInstance().addToRequestQueue
to finish. And that's not true.
retrievedPicture() method will return default value of picture is obvious, Because volley will execute request asynchronously.
In line AppController.getInstance().addToRequestQueue(stringRequest, tag_string_req);. You are executing volley request which is asynchronous, So in very next line you are returning picture, yet volley response is not received. that's why your method is returning default value.
You should execute recipientPicture.setImageUrl(picture, imageLoader); inside onResponse() method, where volley Response received.
The picture return before onResponse.
Try to use EventBus.
Use EventBus post a Event.
Than you can get the event and go on.

Categories