I am using retrofit 2.0 Gson data not getting
When i check Postman i am getting response below
{
"name": "Yashodhan Communication",
"zone": "9-Belgaum",
"tsm_name": "Tarun Patil",
"asm_name": "Shivakumar Patil"
}
Error:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was
BEGIN_OBJECT at line 1 column 2 path $
APIClient Client
public static Retrofit getClient() {
retrofit = new Retrofit.Builder()
.baseUrl("http://vehiclerescue.in/ideadarpan_beta/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
This is Pojo class
public class Appuser_Pojoclass {
#SerializedName("name")
#Expose
private String name;
#SerializedName("zone")
#Expose
private String zone;
#SerializedName("tsm_name")
#Expose
private String tsm_name;
#SerializedName("asm_name")
#Expose
private String asm_name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getZone() {
return zone;
}
public void setZone(String zone) {
this.zone = zone;
}
public String getTsm_name() {
return tsm_name;
}
public void setTsm_name(String tsm_name) {
this.tsm_name = tsm_name;
}
public String getAsm_name() {
return asm_name;
}
public void setAsm_name(String asm_name) {
this.asm_name = asm_name;
}
}
Activity class
private void fetchAllAppUserdata()
{
progressBar.setVisibility(View.VISIBLE);
Log.d("getauthkeydisplay","**** "+Idea_Urban.getInstance().get_Authkeyvalues());
ideaInterface.get_AppUsers(Idea_Urban.getInstance().get_Authkeyvalues()).enqueue(new Callback<List<Appuser_Pojoclass>>() {
#Override
public void onResponse(Call<List<Appuser_Pojoclass>> call, Response<List<Appuser_Pojoclass>> response) {
if(app_users != null)
{
progressBar.setVisibility(View.INVISIBLE);
app_users.clear();
}
if(response.body()!=null) {
app_users.addAll(response.body());
Log.d("appuserresponce","***** "+response.body());
// app_userDetailsAdapter.notifyDataSetChanged();
}else
{
progressBar.setVisibility(View.INVISIBLE);
}
}
#Override
public void onFailure(Call<List<Appuser_Pojoclass>> call, Throwable t) {
Log.d("failure","**** ");
Log.d("printmetthodsfailure","faiure"+call.toString() + "\n " + t.toString());
progressBar.setVisibility(View.INVISIBLE);
}
});
}
I found some solution as google suggestion but i donot know how to achieve.
You problem is java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
So you should check you response of your code .
Your JSON response is JSONObject ,so you should use Call<Appuser_Pojoclass> call
Change
Call<List<Appuser_Pojoclass>> call
to
Call<Appuser_Pojoclass> call
The error is in the Call declaration,change
Call<List<Appuser_Pojoclass>>
with
Call<Appuser_Pojoclass>
Your retrofit call response type is <List<Appuser_Pojoclass>> but your API response is not a list of Appuser_Pojoclass, it is simply a single object of type Appuser_Pojoclass.
Change type from <List<Appuser_Pojoclass>> to Appuser_Pojoclass in your retrofit call
You probably defined your get_AppUsers method as something that returns Call<List<Appuser_Pojoclass>> instead of just Call<Appuser_Pojoclass> so it ends up looking for a JSON array, but then your response only contains a single JSON object which causes the error. Change get_AppUsers to return Call<Appuser_Pojoclass> and then change your callback accordingly and that should fix the problem.
Related
I have an example ,I want to understand some parts,In this exampl ,It was working fine ,but when I changed part
from:
call list<model>> method();
to:
call <model> method();
It caused an error ,What's the reason for that?
What is the difference between the two cases?
// MainActivity :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GetData service = RetrofitClient.getRetrofitInstance().create(GetData.class);
Call<RetroUsers> call = service.getAllUsers();
call.enqueue(new Callback<RetroUsers>() {
#Override
public void onResponse(Call<RetroUsers> call, Response<RetroUsers> response) {
Log.i("print", "" + response.body().getUser());
}
#Override
public void onFailure(Call<RetroUsers> call, Throwable t) {
Log.i("print", "Dont" + t.getMessage());
}
});
}
///Error message :
I/print: Dontjava.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
// interface GetData:
public interface GetData {
#GET("/users")
Call<RetroUsers>getAllUsers();
/*
#GET("/users")
Call<List<RetroUsers>> getAllUsers();
*/
}
// RetrofitClient :
public class RetrofitClient {
private static Retrofit retrofit;
private static final String BASE_URL = "https://jsonplaceholder.typicode.com";
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
// model class :
public class RetroUsers {
#SerializedName("name")
private String name;
public RetroUsers(String name) {
this.name = name;
}
public String getUser() {
return name;
}
public void setUser(String name) {
this.name = name;
}
}
This: Call<RetroUsers> getAllUsers();
will cause you an error because the getAllUsers() will return more than one records of RetroUsers. Due to which it requires you to provide it a type as List so that its datatype is set to List and it can then handle multiple records.
Go through basics of Core Java to better understand this.
In one case you tell the deserializer that you expect a single Model, in the other case you tell it to expect a list of models, aka a List<Model>. Depending on what data you actually get you need to use one or the oter.
Of course you can "hide" the List<...> within your model by not using List<Model> but:
public class MoreThanOneModel {
public List<Model> entries;
...
}
But that does not change the underlying reasoning.
I have an API which returns one of the following schemas:
Success (data found)
{
item_count: 83,
items_per_page: 25,
offset: 25,
items: [
{ ... },
{ ... },
{ ... },
...
]
}
Failure (no data found)
{
success: false,
error: {
code: 200,
message: "Server is busy"
}
}
I want to use Retrofit 2 with GSON to build a wrapper around this API and convert to POJOs, however I'm uncertain how to handle the fact that the API potentially returns two entirely different schemas. For now, I have the following classes:
public class PaginatedResponse<T> {
private int item_count;
private int items_per_page;
private int offset;
private List<T> items;
public PaginatedResponse<T>(int item_count, int items_per_page, int offset, List<T> items) {
this.item_count = item_count;
this.items_per_page = items_per_page;
this.offset = offset;
this.items = items;
}
public List<T> getItems() {
return this.items;
}
}
public class Item {
private int id;
private String name;
// ...
}
Then for my API interface I have:
public interface API {
#GET("items")
Call<PaginatedResponse<Item>> getItems();
}
Then finally to use this I tried to say:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost")
.addConverterFactory(GsonConverterFactory.create())
.build();
API api = retrofit.create(API.class);
api.getItems().enqueue(new retrofit2.Callback<PaginatedResponse<Broadcast>>() {
#Override
public void onResponse(Call<PaginatedResponse<Broadcast>> call, Response<PaginatedResponse<Broadcast>> response) {
Log.d("SUCCESS", response.body().getItems().toString());
}
#Override
public void onFailure(Call<PaginatedResponse<Broadcast>> call, Throwable t) {
Log.d("FAILURE", t.toString());
}
}
So long as no errors are thrown, this seems to work. But when an error is thrown, I get the following in Logcat and my app crashes:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
It seems like because the failure JSON lacks an items property, it's setting List<Item> items to null
It seems like because the failure JSON lacks an items property, it's setting List items to null
Yes, It is. You're getting NullPointerException , because you called toString() on a null object. This is an expected behavior.
Solution
As you have different schema for error and success, you need to create a model with both values. Below given a minimal example,
ResponseModel.java
class ResponseModel {
// ERROR
private final Boolean success;
private final Error error;
// SUCCESS
private final int item_count;
// more success values...
ResponseModel(Boolean success, Error error, int item_count) {
this.success = success;
this.error = error;
this.item_count = item_count;
}
public class Error {
private final int code;
private final String message;
private Error(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
public Boolean getSuccess() {
return success;
}
public Error getError() {
return error;
}
public int getItem_count() {
return item_count;
}
}
and in onResponse method, you can check if the response is success or not like this
ResponseModel responseModel = response.body();
if (responseModel.getError() == null) {
// success
doSomethingWithSuccess(responseModel.getItem_count())
} else {
// error
doSomethingWithError(responseModel.getError())
}
I'm using Retrofit to make API call, When I handle the response I get the next error (Need to get the data from the API call) -
Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
I don't know if I'm doing it right. Anyway here's my code.
Here's the url link: https://data.gov.il/api/
Retrofit call -
#GET("datastore_search?resource_id=2c33523f-87aa-44ec-a736-edbb0a82975e")
Call<Result> getRecords();
Retrofit base call -
private static Retrofit retrofit;
public static final String BASE_URL = "https://data.gov.il/api/action/";
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
Model class -
public class Result {
#SerializedName("include_total")
#Expose
private Boolean includeTotal;
#SerializedName("resource_id")
#Expose
private String resourceId;
#SerializedName("fields")
#Expose
private List<Field> fields = null;
#SerializedName("records_format")
#Expose
private String recordsFormat;
#SerializedName("records")
#Expose
private List<Record> records = null;
#SerializedName("limit")
#Expose
private Integer limit;
#SerializedName("_links")
#Expose
private Links links;
#SerializedName("total")
#Expose
private Integer total;
public Boolean getIncludeTotal() {
return includeTotal;
}
public void setIncludeTotal(Boolean includeTotal) {
this.includeTotal = includeTotal;
}
public String getResourceId() {
return resourceId;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
public List<Field> getFields() {
return fields;
}
public void setFields(List<Field> fields) {
this.fields = fields;
}
public String getRecordsFormat() {
return recordsFormat;
}
public void setRecordsFormat(String recordsFormat) {
this.recordsFormat = recordsFormat;
}
public List<Record> getRecords() {
return records;
}
public void setRecords(List<Record> records) {
this.records = records;
}
...
Main Activity -
RecallService service = RetrofitClientInstance.getRetrofitInstance().create(RecallService.class);
Call<Result> records = service.getRecords();
records.enqueue(new Callback<Result>() {
#Override
public void onResponse(Call<Result> call, Response<Result> response) {
Log.d(TAG, String.valueOf(response.body().getRecords().get(0).getId())); // ERROR
}
#Override
public void onFailure(Call<Result> call, Throwable t) {
Log.e(TAG, t.getMessage());
}
});
The response, which you are getting from the API, doesn't fit the Result POJO.
The response you get from API is like below:
{
"help": "https://data.gov.il/api/3/action/help_show?name=datastore_search",
"success": true,
"result": {...}
}
By using the Result POJO, you are assuming that you get the response as below, which is a json inside the actual response json, and is not what you actually receive. So, just create a POJO which fairly represents the actual response.
{
"include_total": true,
"resource_id": "2c33523f-87aa-44ec-a736-edbb0a82975e",
"fields": [...],
"records_format": "objects",
"records":[...]
}
Try making a class like below (set the annotations yourself):
class Resp{
Result result;
}
Replace the class Result with Resp, like below and other usages:
#GET("datastore_search?resource_id=2c33523f-87aa-44ec-a736-edbb0a82975e")
Call<Resp> getRecords();
Then, finally you can do:
response.body().getResult().getRecords()
The API link you've shared returns the response in the format below:
{"help": "https://data.gov.il/api/3/action/help_show?name=datastore_search", "success": true, "result": {...}}
You are setting the response object to be of type Result which is actually a sub-element within the root element help in the json response. response.body() would include help and the result would be it's sub-element. Since it is not parsed correctly, you're getting a null response.
You will need to include the root element in your model class and update the API call to use that class type as the response type.
I am use Retrofit 2. I use test JSON on http://ip.jsontest.com/.It is very simple JSON. Why I am take this error?
In real project i have this ERROR too, but i think, it is because I have very big JSON. And I thy use test JSON. Need HELP))
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
This is JSON
{
"ip": "54.196.188.78"
}
My Interface
public interface UmoriliApi {
#GET(".")
Call<List<Test>> getData();
}
My Test class
public class Test {
#SerializedName("ip")
#Expose
private String ip;
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
}
My API class
public class App extends Application {
private static UmoriliApi umoriliApi;
private Retrofit retrofit;
#Override
public void onCreate() {
super.onCreate();
retrofit = new Retrofit.Builder()
.baseUrl("http://ip.jsontest.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
umoriliApi = retrofit.create(UmoriliApi.class);
}
public static UmoriliApi getApi() {
return umoriliApi;
}
}
My MainActivity class
public class MainActivity extends AppCompatActivity {
private static final String TAG = "TAG";
List<Test> posts;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
posts = new ArrayList<>();
App.getApi().getData().enqueue(new Callback<List<Test>>() {
#Override
public void onResponse(Call<List<Test>> call, Response<List<Test>> response) {
posts.addAll(response.body());
Log.d(TAG, "onResponse: "+posts.size());
}
#Override
public void onFailure(Call<List<Test>> call, Throwable t) {
Log.d(TAG, "onFailure: ");
}
});
}
}
Basically you are expecting and Array but you received a JSON Object.
As Akash said in the comment:
Call<List<Test>> getData();
List<Test> is what you write when you expect and Array. You need to write Call<Test> for an object Test
You will also have to change the callback.
I am parsing the title correctly and displaying it in a listview. I cant seem to access the
String findMe;
seen below. Here are the two objects, sample response and my call.
response pojo:
public class Response {
public String count;
public Result []results;
}
first object
public class Result {
public String title;
public static arr [] Details;
second object
public class Details {
public Integer _id;
public String findMe;
}
response:
Call<Response> call = api.getListWith(API_KEY);
call.enqueue(new Callback<Response>() {
#Override
public void onResponse(Call<Response> call, Response<Response> response) {
result = response.body();
}
I am getting the title just by passing 'result' into the adapter and using
result[i].getTitle();
I tried using
result[i].Details[0].findMe;
but my error response is:
java.lang.NullPointerException: Attempt to read from null array
public class Result {
public String title;
public Details[] arr;
}
Then
results[i].getarr[0].getfindMe();