Search code examples
androidretrofitillegalstateexceptionretrofit2

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING


I have written a Login functionality and to communicate with web service I am using Retrofit but always getting "Failed"

Getting:

retrofit.RetrofitError: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $

LoginAPI.java:

public interface LoginApi {
    @FormUrlEncoded
    @POST("/retrofit_user/login.php")
    public void getlogin(
        @Field("username") String username,
        @Field("password") String password,
        Callback<User> response);
}

LoginActivity.java:

restAdapter = new RestAdapter.Builder().setEndpoint(ROOT_LOGIN).build();
restAdapter.setLogLevel(RestAdapter.LogLevel.FULL);
loginApi = restAdapter.create(LoginApi.class);

buttonlogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

  loginApi.getlogin(editTextUsername.getText().toString(),
  editTextPassword.getText().toString(), new Callback<User>() {

  @Override
  public void success(User s, Response response) {
     Toast.makeText(LoginActivity.this,"Logged In",Toast.LENGTH_LONG).show();

    if(s != null) {
       Log.d("name:", s.getName());
       Log.d("email:", s.getEmail());
       Log.d("id:", String.valueOf(s.getId()));
    }

  }

  @Override
  public void failure(RetrofitError error) {

       Log.d("error:", error.toString());
 Toast.makeText(LoginActivity.this,"Failed",Toast.LENGTH_LONG).show();
          }
      });
    }
});

User.java:

public class User {

    String name;
    String username;
    String password;
    String email;
    int id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    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;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

Log says

D/Retrofit: <--- HTTP 200 http://domain.info/retrofit_user/login.php (942ms)
D/Retrofit: : HTTP/1.1 200 OK
D/Retrofit: Connection: Keep-Alive
D/Retrofit: Content-Type: text/html; charset=UTF-8
D/Retrofit: Date: Sat, 20 Feb 2016 06:00:39 GMT
D/Retrofit: Keep-Alive: timeout=5, max=100
D/Retrofit: Server: Apache/2.4.16 (Unix) OpenSSL/1.0.1e-fips mod_bwlimited/1.4
D/Retrofit: Transfer-Encoding: chunked
D/Retrofit: X-Android-Received-Millis: 1455948038590
D/Retrofit: X-Android-Response-Source: NETWORK 200
D/Retrofit: X-Android-Selected-Transport: http/1.1
D/Retrofit: X-Android-Sent-Millis: 1455948037988
D/Retrofit: X-Powered-By: PHP/5.6.14
D/Retrofit: Done
D/Retrofit: <--- END HTTP (4-byte body)
D/error:: retrofit.RetrofitError: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
D/GraphicBuffer: create handle(0x55bb2e98) (w:256, h:66, f:1)
D/GraphicBuffer: close handle(0x55bb2e98) (w:256 h:66 f:1)

And here is my login.php script:

<?php

    $objConnect = mysql_connect("localhost","username","password");
    $objDB = mysql_select_db("database");

    /*** for sample */
    // $_POST["username"] = "sun";
    // $_POST["password"] = "live";

    $username = $_REQUEST['username'];
    $password = $_REQUEST['password'];

    $strSQL = "select * from test_users where username = '".$username."' and  password = '".$password."' ";

    $objQuery = mysql_query($strSQL);
    $intNumRows = mysql_num_rows($objQuery);

    if($intNumRows==0)
    {
    echo "Not Done" ;
    }
    else
    {
    echo "Done" ;
    }

    mysql_close($objConnect);
?>

Solution

  • The issue is, retrofit expects a JSON output that it can fit into User class from login.php, but all the login.php gives is "Not Done" or "Done".

    You have to make your php script output json in the following format,

    {
        "name": "name",
        "username": "username",
        "password": "password",
        "email": "email",
        "id": id
    }
    

    You have to edit the php code. It will be something like this,

    <?php
        $objConnect = mysql_connect("localhost","username","password");
        $objDB = mysql_select_db("database");
    
        /*** for sample */
        // $_POST["username"] = "sun";
        // $_POST["password"] = "live";
    
        $username = $_REQUEST['username'];
        $password = $_REQUEST['password'];
    
        $strSQL = "select * from test_users where username = '".$username."' and  password = '".$password."' ";
    
        $objQuery = mysql_query($strSQL);
        $intNumRows = mysql_num_rows($objQuery);
        if($intNumRows==0)
        {
            $response["success"] = 0;
            $response["name"] = "";
            $response["username"] = "";
            $response["password"] = "";
            $response["email"] = "";
            $response["id"] = 0;
        }
        else
        {
            $row = mysql_fetch_array($objQuery);
            $response["success"] = 1;
            $response["name"] = $row["name"];
            $response["username"] = $row["username"];
            $response["password"] = $row["password"];
            $response["email"] = $row["email"];
            $response["id"] = $row["id"];
        }
    
        mysql_close($objConnect);
    
        echo json_encode($response, JSON_NUMERIC_CHECK);
    ?>
    

    Also add a int success; field to User class and use it to validate the output. So your success method will be,

    @Override
    public void success(User s, Response response) {
        if(s != null && s.getSuccess() == 1) {
            Toast.makeText(LoginActivity.this,"Logged In",Toast.LENGTH_LONG).show();
            Log.d("name:", s.getName());
            Log.d("email:", s.getEmail());
            Log.d("id:", String.valueOf(s.getId()));
        } else {
            Toast.makeText(LoginActivity.this,"Invalid!",Toast.LENGTH_LONG).show();
        }
    
    }
    

    Update

    The id field is a int in database stil it returns id as a string. See this thread. Adding JSON_NUMERIC_CHECK to json_encode() in php will help.