my Json:
{
"status": "1",
"login": "sucess"
}
this is my model class:
public class LoginModel {
#SerializedName("status")
#Expose
private String status;
#SerializedName("login")
#Expose
private String login;
...}
this is my interface:
public interface RestInterface {
String url = "http://192.168.10.2/tourist/v1";
#FormUrlEncoded
#POST("/login")
Call<LoginModel> Login(#Field("email") String email,
#Field("pass") String passs);
}
this is my call method:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RestInterface.url)
.addConverterFactory(GsonConverterFactory.create())
.build();
//Creating Rest Services
final RestInterface restInterface = retrofit.create(RestInterface.class);
//Calling method to get check login
Call<LoginModel> response = restInterface.Login(Email.getText().toString(), Password.getText().toString());
response.enqueue(new Callback<LoginModel>() {
#Override
public void onResponse(Response<LoginModel> response, Retrofit retrofit) {
finish();
startActivity(getIntent());
Email.setText("");
Password.setText("");
LoginModel lm = response.body();
if ( lm.getStatus().equals("1")) { //login Success
Toast.makeText(LoginActivity.this, "Login In SuccessFully", Toast.LENGTH_SHORT).show();
Intent i = new Intent(LoginActivity.this,AfterLoginActivity.class);
startActivity(i);
} else if (lm.getStatus().equals("0")) // login failure
{
Toast.makeText(LoginActivity.this, "Invalid UserName/Password ", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Throwable t) {
finish();
startActivity(getIntent());
// String merror = error.getMessage();
Toast.makeText(LoginActivity.this, "try again", Toast.LENGTH_LONG).show(); }
});
Am getting null point exception at line => lm.getstatus().equals(1);
It was working fine before with retrofit 1.9 then I changed it into Retrofit 2 and am getting null point exception now!
https://inthecheesefactory.com/blog/retrofit-2.0/en has clarifications on on the new URL declaration pattern in Retrofit 2.0. It suggests
- Base URL: always ends with /
- #Url: DO NOT start with /
In your case the url might be interpreted as "http://192.168.10.2/login".
Try using
String url = "http://192.168.10.2/tourist/v1/";
and
#POST("login")
Related
i am implementing login web service. i am getting correct response if user email and password is correct. but i am getting null if email or password is incorrect. i want to get message sent from server if email or password is incorrect. My code is below.
Call<LoginResponse> call = RetrofitClient.getInstance().getApi().userLogin(email, password);
call.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
LoginResponse loginResponse = response.body();
System.out.println("body " + response.body());
System.out.println("response " + response.errorBody().toString());
sharedPrefManager.cancelDialog();
if (loginResponse != null) {
if (loginResponse.getSuccess()) {
sharedPrefManager.saveUser(loginResponse.getData(), password);
Intent intent = new Intent(SignIn.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
} else {
Toast.makeText(SignIn.this, loginResponse.getMessage(), Toast.LENGTH_SHORT).show();
}
} else {
SharedPrefManager.getInstance(SignIn.this).cancelDialog();
Toast.makeText(SignIn.this, response.message(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
sharedPrefManager.cancelDialog();
t.printStackTrace();
}
});
public class RetrofitClient {
private static final String BASE_URL = "my_base_url";
private static RetrofitClient mInstance;
private Retrofit retrofit;
OkHttpClient client = new OkHttpClient.Builder()
//.addInterceptor(new SpeechRecognitionIntercepter())
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS).build();
private RetrofitClient() {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized RetrofitClient getInstance() {
if (mInstance == null) {
mInstance = new RetrofitClient();
}
return mInstance;
}
public Apis getApi() {
return retrofit.create(Apis.class);
}
}
public interface Apis {
#FormUrlEncoded
#POST("login")
Call<LoginResponse> userLogin(#Field("email") String email, #Field("password") String password);
}
Unsuccessful login response is:
{
"success": false,
"message": "Username or Password is incorrect."
}
Successful response is:
{
"success": true,
"message": "",
"data": {
"token": "",
"name": "Gmail",
"picture": "",
"userid": 60,
"phone": "(111) 114-4444",
"email": "tahir123#gmail.com",
"company_name": null,
"st_address": "Gmail account, Satellite",
"location_id": 1,
"account_type": 2
}
}
It's not really clear from your code if you receive a 200 status even if the call fails, but from what you describe, it seems like you get another http status code.
If this is the case, Retrofit still calls the onResponse method, but response.isSuccessful() is false and the body will be accessible through the response.errorBody() method.
An easy way to get this is:
if(response.isSuccessful())
// Do what you are doing
else {
Gson gson = new Gson();
LoginResponse error = gson.fromJson(response.errorBody().string());
// Use the error variable now
}
There's a lot going on here. Let's start with why do you need manual deserialization. Retrofit doesn't automatically convert the error body for you, you need to do it yourself. Here I've chosen to create a Gson instance, which is not elegant, but serves the purpose.
I also chose to use string(). This method reads the entire response into memory and can crash for big responses. Calling it will drain the okhttp buffer, which means you won't be able to call it again (to the best of my knowledge), so keep it in a variable if you want to use it multiple times.
Hope this helps
I'm using Retrofit to communicate with REST API on Android, but I'm
getting a NullPointerException like below. I try using Postman,
the API is working fine and I get the response the login was working.
Error
Process: com.example.krish.webdemo, PID: 3064
java.lang.NullPointerException
at com.example.krish.webdemo.activities.LoginActivity$2.onResponse
Call<LoginResponse> call = RetrofitClient
.getInstance()
.getApi()
.userLogin(email, password);
call.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
LoginResponse loginResponse = response.body();
if (!loginResponse.isError()) {
Toast.makeText(LoginActivity.this, loginResponse.getMessage(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(LoginActivity.this, loginResponse.getMessage(), Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
}
I had a NullPointerException to my loginResponse, the '.isError()' was
showing null error
API interface
#FormUrlEncoded
#POST("userlogin")
Call<LoginResponse> userLogin(
#Field("email") String email,
#Field("password") String password
);
Retrofit instance
private static final String BASE_URL ="http://192.168.1.38/KrishApi/public/";
private static RetrofitClient mInstance;
private Retrofit retrofit;
private RetrofitClient() {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized RetrofitClient getInstance() {
if (mInstance == null) {
mInstance = new RetrofitClient();
}
return mInstance;
}
public Api getApi(){
return retrofit.create(Api.class);
}
JSON response
{
"error": false,
"message": "Login Successful",
"user": {
"id": 3,
"email": "pandi#gmail.com",
"name": "pandi",
"age": "22",
"college": "sec"
}
}
POJO class
public class LoginResponse {
private boolean error;
private String message;
private User user;
public LoginResponse(boolean error, String message, User user) {
this.error = error;
this.message = message;
this.user = user;
}
public boolean isError() {
return error;
}
public String getMessage() {
return message;
}
public User getUser() {
return user;
}
}
response.body() returns null if the response is not successful. So, you must always check if the response is successful or not inside the onResponse method.
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if (response.isSuccessful()){
LoginResponse loginResponse = response.body();
if (!loginResponse.isError()) {
Toast.makeText(LoginActivity.this, loginResponse.getMessage(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(LoginActivity.this, loginResponse.getMessage(), Toast.LENGTH_LONG).show();
}
} else{
ResponseBody errorBody = response.errorBody();
// check error.
}
}
"error": false,
NullPointerException is thrown when an application attempts to use an
object reference that has the null value.
You should check your response isSuccess() or not.
/** {#code true} if {#link #code()} is in the range [200..300). */
public boolean isSuccess() {
return rawResponse.isSuccessful(); }
if (response.isSuccess()) //isSuccessful()
{
LoginResponse loginResponse = response.body();
////
}
I'm working with JSON response which I can get from my server, at the beginning I have to log in at my application so I use such api:
#Headers("Content-type: application/json")
#POST("/v1/login")
Call<Post> auth(#Body Post body);
and also my POJO-class:
public class Post {
#SerializedName("username")
private String username;
#SerializedName("password")
private String password;
public Post(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername (String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
and after all initialize it at my mainactivity class:
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();
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);
saveData();
/* try {
String responseString = String.valueOf(response.body());
TextView txt = findViewById(R.id.post);
txt.setText(responseString);
}
catch (Exception e){
e.printStackTrace();
}*/
} 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();
}
});
}
as you can see I commented my trying to fetch some data from JSON response, in general, I would like to get my access token from the response and I also wouldn't like to create some classes for fetching if it is possible, because I have already initialized my retrofit at my MainActivity class. After logging in a can get my received and sent messages in JSON too, but I would like to insert this data into the simple listview. So I hope that somebody at this forum will help me with my problem. Sorry for my maybe bad English.
You have to understand that each Retrofit request is asynchronous, that means, it will eventually be executed while your application runs. You should use RxJava to help you with that, since you should use to observe the data you need to get from your API.
Important Note: Also updating UI in your response from retrofit might trigger exceptions due to not running in Main Thread.
Some useful links to implement what you need :
https://www.toptal.com/android/functional-reactive-android-rxjava
https://www.journaldev.com/20433/android-rxjava-retrofit
https://medium.com/3xplore/handling-api-calls-using-retrofit-2-and-rxjava-2-1871c891b6ae
I'm doing a side project and all I know is I should use Basic Authentication. Since I don't have experience using it, I found some stuff online and I want to ask you for your opinion, is this the right way to do it...
So, first thing is from Retrofit's documentation:
This is the Retrofit(network) setup:
public class RetrofitSetup {
public static final String API_BASE_URL = "----";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.build();
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(
Class<S> serviceClass, String username, String password) {
if (!TextUtils.isEmpty(username)
&& !TextUtils.isEmpty(password)) {
String authToken = Credentials.basic(username, password);
return createService(serviceClass, authToken);
}
return createService(serviceClass, null);
}
public static <S> S createService(
Class<S> serviceClass, final String authToken) {
if (!TextUtils.isEmpty(authToken)) {
AuthenticationInterceptor interceptor =
new AuthenticationInterceptor(authToken);
if (!httpClient.interceptors().contains(interceptor)) {
httpClient.addInterceptor(interceptor);
builder.client(httpClient.build());
retrofit = builder.build();
}
}
return retrofit.create(serviceClass);
}
}
And Authentication Interceptor:
public class AuthenticationInterceptor implements Interceptor {
private String authToken;
public AuthenticationInterceptor(String token) {
this.authToken = token;
}
#Override
public Response intercept(#NonNull Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.header("Authorization", authToken);
Request request = builder.build();
return chain.proceed(request);
}
}
This is my RetrofitSerive class:
public interface RetrofitService {
#GET("login")
Call<Void> basicLogin();
#GET("contact")
Call<List<Contacts>> getContacts(#Header("Authorization") String authkey);
#GET("product")
Call<List<Products>> getProducts(#Header("Authorization") String authkey);
}
And the class I found online for generating auth key:
public class Helper {
public static String getAuthToken(String username, String password) {
byte[] data = new byte[0];
try {
data = (username + ":" + password).getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "Failed to authenticate";
}
return "Basic " + Base64.encodeToString(data, Base64.NO_WRAP);
}
}
And I believe there is nothing to be changed here... So first thing is to login (check authentication), here is the couple of stuff I want to know how to do right:
private void login(final String username, final String password) {
RetrofitService loginService =
RetrofitSetup.createService(RetrofitService.class, username, password);
Call<Void> call = loginService.basicLogin();
call.enqueue(new Callback<Void>() {
#Override
public void onResponse(#NonNull Call<Void> call, #NonNull Response<Void> response) {
progressBar.setVisibility(View.GONE);
if (response.isSuccessful()) {
// user object available
editor.putString("username", username);
editor.putString("password", password);
editor.apply();
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
} else {
Toast.makeText(LoginActivity.this, response.message(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(#NonNull Call<Void> call, #NonNull Throwable t) {
progressBar.setVisibility(View.GONE);
Toast.makeText(LoginActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
If response is successfull, I save those credentials in SharedPreferences..
Next page shuld call another request, so I wonder if there is any difference if I send both username/password or auth key?
This is how I did it:
private void getContacts() {
prefs = getActivity().getSharedPreferences(KEY, MODE_PRIVATE);
String username = prefs.getString("username", null);
String password = prefs.getString("password", null);
RetrofitService loginService =
RetrofitSetup.createService(RetrofitService.class, Helper.getAuthToken(username, password));
Call<List<Contacts>> call = loginService.getContacts(Helper.getAuthToken(username, password));
call.enqueue(new Callback<List<Contacts>>() {
#Override
public void onResponse(#NonNull Call<List<Contacts>> call, #NonNull Response<List<Contacts>> response) {
if (response.isSuccessful()) {
kontaktiAdapter.setKontakti(response.body());
} else {
Toast.makeText(getActivity(), response.message(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(#NonNull Call<List<Contacts>> call, #NonNull Throwable t) {
Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
So in this call, instead of sending username/password to RetrofitSetup.createService, I'm sending Helper.getAuthToken(username, password) with username and password from SharedPreferences.
Is this the right way to do this? If you exit the app, in login screen I'm checking if SharedPreferences contains username/password and try login with those parameteres.. If I want to log out, I clear those parameters from SharedPreferences so next time user opens the app, SharedPreferences won't contain them, so user won't be logged in, he/she would have to type those again...
What are your thoughts about this, is there anything I should do differently?
Regards!
This is so far the easiest method i have ever tried for "Basic Authentication".
Use the below code to generate the auth header (API/Repository class)
var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")
Pass this as header to the webservice call (API/Repository class)
var retrofitCall = myWebservice.getNewsFeed(basic)
Add the basic header as parameter (Retrofit Webservice interface class)
#GET("newsfeed/daily")
fun getNewsFeed(#Header("Authorization") h1:String):Call<NewsFeedResponse>
Sorry, my code is in Kotlin, but can be easily translated to Java.
I'm creating an authorization app, where user registers and gets client_id, client_secret, access_token and refresh_token. I have one API where i need to do call. In that call I use my access_token. All works great. But the access_token expires after hour, so with refresh_token I'm updating my access_token, but the new access_token not works. When I'm doing call with this new access_token, the response body message is "expired access_token provided". In postman all works good. When I'm getting new access_token, in server visible only the access_token that i got from registration. So in server the access_token not updating. But when I'm doing this in postman, the access_token in server changes. So what's the problem, that in postman he updates the access_token, and in server the access_token changes, but when I'm updating in phone, the access_token in server not changes. I done debugging and i see that I'm getting new access_token. So where's the problem?
public interface SupportopApi {
//Post request for user register
#POST("/api/registration")
Call<ResponseBody> registrationRequest(#Body SupportopObjRegistration supportopObjRegistration);
//Post request for user activation
#POST("/api/getClientCD")
Call<ResponseBody> clientActivationRequest(#Body SupportopObjClient activate);
//Get request for getting token
#GET("/api/getToken")
Call<ResponseBody> getTokenRequest(#Query("grant_type") String grant_type,
#Query("client_id") String client_id,
#Query("client_secret") String client_secret,
#Query("email") String email,
#Query("password") String password);
//The call where i use my access_token
#GET("/api/getLanguages")
Call<ResponseBody> getLanguages(#Header("Content-Type") String json,
#Header("Authorization") String token,
#Header("Cache-Control") String cache);}
Here's the retrofit and OkHttpClient initialize part.
public class ApiClient {
private static ApiClient instance;
private SupportopApi supportopApi;
client.addInterceptor(new Interceptor() {
#Override
public Response intercept(#NonNull Chain chain) throws IOException {
Request request = chain.request();
request = request.newBuilder()
.build();
return chain.proceed(request);
}
});
supportopApi = new Retrofit.Builder()
.baseUrl(endpoint)
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(SupportopApi.class);
}
public static synchronized void initializeInstance(String endpoint) {
if (instance == null) {
instance = new ApiClient(endpoint);
}
}
public static synchronized ApiClient getInstance() {
if (instance == null) {
throw new IllegalStateException("PentairAPIClient has not been initialized.");
}
return instance;
}
public Call<ResponseBody> registration(SupportopObjRegistration supportopObjRegistration) {
return supportopApi.registrationRequest(supportopObjRegistration);
}
public Call<ResponseBody> activation(SupportopObjClient activate) {
return supportopApi.clientActivationRequest(activate);
}
public Call<ResponseBody> getToken(String grant_type, String client_id, String client_secret,
String email, String password) {
return supportopApi.getTokenRequest(grant_type, client_id, client_secret, email, password);
}
public Call<ResponseBody> getLanguage(String token) {
String new_token = "Bearer " + token;
return supportopApi.getLanguages("application/json", new_token, "no-cache");
}
}
Registration works great, so I'll show you only the login call.
public class LoginFragment extends BaseFragment {
private View mainView;
private ApiClient apiClient;
private EditText email, password;
private Button userLogin;
private SupportopObjClient supportopClientActivate;
#Override
public String toString() {
return "LoginFragment";
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mainView = inflater.inflate(R.layout.login_fragment, container, false);
init(mainView);
return mainView;
}
private void init(final View v) {
apiClient = ApiClient.getInstance();
email = (EditText) v.findViewById(R.id.login_email);
password = (EditText) v.findViewById(R.id.login_password);
userLogin = (Button) v.findViewById(R.id.user_login);
userLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
supportopClientActivate.setUsername("");
supportopClientActivate.setEmail(email.getText().toString());
supportopClientActivate.setPassword(password.getText().toString());
supportopClientActivate.setType("generic");
getClient();
}
});
}
public void getClient() {
Call<ResponseBody> callActive = apiClient.activation(supportopClientActivate);
callActive.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
//Parsing the data from Json to string
String data = response.body().string();
JSONObject obj = new JSONObject(data);
String client_id = obj.getString("client_id");
String client_secret = obj.getString("client_secret");
//Saving clientID and clientSecret in phone storage
SharedPreferencesManager.getInstance().setClientID(client_id);
SharedPreferencesManager.getInstance().setClientSecret(client_secret);
//Calling the tokenCall method to get access token and refresh token
loginCall(client_id, client_secret);
} catch (JSONException | IOException e) {
e.printStackTrace();
}
} else {
//if the response not successful
Toast.makeText(getActivity(), "user doesn't exist", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(getActivity(), "An error occurred", Toast.LENGTH_SHORT).show();
}
});
}
public void loginCall(String client_id, final String client_secret) {
Call<ResponseBody> token = apiClient.getToken("password", client_id, client_secret,
supportopClientActivate.getEmail(), supportopClientActivate.getPassword());
token.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
//Parsing the data from Json to string
String dataAccess = response.body().string();
JSONObject obj = new JSONObject(dataAccess);
String access_token = obj.getString("accessToken");
String refresh_token = obj.getString("refreshToken");
Toast.makeText(context, access_token, Toast.LENGTH_SHORT).show();
SharedPreferencesManager.getInstance().setAccessToken(access_token);
SharedPreferencesManager.getInstance().setRefreshToken(refresh_token);
Toast.makeText(context, SharedPreferencesManager.getInstance().getAccessToken(), Toast.LENGTH_SHORT).show();
} catch (IOException | JSONException e) {
e.printStackTrace();
}
} else {
Toast.makeText(getActivity(), "password or email are incorrect or doesn't exist",
Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(getActivity(), "An error occurred", Toast.LENGTH_SHORT).show();
}
});
}