Getting JsonSyntaxException in Android retrofit response? - java

Related Question
Response of Json is New line delimiter Json :
{"type":"data","id":"xyz"}
{"type":"value","id":"xcf"}
....
....
I am using Retrofit to make request:
public void getWarehouse(){
//Generation of RestAdapter
RestAdapter adapter = new RestAdapter.Builder ()
.setEndpoint(URL)
.setLogLevel(RestAdapter.LogLevel.FULL)
.setLog(new AndroidLog("= NETWORK ="))
.build();
//Making request to API
adapter.create(WarehouseAPI.class).getWarehouse()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response>() {
#Override
public void onCompleted() {
Log.d(this.getClass().getName(), "OnCompleted ()");
}
#Override
public void onError(Throwable e) {
Log.d(this.getClass().getName(), "Error:" + e.toString());
}
#Override
public void onNext(Response response) {
System.out.println("test");
}
});
}
I can see the response in my Android Studio console but getting following error:
Error:retrofit.RetrofitError: com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 2 column 2 path $
Possibility of Error
Response is in NdJson and it's not able to parse it correctly
Question
How can I parse it correctly?

As #trevor-e mentions, you have to implement a custom converter to handle the ndjson format. Check link below for a guide to start:
Retrofit — Define a Custom Response Converter
Also check out the StringConverter from: How can I return String or JSONObject from asynchronous callback using Retrofit?
You could potentially convert the response to a regular string then parse each line into a JSON object and proceed from there.

Related

Send Data from Android App to MongoDB Atlas

I have build an App in Android Studio that can scan every type of code(like qr code, barcode ect.) and I want to store that Data inside MongoDB.
For that I build an Api with 2 routes post/get to post an item and get all items - tested it with Postman, and it works.
app.get('/items', async (req, res) => {
const collection = client.db('codes').collection('QR');
const items = await collection.find({}).toArray();
res.send(items);
});
app.post('/items', async (req, res) => {
const collection = client.db('codes').collection('QR');
const result = await collection.insertOne(req.body);
res.send(result);
});
My problem is, that it doesnt work when I call my method inside Android Studio
public interface API {
#FormUrlEncoded
#POST("/items")
Call<Void> sendData(
#Field("data") String data
);
}
public void addStuff(String data){
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:3000")
.addConverterFactory(ScalarsConverterFactory.create())
.build();
API api = retrofit.create(API.class);
Call<Void> call = api.sendData(jsonObject.toString());
call.enqueue(new Callback<Void>() {
#Override
public void onResponse(#NonNull Call<Void> call, #NonNull Response<Void> response) {
if (response.isSuccessful()) {
Toast.makeText(getApplicationContext(), "Successfully added data to the Database", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Error getting data from the database" + response.message(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(#NonNull Call<Void> call, #NonNull Throwable t) {
Toast.makeText(getApplicationContext(), "Failure", Toast.LENGTH_LONG).show();
}
});
}
After I scanned a code with my App, I get an dialog that asks me what to do next. One of those options is a Button "Add to Database", where I call the method above.
For Testing purpose I just hard coded an example String that gets passed to my method.
After that, I get the "Failure" Toast.
Tried to attach the debugger to the App, but that didnt really work out, at least Icouldnt figure where the error lies. I tried to to wrap the String into a JSONObject, and send it after I use the toString() Method on the provided data, and I tried to change the data type in the API Interface to JSONObject and send an actual JSONObject, instead of calling the onString() method on the data.
All of it results in failure.

Unable to create converter for my class in Android Retrofit

I am trying to develop clent-server application with Retrofit. My application sends to server json with a string "image" and responses a json with a string with field "name".
My API:
public interface API {
#FormUrlEncoded
#POST("/api/classification/imagenet")
Call<GestureJson> getName(#Body ImageJson json);
}
ImageJson:
public class ImageJson {
public String imageString;
}
NameJson:
public class NameJson {
public int gestureNumber;
}
When user pressed on button in Main Activity MyVoid is called (url is already known):
public void MyVoid() {
String requestUrl = url;
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(GsonConverterFactory.create())
.baseUrl(requestUrl)
.build();
API api = retrofit.create(API.class);
ImageJson json = new ImageJson();
json.imageString = image_uri.toString();
Call<GestureJson> call = api.getName(json);
call.enqueue(new Callback<GestureJson>() {
#Override
public void onResponse(Call<GestureJson> call, Response<GestureJson> response) {
if (response.isSuccessful()) {
status = RESPONSE_SUCCESS;
} else {
status = RESPONSE_FAIL;
}
}
#Override
public void onFailure(Call<GestureJson> call, Throwable t) {
}
});
I have three problems:
1) I don't know what's the difference between Retrofit and Retrofit2. What is better to use?
2) .addCallAdapterFactory(GsonConverterFactory.create()) underlined how wrong (in Retorfit and Retrofit2).
3) I can compile application if i delete .addCallAdapterFactory(GsonConverterFactory.create()). But I have a problem:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.opencvproject, PID: 17742
java.lang.IllegalArgumentException: Unable to create converter for class com.example.opencvproject.GestureJson
for method API.getGesture
Retrofit2 is better because Retrofit outdated (last release was on 2014 https://github.com/square/retrofit/releases/tag/parent-1.6.0). Number 2 in name is just a library version.
GsonConverterFactory may be underlined because you did't add dependency com.squareup.retrofit2:converter-gson
If you delete addCallAdapterFactory(GsonConverterFactory.create()) then Retrofit would't know how to deserialize json to objects. GsonConverterFactory use Gson libarary (https://github.com/google/gson) under the hood to deserialize server json responses.

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

Use different models for deserialization in retrofit success and error callbacks

The API I am working with gives completely different responses for success and failure.
Success:
{
"token":"asdfasdfhkAADBSKJBJBJKBJBK^%&BJBLLKHKJBXZ",
"email":"sample#sample.com",
"role":"admin"
}
Failure:
{
"name": "NotAuthenticated",
"message": "Invalid login.",
"code": 401,
"className": "not-authenticated"
}
I am very new to retrofit and am using the below code to make the call.
LoginRequest request = new LoginRequest(mobileNumber, password);
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<LoginResponse> call = apiService.authenticateUser(request);
call.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
As you can see, retrofit forces me to use the Sample ResponseObject for both success and failure. And hence I am not able to convert the failure response to a pojo.
I have looked at custom deserialization. But writing a custom deserializer for each request can quickly go out of control.
Please help out.
I think the best solution for this will be getting Response Body form retrofit and Serializing it by our self in GSON . I am also looking for other sort of solution.

retrofit wont return response message (android)

this is my code:
the interface :
public interface LoginAPI {
#GET("LoginCheck/{username}/{password}/{status}")
Call<List<Login>> LoginCheck(#Path("username") String username, #Path("password") String password, #Path("status") String status);
}
the class:
public class Login {
String username;
String password;
String status;
}
the main activity :
private void LoginCheck() {
String baseUrl = "http:192.168.169.3:8889/WebService_Indekost/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
LoginAPI api = retrofit.create(LoginAPI.class);
Call<List<Login>> result = api.LoginCheck("username", "password", "status");
result.enqueue(new Callback<List<Login>>() {
#Override
public void onResponse(Call<List<Login>> call, Response<List<Login>> response) {
Log.d("test",response.message());
}
#Override
public void onFailure(Call<List<Login>> call, Throwable t) {
Log.d("Fail", "Fail");
}
});
}
when i try to run it, it shows fail instead of the message. note that the response should be in json format. what am i doing wrong here?
As you commented your error Its saying Expected BEGIN_ARRAY but was BEGIN_OBJECT means exactly You tried to treat it as an Array which starts with brackets like
[ .. data
]
But you are not getting a JSON Array, you are getting an Object. So Try changing the API call Call<List<Login>> into Call<Login>. That may work.
Because you use List<Login> to parse the response, so the response should be a JSON array, like following:
[
{"username":"...","password":"...", "status":"..."},
{"username":"...","password":"...", "status":"..."},
{"username":"...","password":"...", "status":"..."}
]
if the server return result is like following:
{"username":"...","password":"...", "status":"..."}
then you should use Call<Login> replace Call<List<Login>> to parse the response, or, you let server to change its response format to correspond client, it depends what you really want.

Categories