Retrofit go to onFailure while incorrect data input - java

I'm using Retrofit in Android to login with POST method to server with API and response it back. When I insert the data that already have in the server to login it will go to onResponse but when I insert the data that have no in the server in will to go onFailure but in my API I handled when have no data it will response status False. This is the message when it go to onFailure:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 56 path $.data
SignInService.java
public interface SignInService {
#FormUrlEncoded
#POST("api/signIn/")
Call<SignInRespone> signIn(#Field("email") String email,
#Field("password") String password);
}
SignInResponse.java
public class SignInRespone {
#SerializedName("success")
private boolean success;
#SerializedName("message")
private String message;
#SerializedName("data")
private Data data;
public boolean getSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public static class Data {
#SerializedName("id")
private int id;
#SerializedName("username")
private String username;
#SerializedName("email")
private String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
}
SignInRequest.java
public class SignInRequest {
#SerializedName("email")
private String email;
#SerializedName("password")
private String password;
public SignInRequest(String email, String password) {
this.email = email;
this.password = password;
}
}
SignInActivity.java
public void signIn(){
signInService = ServiceGenerator.createService(SignInService.class);
Call<SignInRespone> call= signInService.signIn("jonh1#gmail.com","12345");
call.enqueue(new Callback<SignInRespone>() {
#Override
public void onResponse(Call<SignInRespone> call, Response<SignInRespone> response) {
Log.e(">>>>",response.body().getData().getEmail());
startActivity(new Intent(getApplicationContext(), MainActivity.class));
finish();
}
#Override
public void onFailure(Call<SignInRespone> call, Throwable t) {
Log.e(">>>>", t.toString());
}
});
}

As per comment when you have logged in success fully server returns correct object that's why no exception, but when email is not present on server it returns data[] instead of data object that's why you are getting exception because you are expecting an object but server returned an array.
Solution:
return data:null form server if email not exists

Related

retrofit2.Call com.application.Example.Api.api_v2.BaseApiService.getUsermember(java.lang.String)' on a null object reference

I save JWT tokens in SharedPrefManager as Header. And I want to retrieve the username data but on a null object reference.
but why is SharedPrefManager.getSP_Token r (java.lang.String) 'on a null object reference. After that, I will take this member ID as another transaction
Error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.application.example, PID: 24805
java.lang.NullPointerException: Attempt to invoke interface method 'retrofit2.Call com.application.Example.Api.api_v2.BaseApiService.getUsermember(java.lang.String)' on a null object reference
at com.application.Example.Akun.FragmentAkun.getUsername(FragmentAkun.java:301)
at com.application.Example.Akun.FragmentAkun.onCreateView(FragmentAkun.java:105)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2439)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:802)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
at androidx.fragment.app.FragmentManagerImpl$1.run(FragmentManager.java:733)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7091)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
FeagmentAkun.java
private void getUsername(){
Call<ResultItem> getUser = mApiService.getUsermember(sharedPrefManager.getSPToken());
getUser.enqueue(new Callback<ResultItem>() {
#Override
public void onResponse(Call<ResultItem> call, Response<ResultItem> response) {
if (response.code() == 200) {
Toast.makeText(getActivity(), response.body().getEmail(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResultItem> call, Throwable t) {
}
});
}
ApiServices.java
//getUserMember
#GET("system/users/{id}")
Call<ResultItem> getUsermember(#Header("Authorization") String result);
ResultItem.java
public class ResultItem{
#SerializedName("password")
private String password;
#SerializedName("pin")
private String pin;
#SerializedName("verifiedMember")
private Object verifiedMember;
#SerializedName("profile")
private Profile profile;
#SerializedName("id")
private String id;
#SerializedName("msisdn")
private String msisdn;
#SerializedName("email")
private String email;
#SerializedName("sso")
private String sso;
#SerializedName("username")
private String username;
#SerializedName("token")
private Object token;
public void setPassword(String password){
this.password = password;
}
public String getPassword(){
return password;
}
public void setPin(String pin){
this.pin = pin;
}
public String getPin(){
return pin;
}
public void setVerifiedMember(Object verifiedMember){
this.verifiedMember = verifiedMember;
}
public Object getVerifiedMember(){
return verifiedMember;
}
public void setProfile(Profile profile){
this.profile = profile;
}
public Profile getProfile(){
return profile;
}
public void setId(String id){
this.id = id;
}
public String getId(){
return id;
}
public void setMsisdn(String msisdn){
this.msisdn = msisdn;
}
public String getMsisdn(){
return msisdn;
}
public void setEmail(String email){
this.email = email;
}
public String getEmail(){
return email;
}
public void setSso(String sso){
this.sso = sso;
}
public String getSso(){
return sso;
}
public void setUsername(String username){
this.username = username;
}
public String getUsername(){
return username;
}
public void setToken(Object token){
this.token = token;
}
public Object getToken(){
return token;
}
}

Pass parameters with Retrofit with Field

I'm following a retrofit course in which I create a small backend with an api in which I have a POST method to perform a teacher's login. In the course what he does is create a teacher and with the set method he passes him the email and the password, which is what this method receives in the API.
I would like to do it in such a way that in the call to Retrofit you pass directly this email and password and I have done it in the following way:
public class LoginActivity extends AppCompatActivity {
private EditText etPasswordLogin, etEmailLogin;
private Button btLogin;
private TextView tvSignUp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
setupView();
}
private void setupView() {
etPasswordLogin = findViewById(R.id.loginEditTextPassword);
etEmailLogin = findViewById(R.id.loginEditTextEmail);
btLogin = findViewById(R.id.buttonSignUp);
tvSignUp = findViewById(R.id.textViewSignUp);
btLogin.setOnClickListener(v -> userSignUp());
tvSignUp.setOnClickListener(v -> startActivity(new Intent(getApplicationContext(), SignUpActivity.class)));
}
private void userSignUp() {
String email = etEmailLogin.getText().toString().trim();
String password = etPasswordLogin.getText().toString().trim();
if (email.isEmpty()) {
etEmailLogin.setError(getResources().getString(R.string.email_error));
etEmailLogin.requestFocus();
return;
}
if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
etEmailLogin.setError(getResources().getString(R.string.email_doesnt_match));
etEmailLogin.requestFocus();
return;
}
if (password.isEmpty()) {
etPasswordLogin.setError(getResources().getString(R.string.password_error));
etPasswordLogin.requestFocus();
return;
}
if (password.length() < 4) {
etPasswordLogin.setError(getResources().getString(R.string.password_error_less_than));
etPasswordLogin.requestFocus();
return;
}
login(email, password);
}
private void login(String email, String password) {
String BASE_URL = "http://10.0.2.2:8040";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
WebServiceApi api = retrofit.create(WebServiceApi.class);
Call<List<Profesor>> call = api.login(email, password);
call.enqueue(new Callback<List<Profesor>>() {
#Override
public void onResponse(Call<List<Profesor>> call, Response<List<Profesor>> response) {
if (response.code() == 200) {
Log.d("TAG1", "Profesor logeado");
} else if (response.code() == 404) {
Log.d("TAG1", "Profesor no existe");
} else {
Log.d("TAG1", "Error desconocido");
}
}
#Override
public void onFailure(Call<List<Profesor>> call, Throwable t) {
Log.d("TAG Error: ", Objects.requireNonNull(t.getMessage()));
}
});
}
}
And this would be my model teacher:
public class Profesor {
#SerializedName("id")
private Long id;
#SerializedName("nombre")
private String nombre;
#SerializedName("email")
private String email;
#SerializedName("password")
private String password;
#SerializedName("foto")
private String photo;
public Profesor(){}
public Profesor(Long id, String nombre, String email, String photo) {
this.id = id;
this.nombre = nombre;
this.email = email;
this.photo = photo;
}
public Profesor(String email, String password){
this.email = email;
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
}
Finally the call to Retrofit that I make is the following:
#FormUrlEncoded
#POST("api/login")
Call<List<Profesor>> login(#Field("email") String email, #Field("password") String password);
However when I run the application and pass through the form the email and password, in the log I return "Error desconocido", however in postman gives me answer without problems:
Any idea what I'm doing wrong?
Your postman request is not a form-urlencoded, but raw.
You need to send a json as a request, and not a field. So to fix this, you may change your API, to handle form-urlencoded requests, or change the Android code this way.
public class LoginCredentials {
#SerializedName("email")
private String email;
#SerializedName("password")
private String password;
public LoginCredentials(String email, String password) {
this.email = email;
this.password = password;
}
}
and change this
#FormUrlEncoded
#POST("api/login")
Call<List<Profesor>> login(#Field("email") String email, #Field("password") String password);
to this
#POST("api/login")
Call<List<Profesor>> login(#Body LoginCredentials credentials);
Hope this will help.

App is posting data Successfully, But I would like to retrieve token

Am using retrofit and RxJava to Connect to API. Data is being successfully posted to Server but i would like to get the Token which the API generates after posting data.
This is for Authentication of user using a JSON Web Token Django Backend
The models are working fine but Here are my Models:
public class User {
#SerializedName("user")
#Expose
private User_ user;
public User_ getUser() {
return user;
}
public void setUser(User_ user) {
this.user = user;
}
#Override
public String toString() {
return new ToStringBuilder(this).append("user", user).toString();
}
}
public class User_ {
#SerializedName("email")
#Expose
private String email;
#SerializedName("password")
#Expose
private String password;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Override
public String toString() {
return new ToStringBuilder(this).append("email", email).append("password", password).toString();
}
}
#SerializedName("user")
#Expose
private LoginResponse_ user;
public LoginResponse_ getUser() {
return user;
}
public void setUser(LoginResponse_ user) {
this.user = user;
}
#Override
public String toString() {
return new ToStringBuilder(this).append("user", user).toString();
}
}
public class LoginResponse_ {
#SerializedName("email")
#Expose
private String email;
#SerializedName("token")
#Expose
private String token;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
#Override
public String toString() {
return new ToStringBuilder(this).append("email", email).append("token", token).toString();
}
}
Retrofit Interface
#POST("auth/login")
#Headers("X-Requested-With:XMLHttpRequest")
Observable<User> login(
#Header("Content-Type") String content_type,
#Body User user
);
}
Retrofit Adapter
public class ServiceGenerator {
private static Retrofit retrofit;
private static Gson gson;
public static synchronized Retrofit getUser() {
if (retrofit == null) {
if (gson == null) {
gson = new GsonBuilder().setLenient().create();
}
retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
Retrofit Instance
public class NetworkUtils {
private static UserService userService;
public static UserService ApiInstance(){
if (userService == null){
userService = ServiceGenerator.getUser().create(UserService.class);
}
return userService;
}
}
This is how am trying to login the user
private void loginProcess(String email, String password) {
User user = new User();
User_ user_ = new User_();
user_.setEmail(email);
user_.setPassword(password);
user.setUser(user_);
mUserService.login("application/json", user)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<User>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(User user) {
showResponse(user.toString());
Log.i(TAG, "Response: "+ user);
mProgressBar.setVisibility(View.GONE);
handleResponse();
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onComplete() {
}
});
}
private void handleResponse(LoginResponse response) {
SharedPreferences.Editor editor = mSharedPreference.edit();
editor.putString(Constants.TOKEN,response.getUser().getToken());
editor.putString(Constants.EMAIL,response.getUser().getEmail());
editor.apply();
mEditTextEmail.setText(null);
mEditTextPassword.setText(null);
Intent intent = new Intent(getActivity(),ProfileActivity.class);
startActivity(intent);
}
It would be really helpful if i get to know how to get response after posting the data to the API.
Using postman this is what i post
{"user":{"email":"user#email.com", "password":"userpassword"}}
And this is the response I get
{
"user": {
"email": "user#email.com",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6NSwiZXhwIjoxNTY5MjI5NTgxfQ.S-1yZWNhx_TV8uay8PubGoq9XMpyTIn_ipG8A6DWTfE"
}
}

How to retrieve data using email from firebase realtime databse?

I have a database from firebase. I want to retrieve some data using a user's email. suppose user put his/her email if the email exists in the firebase database then it shows his/her username and password. I am not using firebase authentication, I am using firebase realtime database.
here is my database structure:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_forgate_password);
emailf = findViewById(R.id.emailf);
userf = findViewById(R.id.usernamef);
passwordf = findViewById(R.id.passwordf);
ok = findViewById(R.id.okbtn);
database = FirebaseDatabase.getInstance();
users = database.getReference("Users").child("emailAddress");
ok.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
signInMethod(emailf.getText().toString());
}
});
}
private void signInMethod(final String email) {
users.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
if (dataSnapshot.child("emailAddress").exists()){
if (dataSnapshot.child(user.getUserName()).exists()){
Toast.makeText(ForgatePassword.this,"User already exists",Toast.LENGTH_LONG).show();
}
}
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w("Tag", "Email not exists", error.toException());
}
});
}
here is my model class:
public class SignInUpModel {
private String fullName;
private String userName;
private String schoolName;
private String className;
private String division;
private String phnNumber;
private String emailAddress;
private String reference;
private String password;
public SignInUpModel() {
}
public SignInUpModel(String fullName, String userName, String schoolName, String className, String division, String phnNumber, String emailAddress, String reference, String password) {
this.fullName = fullName;
this.userName = userName;
this.schoolName = schoolName;
this.className = className;
this.division = division;
this.phnNumber = phnNumber;
this.emailAddress = emailAddress;
this.reference = reference;
this.password = password;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getDivision() {
return division;
}
public void setDivision(String division) {
this.division = division;
}
public String getPhnNumber() {
return phnNumber;
}
public void setPhnNumber(String phnNumber) {
this.phnNumber = phnNumber;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getReference() {
return reference;
}
public void setReference(String reference) {
this.reference = reference;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
How can I do this?
Using firebase database to create your own authentication system is not a good idea.
What you want to do will require you to allow read of every user's email password stored in database. This will be a huge security risk for your app as anyone can read all the email passwords in your database.
Firebase provides easy to use firebase authentication with many options to use. You can easily delegate the security to firebase auth and store your user's profile and data in db. This way you can also restrict data access for each user (which is why you want email password login for your app).
Please see the authentication documents of firebase: https://firebase.google.com/docs/auth
It will help you create your app without implementing your own auth and focus on actual features development.

Why the object is returned empty? Android. Retrofit2

Why the object is returned empty? Android. Retrofit2.
I have a class User:
public class User{
#SerializedName("LOGIN")
String login;
#SerializedName("PASSWORD")
String password;
#SerializedName("NAME")
String name;
#SerializedName("SURNAME")
String surname;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
}
This's my JSON:
[{
"LOGIN":"TEST",
"PASSWORD":"TEST",
"NAME":"TEST",
"SURNAME":"TEST"
}
]
Interface:
public interface Link {
#GET("93sZY0Xg")
Call<List<User>> listRepos();
}
and class LoginActivity where i use retrofit2:
public class LoginActivity extends AppCompatActivity implements Callback<List<User>>{
private Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://pastebin.com/raw/")
.build();
private Link service = retrofit.create(Link.class);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Call<List<User>> us = service.listRepos();
us.enqueue(this);
}
#Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
System.out.println(response.body());
System.out.println(response.code());
User us = response.body().get(0);
System.out.println(us.getName());
for(User m: response.body()){
System.out.println( m.getName());
}
}
#Override
public void onFailure(Call<List<User>> call, Throwable t) {
System.out.println(t.getLocalizedMessage());
}
}
I get this response: response.code() is 200;
I/System.out: [com.example.com.dataBase.User#b789a]
I tried getName from class User, but all variables is null.
Why are the values empty? Where's my mistakes?
Try following, expose annotation is important to set value in fields
#Expose
#SerializedName("movie_id")
private String movieId;
#Expose
#SerializedName("movie_name")
private String movieName;
#Expose
#SerializedName("movie_poster")
private String moviePoster;
#Expose
#SerializedName("movie_dialog_count")
private String movieDialogCount;

Categories

Resources