Hello I am an android developer and i have never before faced this problem before "Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $" i am suspecting the issue is in my model.
this is the postman response as is
{
"Status": 200,
"Message": "OK",
"Data": {
"ServiceTypes": [
{
"Id": 1,
"ServiceTypeNameAr": "صيانة",
"ServiceTypeNameEn": "Maintenance",
"MainServices": [
{
"Id": 11,
"ServiceTypeId": 1,
"MainServiceNameAr": "تكييفات\r\n",
"MainServiceNameEn": "Air conditioning\r\n",
"SubServices": null
},
{
"Id": 12,
"ServiceTypeId": 1,
"MainServiceNameAr": "كهرباء\r\n",
"MainServiceNameEn": "Electricity\r\n",
"SubServices": null
},
{
"Id": 14,
"ServiceTypeId": 1,
"MainServiceNameAr": "سباكة",
"MainServiceNameEn": "Plumbing\r\n",
"SubServices": null
},
{
"Id": 15,
"ServiceTypeId": 1,
"MainServiceNameAr": "اجهزة منزلية\r\n",
"MainServiceNameEn": "Home appliances\r\n",
"SubServices": null
}
]
}
]
}
}
i want to implement this as a pojo(model) in my code this is my try (Edited)
ResponseModel
public class ResponseModel {
#SerializedName("Status")
public int Status;
#SerializedName("Message")
public String Message;
#SerializedName("Data")
public DataModel Data;
public int getStatus() {
return Status;
}
public void setStatus(int status) {
Status = status;
}
public String getMessage() {
return Message;
}
public void setMessage(String message) {
Message = message;
}
public DataModel getData() {
return Data;
}
public void setData(DataModel data) {
this.Data = data;
}
}
DataModel
public class DataModel {
#SerializedName("Country")
private List<CountryModel> countryModels;
#SerializedName("Users")
private List<UserModel> users;
#SerializedName("Cities")
private List<CityItem> cityItems;
#SerializedName("ServiceTypes")
private List<ServiceTypeModel> serviceTypeModels;
private Map<String, Object> additionalProperties = new HashMap<String,
Object>();
public List<CityItem> getCityItems() {
return cityItems;
}
public void setCityItems(List<CityItem> cityItems) {
this.cityItems = cityItems;
}
public List<UserModel> getUsers() {
return users;
}
public void setUsers(ArrayList<UserModel> users) {
this.users = users;
}
public List<CountryModel> getCountryModels() {
return countryModels;
}
public void setCountryModels(ArrayList<CountryModel> countryModels) {
this.countryModels = countryModels;
}
public List<ServiceTypeModel> getServiceTypeModels() {
return serviceTypeModels;
}
public void setServiceTypeModels(List<ServiceTypeModel> serviceTypeModels) {
this.serviceTypeModels = serviceTypeModels;
}
public void setCountryModels(List<CountryModel> countryModels) {
this.countryModels = countryModels;
}
public void setUsers(List<UserModel> users) {
this.users = users;
}
public Map<String, Object> getAdditionalProperties() {
return additionalProperties;
}
public void setAdditionalProperties(Map<String, Object> additionalProperties) {
this.additionalProperties = additionalProperties;
}
}
ServiceTypeModel
public class ServiceTypeModel {
#SerializedName("Id")
private int id;
#SerializedName("ServiceTypeNameAr")
private String serviceTypeNameAr;
#SerializedName("ServiceTypeNameEn")
private String serviceTypeNameEn;
#SerializedName("MainServices")
private List<MainServicesModel> mainServicesList;
public List<MainServicesModel> getMainServicesList() {
return mainServicesList;
}
public void setMainServicesList(List<MainServicesModel> mainServicesList) {
this.mainServicesList = mainServicesList;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getServiceTypeNameAr() {
return serviceTypeNameAr;
}
public void setServiceTypeNameAr(String serviceTypeNameAr) {
this.serviceTypeNameAr = serviceTypeNameAr;
}
public String getServiceTypeNameEn() {
return serviceTypeNameEn;
}
public void setServiceTypeNameEn(String serviceTypeNameEn) {
this.serviceTypeNameEn = serviceTypeNameEn;
}
}
The Interface:
public interface ServiceTypeInterface {
#GET("ServiceType")
public Call<ResponseModel> GetServicesType(#Header("authorization") String token);
#GET("ServiceType/{id}")
public Call<ResponseModel> GetServiceTypeById(#Path("id") int Id, #Header("authorization") String token);
}
Adapter
public class ServiceTypeAdapter extends RecyclerView.Adapter<ServiceTypeAdapter.ServiceTypeHolder> {
private List<ResponseModel> serviceTypeModels = new ArrayList<>();
private final ServiceTypeListener listener;
private Context context;
public ServiceTypeAdapter(ServiceTypeListener listener, Context context, List<ResponseModel> serviceTypeList) {
this.listener = listener;
this.context = context;
this.serviceTypeModels = serviceTypeList;
}
#NonNull
#Override
public ServiceTypeHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_sub_service, parent, false);
return new ServiceTypeHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ServiceTypeHolder holder, int position) {
final ResponseModel ServiceType = serviceTypeModels.get(position);
holder.TxtServiceTypeName.setText(ServiceType.getData().getServiceTypeModels().get(0).getServiceTypeNameEn());
}
#Override
public int getItemCount() {
return serviceTypeModels.size();
}
public long getItemId(int position) {
return position;
}
public void setList(List<ResponseModel> serviceTypeModels) {
// serviceTypeModels = new List<ResponseModel>(serviceTypeModels.get(0).getData().getServiceTypeModels().get(0).getServiceTypeNameEn());
this.serviceTypeModels = serviceTypeModels;
notifyDataSetChanged();
}
public class ServiceTypeHolder extends RecyclerView.ViewHolder {
TextView TxtServiceTypeName;
public ServiceTypeHolder(#NonNull View itemView) {
super(itemView);
TxtServiceTypeName = itemView.findViewById(R.id.ServiceTypeName);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listener.onServiceTypeSelected(serviceTypeModels.get(getAdapterPosition()));
}
});
}
}
public interface ServiceTypeListener {
void onServiceTypeSelected(ResponseModel serviceTypeModel);
}
}
i tried to separate them as well into two models the status, message and data which calls for the services type which is in another model.
if anything else or more clarification is needed pls don't hesitate to ask me for code or anything.
any help is really appreciated.
Thanks in advance.
you may implement pojo as this:
this class represent the top level object:
public class ResponseModel {
private Integer Status;
private String Message;
private DataModel Data;
// getters, setters, constructors
}
this class represents Data class:
public class DataModel {
private List<ServiceTypeModel> ServiceTypes;
// getters, setters, constructors
}
and this class maps with ServiceTypes
public class ServiceTypeModel {
private Long Id;
private String ServiceTypeNameAr;
private String ServiceTypeNameEn;
private List<MainServiceModel> MainServices;
// getters, setters, constructors
}
And finally this class maps with MainServices
public class MainServiceModel{
private Long Id;
private Long ServiceTypeId;
private String MainServiceNameAr;
private String MainServiceNameEn;
private List<SubServiceModel> SubServices;
// getters, setters, constructors
}
for SubServices, you have provided null so I imagine this is a List of SubServiceModel. You can implement this class like how I did for the others.
Also you can use some online tools to generate pojo of a json like this
I think the problem is with your ServiceTypeWebEntity model where you set data as a list but it's an object which has ServiceTypes key with List<ServiceTypeModel> inside, so you can try this model.
public class ServiceTypeWebEntity {
#SerializedName("Status")
private int Status;
#SerializedName("Message")
private String Message;
#SerializedName("data")
public ServiceTypes ServicesType;
public int getStatus() {
return Status;
}
public void setStatus(int status) {
Status = status;
}
public String getMessage() {
return Message;
}
public void setMessage(String message) {
Message = message;
}
public ServiceTypes getServicesType() {
return ServicesType;
}
public void setServicesType(ServiceTypes servicesType) {
ServicesType = servicesType;
}
public class ServiceTypes{
#SerializedName("ServiceTypes")
public List<ServiceTypeModel> ServicesType;
public List<ServiceTypeModel> getServicesType() {
return ServicesType;
}
public void setServicesType(List<ServiceTypeModel> servicesType) {
ServicesType = servicesType;
}
}
public class ServiceTypeModel {
#SerializedName("Id")
private int id;
#SerializedName("ServiceTypeNameAr")
private String serviceTypeNameAr;
#SerializedName("ServiceTypeNameEn")
private String serviceTypeNameEn;
#SerializedName("MainServices")
private List<MainServicesModel> mainServicesList;
public List<MainServicesModel> getMainServicesList() {
return mainServicesList;
}
public void setMainServicesList(List<MainServicesModel> mainServicesList) {
this.mainServicesList = mainServicesList;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getServiceTypeNameAr() {
return serviceTypeNameAr;
}
public void setServiceTypeNameAr(String serviceTypeNameAr) {
this.serviceTypeNameAr = serviceTypeNameAr;
}
public String getServiceTypeNameEn() {
return serviceTypeNameEn;
}
public void setServiceTypeNameEn(String serviceTypeNameEn) {
this.serviceTypeNameEn = serviceTypeNameEn;
}
}
}
hope it helps.
I knew where i was wrong i was missing a small part in my main for calling the list itself here is the main for anyone who needs it or anyone facing the same issue
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_categories);
//
TestTxt = findViewById(R.id.TestTxt);
serviceTypeViewModel = ViewModelProviders.of(this).get(ServiceTypeViewModel.class);
serviceTypeViewModel.GetServiceType();
serviceTypeRecycler = findViewById(R.id.ServiceTypeRV);
// LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
// serviceTypeRecycler.setLayoutManager(layoutManager);
// serviceTypeRecycler.setItemAnimator(new DefaultItemAnimator());
// serviceTypeRecycler.setAdapter(serviceTypeAdapter);
FillListServices();
}
private void FillListServices() {
serviceTypeViewModel.ServiceTypeMutableLiveData.observe(this, new Observer<ResponseModel>() {
// Here i was trying to call the ServiceTypeModel instead
#Override
public void onChanged(ResponseModel responseModel) {
Utilities.dismissLoadingDialog();
serviceTypeModelArrayList = new ArrayList<>();
serviceTypeModelArrayList = responseModel.getData().getServiceTypeModels();
TestTxt.setText(responseModel.getData().getServiceTypeModels().get(0).getServiceTypeNameAr());
serviceTypeAdapter = new ServiceTypeAdapter(responseModel.getData().getServiceTypeModels());
LinearLayoutManager layoutManager = new LinearLayoutManager(MainCategories.this, LinearLayoutManager.HORIZONTAL, false);
serviceTypeRecycler.setLayoutManager(layoutManager);
serviceTypeRecycler.setAdapter(serviceTypeAdapter);
}
});
}
Related
I want to get the value from the nested json and using retrofit. The value for both LicenseCDL and LicenseVDL classes are null. How to get the data from both array? Where did I missing from the java class?
This is the Json looks like.
{
"data": {
"LicenseCDL": [
{
"class_code": "B2",
"invoice_num": "W1007INV20051",
"total": "1484.00",
"created_at": "2020-05-18 08:56:13"
}
],
"LicenseVDL": [
{
"class_code": "PSV VAN",
"invoice_num": "W1007INV20052",
"total": "583.00",
"created_at": "2020-05-18 10:12:13"
}
]
},
"status": "1",
"message": "record found."
}
This is LicenseClassModel
public class LicenseClassModel {
#SerializedName("LicenseCDL")
private List<LicenseCDL> LicenseCDL;
#SerializedName("LicenseVDL")
private List<LicenseVDL> LicenseVDL;
#SerializedName("message")
private String message;
#SerializedName("status")
private String status;
public List<LicenseClassModel.LicenseCDL> getLicenseCDL() {
return LicenseCDL;
}
public List<LicenseClassModel.LicenseVDL> getLicenseVDL() {
return LicenseVDL;
}
public String getMessage() {
return message;
}
public String getStatus() {
return status;
}
public static class LicenseCDL {
#SerializedName("class_code")
private String classCode;
#SerializedName("data")
private List<LicenseDataItem> data;
public String getClassCode() {
return classCode;
}
public List<LicenseDataItem> getData() {
return data;
}
}
public static class LicenseVDL {
#SerializedName("class_code")
private String classCode;
#SerializedName("data")
private List<LicenseDataItem> data;
public String getClassCode() {
return classCode;
}
public List<LicenseDataItem> getData() {
return data;
}
}
This is method that I want to get the value
private void callLicenseApi() {
Call<LicenseClassModel> CheckCall = apiInterface.LICENSE_CLASS_LIST_CALL(String.valueOf(UserData.getId()));
CheckCall.enqueue(new Callback<LicenseClassModel>() {
#Override
public void onResponse(#NonNull Call<LicenseClassModel> call, #NonNull Response<LicenseClassModel> response) {
Log.i("???","value cdl: " + response.body().getLicenseCDL()); //output: value cdl: null
Log.i("???","value vdl: " + response.body().getLicenseVDL()); //output: value cdl: null
}
#Override
public void onFailure(Call<LicenseClassModel> call, Throwable t) {
Log.i("???","Erorr : " + t.getMessage());
}
});
}
LicenseCDL and LicenseVDL are inside "data" key So you need to Update the Classes
public class LicenseClassModel {
#SerializedName("data")
#Expose
private Data data;
#SerializedName("status")
#Expose
private String status;
#SerializedName("message")
#Expose
private String message;
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
public class Data {
#SerializedName("LicenseCDL")
#Expose
private List<LicenseCDL> licenseCDL = null;
#SerializedName("LicenseVDL")
#Expose
private List<LicenseVDL> licenseVDL = null;
public List<LicenseCDL> getLicenseCDL() {
return licenseCDL;
}
public void setLicenseCDL(List<LicenseCDL> licenseCDL) {
this.licenseCDL = licenseCDL;
}
public List<LicenseVDL> getLicenseVDL() {
return licenseVDL;
}
public void setLicenseVDL(List<LicenseVDL> licenseVDL) {
this.licenseVDL = licenseVDL;
}
}
I solved this by changing the model class to this.
public class LicenseClassModel {
#SerializedName("data")
private LicensePerantaraan data;
#SerializedName("message")
private String message;
#SerializedName("status")
private String status;
public LicensePerantaraan getData() {
return data;
}
public String getMessage() {
return message;
}
public String getStatus() {
return status;
}
public static class LicensePerantaraan {
#SerializedName("LicenseCDL")
private List<LicenseDataItem> LicenseCDL;
#SerializedName("LicenseVDL")
private List<LicenseDataItem> LicenseVDL;
public List<LicenseClassModel.LicenseDataItem> getLicenseCDL() {
return LicenseCDL;
}
public List<LicenseClassModel.LicenseDataItem> getLicenseVDL() {
return LicenseVDL;
}
}
public static class LicenseDataItem {
#SerializedName("class_code")
private String classCode;
#SerializedName("invoice_num")
private String invoiceNum;
#SerializedName("total")
private double total;
#SerializedName("created_at")
private String createdAt;
public String getClassCode() {
return classCode;
}
public String getInvoiceNum() {
return invoiceNum;
}
public double getTotal() {
return total;
}
public String getCreatedAt() {
return createdAt;
}
}
}
And after that I call this method in the adapter. Using the array and using method addAll, before using that method, clear the array 1st.
private void callLicenseApi() {
licenseDataItemArrayList.clear();
Call<LicenseClassModel> CheckCall = apiInterface.LICENSE_CLASS_LIST_CALL(String.valueOf(UserData.getId()));
CheckCall.enqueue(new Callback<LicenseClassModel>() {
#Override
public void onResponse(#NonNull Call<LicenseClassModel> call, #NonNull Response<LicenseClassModel> response) {
if (response.code() == 200) {
if (response.body() != null)
if (response.body().getStatus().equals("1")) {
if (response.body().getData().getLicenseCDL().size() != 0) {
licenseDataItemArrayList.addAll(response.body().getData().getLicenseCDL());
licenseDataItemArrayList.addAll(response.body().getData().getLicenseVDL());
licenseClassAdapter = new LicenseClassAdapter(con, licenseDataItemArrayList, new RecyclerViewBaseAdapter.ItemSelectedListener<LicenseClassModel.LicenseDataItem>() {
#Override
public void onItemSelected(LicenseClassModel.LicenseDataItem listItem) {
}
});
tvNoRecordFound.setVisibility(View.GONE);
rv.setVisibility(View.VISIBLE);
rv.setLayoutManager(new LinearLayoutManager(con));
rv.setAdapter(licenseClassAdapter);
} else {
rv.setVisibility(View.GONE);
tvNoRecordFound.setVisibility(View.VISIBLE);
}
} else {
Toast.makeText(con, getString(R.string.record_not_found), Toast.LENGTH_SHORT).show();
tvNoRecordFound.setVisibility(View.VISIBLE);
}
} else {
Toast.makeText(con, getString(R.string.record_not_found), Toast.LENGTH_SHORT).show();
tvNoRecordFound.setVisibility(View.VISIBLE);
}
lytProgress.setVisibility(View.GONE);
}
#Override
public void onFailure(Call<LicenseClassModel> call, Throwable t) {
callAPiForLog(TAG, t.getMessage());
Toast.makeText(con, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
I've tried to set values inside movies ArrayList in BlogRepository class.
but I couldn't find the results in the end.
I want to modify the example so that the storage inside the ArrayList is movies.
so the example works and the results show then the example works.
json data :
[
{
"albumId": 1,
"id": 1,
"title": "accusamus beatae ad facilis cum similique qui sunt",
"url": "https://via.placeholder.com/600/92c952",
"thumbnailUrl": "https://via.placeholder.com/150/92c952"
},
{
"albumId": 1,
"id": 2,
"title": "reprehenderit est deserunt velit ipsam",
"url": "https://via.placeholder.com/600/771796",
"thumbnailUrl": "https://via.placeholder.com/150/771796"
},
{
"albumId": 1,
"id": 3,
"title": "officia porro iure quia iusto qui ipsa ut modi",
"url": "https://via.placeholder.com/600/24f355",
"thumbnailUrl": "https://via.placeholder.com/150/24f355"
}
]
Code:
//
public class BlogRepository {
private ArrayList<Blog2> movies = new ArrayList<>();
private MutableLiveData<List<Blog2>> mutableLiveData = new MutableLiveData<>();
private Application application;
public BlogRepository(Application application){
this.application = application;
}
public MutableLiveData<List<Blog2>> getMutableLiveData() {
RestApiService service = RetrofitInstance.getApiService();
Call<List<BlogWrapper>> call = service.getPopularBlog();
call.enqueue(new Callback<List<BlogWrapper>>(){
#Override
public void onResponse(Call<List<BlogWrapper>> call, Response<List<BlogWrapper>> response) {
List<BlogWrapper> mBlogWrapper = response.body();
for (int i=0; i<mBlogWrapper.size(); i++) {
movies = (ArrayList<Blog2>) mBlogWrapper.get(i).getBlog();
//Log.d("trace_movies : ",""+ movies);
}
}
#Override
public void onFailure(Call<List<BlogWrapper>> call, Throwable t) {
// Toast.makeText(MainActivity.this, "Unable to load users", Toast.LENGTH_SHORT).show();
Log.e("trace_2",""+t.getMessage().toString());
}
});
return mutableLiveData;
}
}
//
public class Blog2 {
#SerializedName("albumId")
private int albumId;
#SerializedName("id")
private int id;
#SerializedName("title")
private String title;
#SerializedName("url")
private String url;
#SerializedName("thumbnailUrl")
private String thumbnailUrl;
public void setAlbumId(int albumId) {
this.albumId = albumId;
}
public void setId(int id) {
this.id = id;
}
public void setTitle(String title) {
this.title = title;
}
public void setUrl(String url) {
this.url = url;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
public int getAlbumId() {
return albumId;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public String getUrl() {
return url;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
}
///
public class BlogWrapper {
#SerializedName("data")
private List<Blog2> mData;
#SerializedName("error")
private Boolean mError;
#SerializedName("message")
private String mMessage;
#SerializedName("status")
private String mStatus;
public List<Blog2>getBlog() {
return mData;
}
public void setBlog(List<Blog2> data) {
mData = data;
}
public Boolean getError() {
return mError;
}
public void setError(Boolean error) {
mError = error;
}
public String getMessage() {
return mMessage;
}
public void setMessage(String message) {
mMessage = message;
}
public String getStatus() {
return mStatus;
}
public void setStatus(String status) {
mStatus = status;
}
}
///
public interface RestApiService {
#GET("/photos")
public Call<List<BlogWrapper>> getPopularBlog();
}
//
public class RetrofitInstance {
private static Retrofit retrofit = null;
public static final String BASE_URL_ = "https://jsonplaceholder.typicode.com/albums/1/";
// public static final String BASE_URL_ = "https://androidwave.com/api/";
public static RestApiService getApiService() {
Gson gson = new GsonBuilder().setLenient().create();
if (retrofit == null) {
retrofit = new retrofit2.Retrofit
.Builder()
.baseUrl(BASE_URL_)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit.create(RestApiService.class);
}
}
Try this code, sorry i am away from laptop... mybe you can understand from this. I just swich response object as List<Blog2>, because you need it
call.enqueue(new Callback<List<Blog2>>(){
#Override
public void onResponse(Call<List<Blog2>> call, Response<List<Blog2>> response) {
List<Blog2> mBlogWrapper = response.body();
for (int i=0; i<mBlogWrapper.size(); i++) {
movies.add(mBlogWrapper.get(i));
//Log.d("trace_movies : ",""+ movies);
}
}
});
now you have values from the List, then you can store its value to MutableLivedata.
Also don't forget to change your Retrofit method
public interface RestApiService {
#GET("/photos")
public Call<List<Blog2>> getPopularBlog();
}
I'm trying to use New York Times API with Retrofit using Observable. But I'm getting this error when trying to use datas.
Can someone help me see where I'm wrong, please ?
Here is my ApiServices interface:
#GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
Observable<TopStoryResult> getTopStories();
#GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
Observable<List<NewsItem>> getResults();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.nytimes.com/")
.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
Here is my ApiStreams class
public static Observable<TopStoryResult> streamFetchTopStories(){
ApiServices mApiServices = ApiServices.retrofit.create(ApiServices.class);
return mApiServices.getTopStories()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.timeout(10, TimeUnit.SECONDS);
}
public static Observable<List<NewsItem>> streamFetchNews(){
ApiServices mApiServices = ApiServices.retrofit.create(ApiServices.class);
return mApiServices.getResults()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.timeout(10, TimeUnit.SECONDS);
}
And this is what I'm trying to do in my MainActivity. For now I just want to display in a TextView the list of each Title...
//------------------------
// Update UI
//------------------------
private void updateUIWhenStartingHttpRequest() {
this.textView.setText("Downloading...");
}
private void updateUIWhenStopingHttpRequest(String response) {
this.textView.setText(response);
}
//------------------------
// Rx Java
//------------------------
private void executeRequestWithRetrofit(){
this.updateUIWhenStartingHttpRequest();
this.disposable = ApiStreams.streamFetchNews()
.subscribeWith(new DisposableObserver<List<NewsItem>>(){
#Override
public void onNext(List<NewsItem> topStories) {
Log.e("TAG", "On Next");
updateUIWithResult(topStories);
}
#Override
public void onError(Throwable e) {
Log.e("ERROR", Log.getStackTraceString(e));
}
#Override
public void onComplete() {
Log.e("TAG", "On Complete !");
}
});
}
private void updateUIWithResult(List<NewsItem> newsItemList){
StringBuilder mStringBuilder = new StringBuilder();
for (NewsItem news : newsItemList){
Log.e("TAG", "UPDATE UI" + news.getTitle());
mStringBuilder.append("- " + news.getTitle() + "\n");
}
updateUIWhenStopingHttpRequest(mStringBuilder.toString());
}
[EDIT]
There are my two models for TopStories and NewsItem
TopStories:
private String status;
private String copyright;
private String section;
private String lastUpdated;
private Integer numResults;
private List<NewsItem> results = null;
public String getStatus() {return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCopyright() {
return copyright;
}
public void setCopyright(String copyright) {
this.copyright = copyright;
}
public String getSection() {
return section;
}
public void setSection(String section) {
this.section = section;
}
public String getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(String lastUpdated) {
this.lastUpdated = lastUpdated;
}
public Integer getNumResults() {
return numResults;
}
public void setNumResults(Integer numResults) {
this.numResults = numResults;
}
public List<NewsItem> getResults() {
return results;
}
public void setResults(List<NewsItem> results) {
this.results = results;
}
NewsItem:
private String section;
private String subsection;
private String title;
private String url;
private String byline;
private String updated_date;
private String created_date;
private String published_date;
private String material_type_facet;
private String kicker;
#SerializedName("abstract")
private String abstract_string;
private List<Multimedia> multimedia;
private transient String des_facet;
private transient String org_facet;
private transient String per_facet;
private transient String geo_facet;
public NewsItem() {
}
public NewsItem(String url) {
this.url = url;
}
public NewsItem(String section, String subsection, String title, String url, String byline, String updated_date, String created_date, String published_date, String material_type_facet, String kicker) {
this.section = section;
this.subsection = subsection;
this.title = title;
this.url = url;
this.byline = byline;
this.updated_date = updated_date;
this.created_date = created_date;
this.published_date = published_date;
this.material_type_facet = material_type_facet;
this.kicker = kicker;
}
public String getSection() {
return section;
}
public void setSection(String section) {
this.section = section;
}
public String getSubsection() {
return subsection;
}
public void setSubsection(String subsection) {
this.subsection = subsection;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getByline() {
return byline;
}
public void setByline(String byline) {
this.byline = byline;
}
public String getUpdated_date() {
return updated_date;
}
public void setUpdated_date(String updated_date) {
this.updated_date = updated_date;
}
public String getCreated_date() {
return created_date;
}
public void setCreated_date(String created_date) {
this.created_date = created_date;
}
public String getPublished_date() {
return published_date;
}
public void setPublished_date(String published_date) {
this.published_date = published_date;
}
public String getMaterial_type_facet() {
return material_type_facet;
}
public void setMaterial_type_facet(String material_type_facet) {
this.material_type_facet = material_type_facet;
}
public String getKicker() {
return kicker;
}
public void setKicker(String kicker) {
this.kicker = kicker;
}
public String getAbstract() {
return abstract_string;
}
public void setAbstract(String abstract_string) {
this.abstract_string = abstract_string;
}
public List<Multimedia> getMultimedia() {
return multimedia;
}
public void setMultimedia(List<Multimedia> multimedia) {
this.multimedia = multimedia;
}
public String getDes_facet() {
return des_facet;
}
public void setDes_facet(String des_facet) {
this.des_facet = des_facet;
}
public String getOrg_facet() {
return org_facet;
}
public void setOrg_facet(String org_facet) {
this.org_facet = org_facet;
}
public String getPer_facet() {
return per_facet;
}
public void setPer_facet(String per_facet) {
this.per_facet = per_facet;
}
public String getGeo_facet() {
return geo_facet;
}
public void setGeo_facet(String geo_facet) {
this.geo_facet = geo_facet;
}
Here is what the JSON looks like:
JSON
First when I tried this one with Github user API, it works fine. But I can't figure out where I'm wrong there...
Is anybody can help me please ?
Thanks a lot !
Expected BEGIN_ARRAY but was BEGIN_OBJECT
this means you are trying to a get a JSON Array as a List in JAVA but the api sent you a JSON OBJECT. So I cannot gather enough information but if I have to guess you should change this
#GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
Observable<List<NewsItem>> getResults();
to
#GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
Observable<NewsItemObject> getResults();
NewsItemObject is the Class that wraps NewsItem
In your ApiServices interface you expect that getResults() returns Observable<List<NewsItem>>. Based on JSON you getting back this is not gonna work, because your root JSON element is Object, not an Array.
You have to create new wrapper Class (ResultsWrapper) with "results" field type of List<NewsItem>. Your method in ApiServices interface will then be:
#GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
Observable<ResultsWrapper> getResults();
That is what "Expected BEGIN_ARRAY but was BEGIN_OBJECT" says to you.
I starting out with RxJava and Retrofit and wanted to create a simple app to show a list of 100 cryptocurrencies.
I am making an api call which results in something like this :
{
"Response": "Success",
"Message": "Coin list succesfully returned!",
"BaseImageUrl": "https://www.cryptocompare.com",
"BaseLinkUrl": "https://www.cryptocompare.com",
"Data": {
"LTC": {
"Id": "3808",
"Url": "/coins/ltc/overview",
"ImageUrl": "/media/19782/ltc.png",
"Name": "LTC",
"CoinName": "Litecoin",
"FullName": "Litecoin (LTC)",
"Algorithm": "Scrypt",
"ProofType": "PoW",
"SortOrder": "2"
}
...
},
"Type": 100
}
But all I want from this is "Response" and "Data". Since it is not practical to create a 100 different model classes for each coin, I want to store information of all the coins in a common class named Coin which would look something like this :
public class Coins {
#SerializedName("Algorithm")
private String mAlgorithm;
#SerializedName("CoinName")
private String mCoinName;
#SerializedName("FullName")
private String mFullName;
#SerializedName("FullyPremined")
private String mFullyPremined;
#SerializedName("Id")
private String mId;
#SerializedName("ImageUrl")
private String mImageUrl;
#SerializedName("Name")
private String mName;
#SerializedName("PreMinedValue")
private String mPreMinedValue;
#SerializedName("ProofType")
private String mProofType;
#SerializedName("SortOrder")
private String mSortOrder;
#SerializedName("Sponsored")
private Boolean mSponsored;
#SerializedName("Symbol")
private String mSymbol;
#SerializedName("TotalCoinSupply")
private String mTotalCoinSupply;
#SerializedName("TotalCoinsFreeFloat")
private String mTotalCoinsFreeFloat;
#SerializedName("Url")
private String mUrl;
public String getAlgorithm() {
return mAlgorithm;
}
public void setAlgorithm(String Algorithm) {
mAlgorithm = Algorithm;
}
public String getCoinName() {
return mCoinName;
}
public void setCoinName(String CoinName) {
mCoinName = CoinName;
}
public String getFullName() {
return mFullName;
}
public void setFullName(String FullName) {
mFullName = FullName;
}
public String getFullyPremined() {
return mFullyPremined;
}
public void setFullyPremined(String FullyPremined) {
mFullyPremined = FullyPremined;
}
public String getId() {
return mId;
}
public void setId(String Id) {
mId = Id;
}
public String getImageUrl() {
return mImageUrl;
}
public void setImageUrl(String ImageUrl) {
mImageUrl = ImageUrl;
}
public String getName() {
return mName;
}
public void setName(String Name) {
mName = Name;
}
public String getPreMinedValue() {
return mPreMinedValue;
}
public void setPreMinedValue(String PreMinedValue) {
mPreMinedValue = PreMinedValue;
}
public String getProofType() {
return mProofType;
}
public void setProofType(String ProofType) {
mProofType = ProofType;
}
public String getSortOrder() {
return mSortOrder;
}
public void setSortOrder(String SortOrder) {
mSortOrder = SortOrder;
}
public Boolean getSponsored() {
return mSponsored;
}
public void setSponsored(Boolean Sponsored) {
mSponsored = Sponsored;
}
public String getSymbol() {
return mSymbol;
}
public void setSymbol(String Symbol) {
mSymbol = Symbol;
}
public String getTotalCoinSupply() {
return mTotalCoinSupply;
}
public void setTotalCoinSupply(String TotalCoinSupply) {
mTotalCoinSupply = TotalCoinSupply;
}
public String getTotalCoinsFreeFloat() {
return mTotalCoinsFreeFloat;
}
public void setTotalCoinsFreeFloat(String TotalCoinsFreeFloat) {
mTotalCoinsFreeFloat = TotalCoinsFreeFloat;
}
public String getUrl() {
return mUrl;
}
public void setUrl(String Url) {
mUrl = Url;
}
}
So finally my mapped response class would look like :
public class CoinsListResponse {
private boolean success;
private List<Coins> coinsList;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public List<Coins> getCoinsList() {
return coinsList;
}
public void setCoinsList(List<Coins> coinsList) {
this.coinsList = coinsList;
}
}
I haven't added #Serialized notations because I don't know what key to annotate it with.
My Retrofit service interface has a method to return the results to this map :
public interface CoinService {
#NonNull
#POST
Observable<CoinsListResponse> getCoinList();
}
Since, I am a starter with Retrofit and RxAndroid, there might be a better method to do this, which I am not aware of. If so, please mention that as well !! I am trying to get my head around this for days but couldn't find any answer on SO as well.
Please Help !!
Change
private List<Coins> coinsList;
to
#SerializedName("Data")
private Map<String, Coins> coinsByName;
You can then either just use coinsByName.values() or call e.g. coinsByName.get("LTC")
I want to get data from the server (https://data.egov.kz/api/v2/zheke_zhane_zandy_tulgalardy_k1/v6?pretty) as an array of json objects. But I get this Log:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
I am using Retrofit2 and here my code:
MainActivity.java
public class MainActivity extends AppCompatActivity
implements GetAdmissionSchedule.GetAdmissionScheduleInterface {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GetAdmissionSchedule getAdmissionSchedule = new GetAdmissionSchedule(this);
getAdmissionSchedule.getAdmissionScheduleList();
}
#Override
public void getAdmissionSchedule(List<AdmissionSchedule> admissionScheduleList) {
// here i get my data
}
}
GetAdmissionSchedule.java
public class GetAdmissionSchedule {
private GetAdmissionScheduleInterface getAdmissionScheduleInterface;
public GetAdmissionSchedule(GetAdmissionScheduleInterface getAdmissionScheduleInterface) {
this.getAdmissionScheduleInterface = getAdmissionScheduleInterface;
}
public interface GetAdmissionScheduleInterface {
void getAdmissionSchedule(List<AdmissionSchedule> admissionScheduleList);
}
public void getAdmissionScheduleList() {
DataEgovApi service = DataEgovBaseURL.getRetrofit();
Call<List<AdmissionSchedule>> call = service.getAdmissionScheduleList();
call.enqueue(new Callback<List<AdmissionSchedule>>() {
#Override
public void onResponse(Call<List<AdmissionSchedule>> call, Response<List<AdmissionSchedule>> response) {
Log.d("MyLogs", "MVD: getAdmissionScheduleList " + response.code());
getAdmissionScheduleInterface.getAdmissionSchedule(response.body());
}
#Override
public void onFailure(Call<List<AdmissionSchedule>> call, Throwable t) {
Log.d("MyLogs", "MVD: getAdmissionScheduleList " + t.getLocalizedMessage());
getAdmissionScheduleInterface.getAdmissionSchedule(null);
}
});
}
}
DataEgovBaseURL.java
public class DataEgovBaseURL {
private static final String BASE_URL = "https://data.egov.kz/";
private static Retrofit retrofit = null;
public static DataEgovApi getRetrofit() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit.create(DataEgovApi.class);
}
}
DataEgovApi.java
public interface DataEgovApi {
#GET("api/v2/zheke_zhane_zandy_tulgalardy_k1/v6?pretty")
Call<List<AdmissionSchedule>> getAdmissionScheduleList();
}
AdmissionSchedule.java (My POJO class)
public class AdmissionSchedule {
#SerializedName("id")
#Expose
private String id;
#SerializedName("vremia")
#Expose
private String vremia;
#SerializedName("adres_ru")
#Expose
private String adresRu;
#SerializedName("doljnost_ru")
#Expose
private String doljnostRu;
#SerializedName("name_ru")
#Expose
private String nameRu;
#SerializedName("data")
#Expose
private String data;
#SerializedName("adres_kz")
#Expose
private String adresKz;
#SerializedName("doljnost_kz")
#Expose
private String doljnostKz;
#SerializedName("name_kz")
#Expose
private String nameKz;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getVremia() {
return vremia;
}
public void setVremia(String vremia) {
this.vremia = vremia;
}
public String getAdresRu() {
return adresRu;
}
public void setAdresRu(String adresRu) {
this.adresRu = adresRu;
}
public String getDoljnostRu() {
return doljnostRu;
}
public void setDoljnostRu(String doljnostRu) {
this.doljnostRu = doljnostRu;
}
public String getNameRu() {
return nameRu;
}
public void setNameRu(String nameRu) {
this.nameRu = nameRu;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getAdresKz() {
return adresKz;
}
public void setAdresKz(String adresKz) {
this.adresKz = adresKz;
}
public String getDoljnostKz() {
return doljnostKz;
}
public void setDoljnostKz(String doljnostKz) {
this.doljnostKz = doljnostKz;
}
public String getNameKz() {
return nameKz;
}
public void setNameKz(String nameKz) {
this.nameKz = nameKz;
}
}
You server url is https and certificate is already not valid.
Change https to http and it will work.
Else you can install valid SSL certificate on the server.