I have some problem about retrofit2
How to fix Expected BEGIN_ARRAY but was BEGIN_OBJECT in retrofit2
I don't know to fix it
What's my wrong ?
my json is
{
"result": true,
"message": "success",
"data": [
{
"id": "10",
"type_name": "pppppp"
},
{
"id_mt": "11",
"type_name": "aaaaaa"
}
]
}
and my model class is
public class MessageFastModel {
private boolean result;
private String message;
private List<DataBean> data;
public boolean isResult() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<DataBean> getData() {
return data;
}
public void setData(List<DataBean> data) {
this.data = data;
}
public static class DataBean {
private String id;
private String type_name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType_name() {
return type_name;
}
public void setType_name(String type_name) {
this.type_name = type_name;
}
}
}
My code is
#FormUrlEncoded
#POST("api/message_type")
Call<MessageFastModel> listMessageFast(#Field("token") String token);
and
Call<MessageFastModel> dddddCall = ooooo.listMessageFast(Preferences.getToken());
dddddCall.enqueue(new Callback<MessageFastModel>() {
#Override
public void onResponse(Call<MessageFastModel> call, Response<MessageFastModel> response) {
if (response.isSuccessful()) {
Log.d("ddd", "onResponse: " + response.body().getData().size());
}
}
#Override
public void onFailure(Call<MessageFastModel> call, Throwable t) {
Log.e("ddd", "onFailure: " + t.getMessage());
}
});
but My error is
E/ddd: onFailure: java.lang.IllegalStateException: Expected
BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 44 path $.data
what's problem ? thanks!
#GET("photos")
Call<Model> savePhoto();
And Call your retrofit method like this >>>
Call<Model> call = apiService.savePhoto();
call.enqueue(new retrofit2.Callback<Model>() {
#Override
public void onResponse(Call<Model> call, retrofit2.Response<Model> response) {
int statusCode = response.code();
try {
Model model;
// Log.w("resedatasync", new Gson().toJson(response));
model= response.body();
And Create Your Model Class like this
public class Model{
#SerializedName("ArrayName")
public List<DataBean > arraylist= new ArrayList<>();
#SerializedName("message")
private String message;
public class DataBean {
#SerializedName("id")
private String id;
#SerializedName("typename")
private String typename;
#SerializedName("typename")
public void settypename(String typename) {
this.typename= typename;
}
}
}
When you have problem
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 44 path $.data
We must know that where need JSONArray .You have List<DataBean> data .So your data must use JSONArray .
And may be your problem at
Log.d("ddd", "onResponse: " + response.body().getData().size());
You can do like this .
System.out.println(response.body().string());
And show your message .
And try this class .
public class MessageFastModel {
private boolean result;
private String message;
private DataBean data;
public boolean isResult() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public DataBean getData() {
return data;
}
public void setData(DataBean data) {
this.data = data;
}
public static class DataBean {
private String id;
private String type_name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType_name() {
return type_name;
}
public void setType_name(String type_name) {
this.type_name = type_name;
}
}
}
And remove Log.d("ddd", "onResponse: " + response.body().getData().size());
This happens when the structure of JSON doesn't matches with the structure of your recipient model class. Also use #Expose and #SerializedName("receivingJsonVariableName") for each variable in the model class.
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")
This question already has answers here:
Why does Gson fromJson throw a JsonSyntaxException: Expected BEGIN_OBJECT but was BEGIN_ARRAY?
(2 answers)
Closed 5 years ago.
with the next problem, when trying to consume a webservice, then message and presentation;
Expected BEGIN_ARRAY but was BEGIN_OBJECT
I'm not sure how to make a scenario, I've already got data from a webservice, but when it's not a simple array.
I have tried many alternatives, but without success.
response api
{
"_links": {
"self": {
"href": "http://url.com/service?page=1"
},
"first": {
"href": "http://url.com/service"
},
"last": {
"href": "http://url.com/service?page=1"
}
},
"_embedded": {
"data": [
{
"id": 1,
"nome": "teste",
"_links": {
"self": {
"href": "http://url.com/service/1"
}
}
},
{
"id": 2,
"nome": "teste 2",
"_links": {
"self": {
"href": "http://url.com/service/2"
}
}
}
]
},
"page_count": 1,
"page_size": 25,
"total_items": 2,
"page": 1
}
Client
public class ApiClient {
private static final String BASE_URL = "http://url.com/";
private static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Gson gson = new GsonBuilder().setLenient().create();
return new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
/**
* Get API Service
*
* #return API Service
*/
public static ApiInterface getApiService() {
return getClient().create(ApiInterface.class);
}
}
Interface
/**
* Class ApiInterface
*/
public interface ApiInterface
{
#Headers("Accept: application/json")
#GET("/service")
Call<ArrayList<ServiceData>> getData();
}
Service
public class Service{
#SerializedName("data")
private ArrayList<ServiceData> service = new ArrayList<>();
}
Service Data
public class ServiceData {
#SerializedName("id")
private int id;
public ServiceData(int id, String nome) {
this.id = id;
}
public int getId() {
return id;
}
}
Activity
final Call<ArrayList<ServiceData>> service = apiService.getService();
service.enqueue(new Callback<ArrayList<ServiceData>>() {
#Override
public void onResponse(Call<ArrayList<ServiceData>> call, Response<ArrayList<ServiceData>> response) {
Log.e(TAG, "" + response.body());
}
#Override
public void onFailure(Call<ArrayList<ServiceData>> call, Throwable t) {
Log.e(TAG, "" + t);
}
});
You were in the right path but the response is the whole json and not only the data part you want.
I would create the ResponseApi class:
public class ResponseApi {
#SerializedName("_embedded")
private Service embedded;
}
And change on ApiInterface:
Call<ArrayList<ServiceData>> getData();
To:
Call<ResponseApi> getData();
Also in your activity replace all ArrayList<ServiceData> with ResponseApi.
With only this changes your code should work. And then you'll need to add getters in ResponseApi and Service to access the saved data.
UPDATE adding some getters:
We need the possibility to get the ArrayList of ServiceData of services:
public class Service {
// Your current code
public List<ServiceData> getServices() {
return service;
}
}
And also we could create a getter in ResponseApi to get embedded getEmbedded (I'll add the code as info only) but since we only want the services we could create a getter to the list of services getEmbededServices and use this last method.
public class ResponseApi {
// Your current code
public Service getEmbedded() { // Not used, only shown as info
return embedded;
}
public List<ServiceData> getEmbeddedServices() {
return embedded.getServices();
}
}
This way, when you'll receive a ResponseApi object in the onResponse method you can call its getEmbeddedServices to get the List of ServiceData and then you can loop through them to get the ids:
#Override
public void onResponse(Call<ResponseApi> call, Response<ResponseApi> response) {
Log.d(TAG, "services: " + response.getEmbeddedServices());
// Here you can loop the response.getEmbeddedServices() which is a List of ServiceData and get each of the ids. Ex:
for (ServiceData serviceData : response.getEmbeddedServices()) {
Log.d(TAG, "service Id: " + serviceData.getId());
// Here you have access to the ids and can do whatever you need with them.
}
}
By the way, only as a suggestion, I would rename (with refactor in Android Studio) this service var (in Service class):
private ArrayList<ServiceData> service = new ArrayList<>();
To servicesList:
private ArrayList<ServiceData> servicesList = new ArrayList<>();
And maybe also refactor the Service class to ServicesList class.
It's going to work either you rename them or not but, in my opinion, the code is more readable this way.
Try this
Your Parsing mapping has issues try below Model
ServiceData.java
public class ServiceData {
#SerializedName("_links")
#Expose
private Links links;
#SerializedName("_embedded")
#Expose
private Embedded embedded;
#SerializedName("page_count")
#Expose
private Integer pageCount;
#SerializedName("page_size")
#Expose
private Integer pageSize;
#SerializedName("total_items")
#Expose
private Integer totalItems;
#SerializedName("page")
#Expose
private Integer page;
public Links getLinks() {
return links;
}
public void setLinks(Links links) {
this.links = links;
}
public Embedded getEmbedded() {
return embedded;
}
public void setEmbedded(Embedded embedded) {
this.embedded = embedded;
}
public Integer getPageCount() {
return pageCount;
}
public void setPageCount(Integer pageCount) {
this.pageCount = pageCount;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getTotalItems() {
return totalItems;
}
public void setTotalItems(Integer totalItems) {
this.totalItems = totalItems;
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
}
Self_.java
public class Self_ {
#SerializedName("href")
#Expose
private String href;
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
}
Self.java
public class Self {
#SerializedName("href")
#Expose
private String href;
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
}
Links_.java
public class Links_ {
#SerializedName("self")
#Expose
private Self_ self;
public Self_ getSelf() {
return self;
}
public void setSelf(Self_ self) {
this.self = self;
}
}
Links.java
public class Links {
#SerializedName("self")
#Expose
private Self self;
#SerializedName("first")
#Expose
private First first;
#SerializedName("last")
#Expose
private Last last;
public Self getSelf() {
return self;
}
public void setSelf(Self self) {
this.self = self;
}
public First getFirst() {
return first;
}
public void setFirst(First first) {
this.first = first;
}
public Last getLast() {
return last;
}
public void setLast(Last last) {
this.last = last;
}
}
Last.java
public class Last {
#SerializedName("href")
#Expose
private String href;
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
}
First.java
public class First {
#SerializedName("href")
#Expose
private String href;
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
}
Embedded.java
public class Embedded {
#SerializedName("data")
#Expose
private List<Datum> data = null;
public List<Datum> getData() {
return data;
}
public void setData(List<Datum> data) {
this.data = data;
}
}
Datum.java
public class Datum {
#SerializedName("id")
#Expose
private Integer id;
#SerializedName("nome")
#Expose
private String nome;
#SerializedName("_links")
#Expose
private Links_ links;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Links_ getLinks() {
return links;
}
public void setLinks(Links_ links) {
this.links = links;
}
}
Try to remove ArrayList from every where and direct use ServiceData
Interface
/**
* Class ApiInterface
*/
public interface ApiInterface
{
#Headers("Accept: application/json")
#GET("/service")
Call<ServiceData> getData();
}
Service Data
public class ServiceData {
#SerializedName("id")
private int id;
public ServiceData(int id, String nome) {
this.id = id;
}
public int getId() {
return id;
}
}
Activity
final Call<ServiceData> service = apiService.getService();
service.enqueue(new Callback<ServiceData>() {
#Override
public void onResponse(Call<ServiceData> call, Response<ServiceData> response) {
Log.e(TAG, "" + response.body());
}
#Override
public void onFailure(Call<ServiceData> call, Throwable t) {
Log.e(TAG, "" + t);
}
});
You call and waiting for List. Call<ArrayList<ServiceData>>
But in the response, you have an object.
[...] - is array (list)
{...} - is object
You need to create classes for all parameters properly.
Just try to look at this service (or similar):
http://www.jsonschema2pojo.org/
Or Android Studio (IDEA) also has a plugin (GsonFormat) for converting JSON.