response.body is null even after passing data - android

I am trying to send a notification from one app to another using Firebase Cloud Messaging. I have spent a couple of days now trying to figure out what the problem is. I have passed a notification body to specific token id. When i debug my app it says 'mService is not available' and when i run the app it throws a NullPointerException.
The content i am trying to send is ok as per my analysis.
I have checked the interface IFCMService,FCMClient and the Main class, they all seem to be ok but i still don't understand why i am getting a null response.body. I have also checked my server key and it is well. I have seen a few similar questions but none have been able to specify why this issue may occur. Kindly anyone, i would really appreciate your help.
Below is my IFCMService code
public interface IFCMService {
#Headers({"Authorization:key=" + "<YOUR SERVER KEY>",
"Content-Type:application/json"})
#POST("fcm/send")
Call<FCMResponse> sendMessage(#Body Sender body);
}
FCMClient class
public class FCMClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseURL)
{
if (retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
This is the declaration and specific code where i get the error. The 'mService.sendMessage(content)' section is where the NullPointerException is thrown.
protected void sendRequestDriver(String driverId){
Toast.makeText(MainActivity.this,"send driver",Toast.LENGTH_SHORT).show();
DatabaseReference tokens = FirebaseDatabase.getInstance().getReference(Common.token_tbl);
tokens.orderByKey().equalTo(driverId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postsnapshot:dataSnapshot.getChildren())
{
Token token = postsnapshot.getValue(Token.class);
String json_lat_lng = new Gson().toJson(new LatLng(mLastLocation.getLatitude(),mLastLocation.getLongitude()));
Notification notification = new Notification("X", json_lat_lng);
Sender content = new Sender(notification,token.getToken());
mService.sendMessage(content)
.enqueue(new Callback<FCMResponse>() {
#Override
public void onResponse(Call<FCMResponse> call, Response<FCMResponse> response) {
if (response.body().success == 1)
{
Toast.makeText(MainActivity.this,"Request sent",Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(MainActivity.this,"Failed",Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<FCMResponse> call, Throwable t) {
Log.e("ERROR",t.getMessage());
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}

try this one please:
public interface IFCMService {
#Headers({"Content-Type:application/json",
"Authorization:key=" + "<YOUR SERVER KEY>"
})
#POST("fcm/send")
Call<FCMResponse> sendMessage(#Body Sender body);
}

Related

Working with access_token android retrofit?

In my application, I connect to a server and have to get a successful response to my further working, after such type of response, in general, I get two tokens ( access+refresh). For my further actions, I have to use my access token because I won't be able to get data. This token, in general, expires in 30 minutes. I can't understand how I can get a new token from the server without fails of my application. I had seen some questions and this Refreshing OAuth token using Retrofit without modifying all calls one was the best I think. But I can't understand the way of using it for me.
Right now I am using such an interface:
public interface APIService {
#Headers("Content-type: application/json")
#POST("/v1/login")
Call<Post> auth(#Body Post body);
#Headers({"Content-type: application/json",
"Authorization: Bearer access_token"})
#GET("/v1/message/list")
Call<Message> getInMess(#Query("type") int type, #Query("offset") int offset);
}
there I have to insert my access token by hands.
And then in my MainActivity Class I initialize my interface:
public void sendPost()
{
final EditText titleEt = findViewById(R.id.login);
final EditText bodyEt = findViewById(R.id.password);
final String a = titleEt.getText().toString().trim();
final String b = bodyEt.getText().toString().trim();
saveData();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://server/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
APIService mAPIService = retrofit.create(APIService.class);
//retrofit.create(APIService.class);
mAPIService.auth(new Post(a, b)).enqueue(new Callback<Post>() {
#Override
public void onResponse(#NonNull Call<Post> call, #NonNull Response<Post> response) {
if (response.isSuccessful()) {
Toast.makeText(LoginActivity.this, "Post submitted to API.", Toast.LENGTH_LONG).show();
Intent intent = new Intent(LoginActivity.this, SecondScreen.class);
findViewById(R.id.btn_submit).getBackground().setColorFilter(Color.parseColor("#1cd000"), PorterDuff.Mode.MULTIPLY);
startActivity(intent);
} else {
Toast.makeText(LoginActivity.this, "Unable to submit post to API.Error!!!", Toast.LENGTH_LONG).show();
findViewById(R.id.btn_submit).getBackground().setColorFilter(Color.parseColor("#FF0000"), PorterDuff.Mode.MULTIPLY);
}
}
#Override
public void onFailure(#NonNull Call<Post> call, #NonNull Throwable t) {
Toast.makeText(LoginActivity.this, "Unable to submit post to API.", Toast.LENGTH_LONG).show();
}
});
}
Please help me to understand the strategy of my further development because I can't solve my problem.
P.S. Sorry for my bad English))
You need to intercept the request and add the header in your interceptor. I use this in my applications :
public class AuthenticationInterceptor implements Interceptor {
public AuthenticationInterceptor(Context context) {
}
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if(!YOUR_TOKEN.isEmpty()) {
Request authenticatedRequest = request.newBuilder().header("Authorization", "Bearer:" + YOUR_TOKEN).build();
return chain.proceed(authenticatedRequest);
}
return chain.proceed(request);
}
}

Retrofit2 NULL response in onResponse even when Data is not NULL

So, my problem is fairly straightforward.
This is the response I am getting through the API call.
D/OkHttp: {"status":"error","status_code":"500","error_msg":"There was an error trying to send the password reset email."}
<-- END HTTP (220-byte body)
This is my code to handle the calls
Call<PasswordReset> forgotPasswordCall = apiInterface.Reset(email);
forgotPasswordCall.enqueue(new Callback<PasswordReset>() {
#Override
public void onResponse(Call<PasswordReset> call, Response<PasswordReset> response) {
PasswordReset passwordReset = response.body();
try {
if (passwordReset.getStatusCode() != null && passwordReset.getStatusCode().equals("200")) { //line 133
Log.d("Success", "Password Reset Email Sent");
new CustomToast().showToast(getContext(), view, "Password Email sent");
new LoginActivity().replaceFragment("left");
} else {
String test = passwordReset.getStatusCode();
Log.d("Failure", test);
hideDialog();
}
}
catch (Exception e){
e.printStackTrace();
hideDialog();
}
}
#Override
public void onFailure(Call<PasswordReset> call, Throwable t) {
Log.d("Failure", "Password Reset Email Not Sent");
new CustomToast().showToast(getContext(), view, "Email Not Sent");
new LoginActivity().replaceFragment("left");
hideDialog();
}
});
And this is the exception I am catching
W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String in.siddhant.anetpays_customer.POJO.PasswordReset.getStatusCode()' on a null object reference
at in.siddhant.anetpays_customer.Login.Fragments.ForgotPassword$1.onResponse(ForgotPassword.java:133)
How can my response be null if I am getting some data ?
PasswordReset.class
public class PasswordReset {
#SerializedName("data")
private String data;
#SerializedName("status_code")
private String statusCode;
#SerializedName("status")
private String status;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
Retrofit Client
public static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl("http://xsdf/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
API_Interface
#FormUrlEncoded
#POST("/ddd/pwdresetrequest")
Call<PasswordReset>Reset(#Field("email")String email);
P.S - The API itself has some problem and always returns "status":"error" but this shouldn't affect the application, right ? Also I am happy to share more code.
Thanks in advance.
Solution
I am posting the solution as suggested as per the accepted answer, Hope it helps someone who comes looking.
forgotPasswordCall.enqueue(new Callback<PasswordReset>() {
#Override
public void onResponse(Call<PasswordReset> call, Response<PasswordReset> response) {
if (!response.isSuccessful()){
Gson gson = new Gson();
PasswordReset passwordReset1 = gson.fromJson(response.errorBody().charStream(), PasswordReset.class);
if (passwordReset1.getStatusCode().equals("500")){
new CustomToast().showToast(getContext(), view, "Password Email not sent");
hideDialog();
}
else {
Thread.dumpStack();
hideDialog();
}
}
else if (response.isSuccessful()) {
Log.d("Success", "Password Reset Email Sent");
new CustomToast().showToast(getContext(), view, "Password Email sent");
new LoginActivity().replaceFragment("left");
}
As for the theory, onResponse method of retrofit2 is called when we get some response and onFailure is called when the process of establishing and receiving a response is not met. I had overlooked this simple fact.
So, if someone does come looking and reading still, I will suggest you to also check your response.body() if its successful or not.
Happy Coding!
From the retrofit's javadoc for Response you can read that body() returns the deserialized response from a successful response. Unfortunately, seems like you have an unsuccessful response, given that you seem to receive a 500.
errorBody() is what you want to use. However, this returns the raw response, so you'll have to deserialize it yourself.
There's a lot of ways you can do this. One might be using gson to deserialize the body:
new Gson().fromJson(response.errorBody().body().string(), YourModel.class);
PS: Just because you end up on onResponse it doesn't mean you have a successful response. However, from your code it seems you already know this and are checking for the http status 200.

retrofit 2 post rxjava (login)

I'm new using retrofit2 and rxjava, i was able to use GET to get information from api's but now, using POST for a login request is not working how is suposed too.
Application application = Application.get(mLoginView.getContext());
Service Service = application.getmService();
Log.i(TAG,""+username);
Log.i(TAG,""+password);
mSubscription = Service.login(username,password)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<User>() {
#Override
public void onCompleted() {
Log.i(TAG,"User: " + mUser.getHash());
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
Log.i(TAG,"USERNAME DON'T EXIST");
}
#Override
public void onNext(User user) {
// LoginPresenter.this.mUser = user;
}
});
Service:
public interface Service {
String mUrl = "https://blabla.com/api/index.php/"; // TODO Change
#FormUrlEncoded
#POST("user/login")
Observable<User> login(#Field(value="email",encoded=true) String email, #Field(value="password",encoded = true) String password );
I enter a POST with username and pass from an existing user and return me a 404 page and not the hash im supposed to get.
Thank you
I forgot this was here, I found a solutions months ago, and what i did was create a object UserCredentials to do the body request and a object to get the response.
#POST("user/login")
Observable<LoginResponse> login(#Body UserCredentials userCredentials);

POST with Retrofit

I am creating a simple log-in/register app, consuming predefined JSON-structured data. So far I have created the GET endpoint (using retrofit)
public interface RetrofitGet {
#GET("----")
Call<User> getUserDetails();
}
EDIT: the POST endPoint:
#POST("----")
Call<User> postUserDetails();
Then I have a method, taking the entered JSON-like data and set the data as text of 2 of the fields:
private void getUser() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitGet service = retrofit.create(RetrofitGet.class);
Call<User> call = service.getUserDetails();
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Response<User> response, Retrofit retrofit) {
try {
input_email.setText(response.body().getEmail());
input_pass.setText(response.body().getPassword());
} catch (Exception e) {
Log.d("onResponse", "There is an error");
e.printStackTrace();
}
}
#Override
public void onFailure(Throwable t) {
Log.d("onFailure", t.toString());
}
});
What I am trying to do now is to define the POST endpoint, in order to be able the data to be generated from the app (to be taken from the register form), posted on the server, and then handled in the login.
EDIT:
The method, consuming the POST endpoint so far:
private void postUser() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitPost service = retrofit.create(RetrofitPost.class);
Call<User> call = service.postUserDetails();
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Response<User> response, Retrofit retrofit) {
try {
emailRegister.getText().toString();
passRegister.getText().toString();
} catch (Exception e) {
Log.d("onResponse", "There is an error");
e.printStackTrace();
}
}
So, I have the data, entered by the user on Register, but I don't see it stored in the server and cannot handle it in the Login part.
Any help would be appreciated,
Thanks!
#POST("----")
Call<CommonBean> comment(#Body PostComment comment);
and the PostComment:
public class PostComment {
private int pcOrdersId;
private int pcStar;
private String pcComment;
public PostComment(int pcOrdersId, int pcStar, String pcComment) {
this.pcOrdersId = pcOrdersId;
this.pcStar = pcStar;
this.pcComment = pcComment;
}
}
others on different with 'GET'

Retrofit2 POST request with Body

I need make POST request with parameters "guid=1" in Body. i use Retrofit2
I try :
#POST("/api/1/model")
Call<ApiModelJson> getPostClub(#Body User body);
User Class:
public class User {
#SerializedName("guid")
String guid;
public User(String guid ) {
this.guid = guid;
}
MailActivity:
User user =new User ("1");
Call<ApiModelJson> call = service.getPostClub(user);
call.enqueue(new Callback<ApiModelJson>() {
#Override
public void onResponse(Response<ApiModelJson> response) {
}
#Override
public void onFailure(Throwable t) {
dialog.dismiss();
}
How make this request?
you have to call call.enqueue, providing an instance of Callback< ApiModelJson>, where you will get the response. enqueue executes your backend call asynchronously. You can read more about call.enqueue here
With code below, you can make the request synchronously:
ApiModelJson responseBody = call.execute();
If you want it to be asynchronous:
call.enqueue(new Callback<ApiModelJson>() {
#Override
public void onResponse(Response<ApiModelJson> response, Retrofit retrofit) {
}
#Override
public void onFailure(Throwable t) {
}
});

Categories

Resources