-1

I want to use the retrofit interface like this.

public interface ApiInterface {

    @GET("test.php")
    Call<Person> getPerson(@Query("name") String keyword);
}

I have this error because I have squeezed and executed php like this.

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $

I want to use Call<Person>, I don't want to use Call<List<Person>>

Here's the php I made.

<?php

require_once 'conn.php';

if(isset($_GET['name'])) {
    $name = $_GET['name'];
    $query = "SELECT `NAME`, AGE, `ADDRESS` FROM test WHERE `NAME` = '$name'";
    $result = mysqli_query($conn, $query);

    $response = array();
    while($row = mysqli_fetch_assoc($result)) {
        array_push(
            $response, array(
                'name'=>$row['NAME'],
                'age'=>$row['AGE'],
                'address'=>$row['ADDRESS'])
            );
    }

    echo json_encode($response);
}

mysqli_close($conn);

?>

This is Person POJO.

public class Person {
    @SerializedName("name") private String name;
    @SerializedName("age") private int age;
    @SerializedName("address") private String address;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

I finally want to use it in MainActivity like this.

public class MainActivity extends AppCompatActivity {

    SearchView searchView;
    ApiInterface apiInterface;
    TextView nameText, ageText, addressText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        nameText = findViewById(R.id.nameText);
        ageText = findViewById(R.id.ageText);
        addressText = findViewById(R.id.addressText);

        searchView = findViewById(R.id.searchView);
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                personList(s);

                return false;
            }

            @Override
            public boolean onQueryTextChange(String s) {
                return false;
            }
        });
    }

    public void personList(String key) {
        apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
        Call<Person> call = apiInterface.getPerson(key);
        call.enqueue(new Callback<Person>() {
            @Override
            public void onResponse(Call<Person> call, Response<Person> response) {
                Person person = response.body();
                nameText.setText(person.getName());
                System.out.println("Name : " + person.getName());
            }

            @Override
            public void onFailure(Call<Person> call, Throwable t) {
                Log.e("onFailure", t.toString());
            }
        });
    }
}

I don't know how to modify it, not the arrangement.

luhai
  • 59
  • 6
  • In your API interface, try changing `@Query` to `@Field` – Indiana Sep 14 '20 at 06:18
  • Thank you, I've tried this, and I've tried @FormUrlEncoded, but both of them have errors. – luhai Sep 14 '20 at 06:22
  • Have you tested the call in Postman to see what the response looks like? From the error message `Expected BEGIN_OBJECT but was BEGIN_ARRAY` it could be returning an array of `Person` where as you are expecting an object – Indiana Sep 14 '20 at 06:33
  • Infact, looking at your php code, it is returning an array. – Indiana Sep 14 '20 at 06:33
  • Change your API service to return a list of objects rather than a single object: change `Call` to `Call>`. Note you will need to make changes to your main activity to reflect this – Indiana Sep 14 '20 at 06:34
  • Now the php returns the array. I don't know the php well, so I don't know how to modify it to return it to `Call`. – luhai Sep 14 '20 at 06:43
  • I don't use recyclerview, so I don't know how to get the position when I use `Call>`. What I'm making now is, when I search for a name, I get his name, age, and address and put it in each TextView. Sorry... – luhai Sep 14 '20 at 06:43
  • Your data is returning as a list of objects, not as an object. That has nothing to do with a recyclerview – Indiana Sep 14 '20 at 06:49
  • **Warning:** You are wide open to [SQL Injections](https://stackoverflow.com/a/60496/1839439) and should use parameterized **prepared statements** instead of manually building your queries. They are provided by [PDO](https://php.net/manual/pdo.prepared-statements.php) or by [MySQLi](https://php.net/manual/mysqli.quickstart.prepared-statements.php). Never trust any kind of input! Even when your queries are executed only by trusted users, [you are still in risk of corrupting your data](http://bobby-tables.com/). [Escaping is not enough!](https://stackoverflow.com/q/5741187) – Dharman Sep 14 '20 at 11:07

2 Answers2

1

As explained in comments, your issue is being caused because the API call is returning an array of Person, whereas you are expecting to receive a Person object. That's why the error states Expected BEGIN_OBJECT but was BEGIN_ARRAY

You can either:

A) change your php code to return one object and not an array.

OR

B) Change your Java code as follows:

ApiInterface

public interface ApiInterface {

    @GET("test.php")
    Call<List<Person>> getPerson(@Query("name") String keyword);
}

MainActivity

    public void personList(String key) {
        apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
        Call<List<Person>> call = apiInterface.getPerson(key);
        call.enqueue(new Callback<List<Person>>() {
            @Override
            public void onResponse(Call<List<Person>> call, Response<List<Person>> response) {
                // Check that the list of objects is not empty before trying to read first entry
                if (!response.body.isEmpty()) {
                    // Take the first entry in the List
                    Person person = response.body().get(0);
                    nameText.setText(person.getName());
                    System.out.println("Name : " + person.getName());
                }
               
            }

            @Override
            public void onFailure(Call<List<Person>> call, Throwable t) {
                Log.e("onFailure", t.toString());
            }
        });
    }

Lastly, I also believe the @Query should be changed to @Field

Indiana
  • 683
  • 7
  • 18
  • Wow! I was having such a big illusion! I thought `get(0)` would bring the 0th data of the table no matter what! Thank you very much! You are my savior! – luhai Sep 14 '20 at 07:03
0

I don't understand PHP, but jsonsyntaxexception is caused by JSON parsing error. You can try to print jsonstr in Android and then convert it. I hope it can help you

@GET("test.php")
Call getPerson(@Query("name") String keyword);