Mapping a nested JSON response obtained using RxJava and Retrofit - java

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")

Related

Cannot get value from nested json retrofit android studio

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

Retrofit + Observable - Expected BEGIN_ARRAY but was BEGIN_OBJECT

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.

Assigning multiple Retrofit response values to an arraylist

I'm struggling to implement a solution to retrieve multiple values from my api response ( https://www.thecocktaildb.com/api/json/v1/1/lookup.php?i=13060 ) and assign specific values to an array. Specifically values, strIngredient1, strIngredient2, strIngredient3 etc...
At present i created a POJO cocktail class as follows:
public class Cocktail implements Serializable {
#SerializedName("idDrink")
#Expose
private String idDrink;
#SerializedName("strDrink")
#Expose
private String strDrink;
#SerializedName("strVideo")
#Expose
private Object strVideo;
#SerializedName("strCategory")
#Expose
private String strCategory;
#SerializedName("strIBA")
#Expose
private Object strIBA;
#SerializedName("strAlcoholic")
#Expose
private String strAlcoholic;
#SerializedName("strGlass")
#Expose
private String strGlass;
#SerializedName("strInstructions")
#Expose
private String strInstructions;
#SerializedName("strDrinkThumb")
#Expose
private String strDrinkThumb;
#SerializedName("strIngredient1")
#Expose
private String strIngredient1;
#SerializedName("strIngredient2")
#Expose
private String strIngredient2;
#SerializedName("strIngredient3")
#Expose
private String strIngredient3;
#SerializedName("strIngredient4")
#Expose
private String strIngredient4;
#SerializedName("strIngredient5")
#Expose
private String strIngredient5;
#SerializedName("strIngredient6")
#Expose
private String strIngredient6;
#SerializedName("strIngredient7")
#Expose
private String strIngredient7;
#SerializedName("strIngredient8")
#Expose
private String strIngredient8;
#SerializedName("strIngredient9")
#Expose
private String strIngredient9;
#SerializedName("strIngredient10")
#Expose
private String strIngredient10;
#SerializedName("strIngredient11")
#Expose
private String strIngredient11;
#SerializedName("strIngredient12")
#Expose
private String strIngredient12;
#SerializedName("strIngredient13")
#Expose
private String strIngredient13;
#SerializedName("strIngredient14")
#Expose
private String strIngredient14;
#SerializedName("strIngredient15")
#Expose
private String strIngredient15;
#SerializedName("strMeasure1")
#Expose
private String strMeasure1;
#SerializedName("strMeasure2")
#Expose
private String strMeasure2;
#SerializedName("strMeasure3")
#Expose
private String strMeasure3;
#SerializedName("strMeasure4")
#Expose
private String strMeasure4;
#SerializedName("strMeasure5")
#Expose
private String strMeasure5;
#SerializedName("strMeasure6")
#Expose
private String strMeasure6;
#SerializedName("strMeasure7")
#Expose
private String strMeasure7;
#SerializedName("strMeasure8")
#Expose
private String strMeasure8;
#SerializedName("strMeasure9")
#Expose
private String strMeasure9;
#SerializedName("strMeasure10")
#Expose
private String strMeasure10;
#SerializedName("strMeasure11")
#Expose
private String strMeasure11;
#SerializedName("strMeasure12")
#Expose
private String strMeasure12;
#SerializedName("strMeasure13")
#Expose
private String strMeasure13;
#SerializedName("strMeasure14")
#Expose
private String strMeasure14;
#SerializedName("strMeasure15")
#Expose
private String strMeasure15;
#SerializedName("dateModified")
#Expose
private String dateModified;
public String getIdDrink() {
return idDrink;
}
public void setIdDrink(String idDrink) {
this.idDrink = idDrink;
}
public String getStrDrink() {
return strDrink;
}
public void setStrDrink(String strDrink) {
this.strDrink = strDrink;
}
public Object getStrVideo() {
return strVideo;
}
public void setStrVideo(Object strVideo) {
this.strVideo = strVideo;
}
public String getStrCategory() {
return strCategory;
}
public void setStrCategory(String strCategory) {
this.strCategory = strCategory;
}
public Object getStrIBA() {
return strIBA;
}
public void setStrIBA(Object strIBA) {
this.strIBA = strIBA;
}
public String getStrAlcoholic() {
return strAlcoholic;
}
public void setStrAlcoholic(String strAlcoholic) {
this.strAlcoholic = strAlcoholic;
}
public String getStrGlass() {
return strGlass;
}
public void setStrGlass(String strGlass) {
this.strGlass = strGlass;
}
public String getStrInstructions() {
return strInstructions;
}
public void setStrInstructions(String strInstructions) {
this.strInstructions = strInstructions;
}
public String getStrDrinkThumb() {
return strDrinkThumb;
}
public void setStrDrinkThumb(String strDrinkThumb) {
this.strDrinkThumb = strDrinkThumb;
}
public String getStrIngredient1() {
return strIngredient1;
}
public void setStrIngredient1(String strIngredient1) {
this.strIngredient1 = strIngredient1;
}
public String getStrIngredient2() {
return strIngredient2;
}
public void setStrIngredient2(String strIngredient2) {
this.strIngredient2 = strIngredient2;
}
public String getStrIngredient3() {
return strIngredient3;
}
public void setStrIngredient3(String strIngredient3) {
this.strIngredient3 = strIngredient3;
}
public String getStrIngredient4() {
return strIngredient4;
}
public void setStrIngredient4(String strIngredient4) {
this.strIngredient4 = strIngredient4;
}
public String getStrIngredient5() {
return strIngredient5;
}
public void setStrIngredient5(String strIngredient5) {
this.strIngredient5 = strIngredient5;
}
public String getStrIngredient6() {
return strIngredient6;
}
public void setStrIngredient6(String strIngredient6) {
this.strIngredient6 = strIngredient6;
}
public String getStrIngredient7() {
return strIngredient7;
}
public void setStrIngredient7(String strIngredient7) {
this.strIngredient7 = strIngredient7;
}
public String getStrIngredient8() {
return strIngredient8;
}
public void setStrIngredient8(String strIngredient8) {
this.strIngredient8 = strIngredient8;
}
public String getStrIngredient9() {
return strIngredient9;
}
public void setStrIngredient9(String strIngredient9) {
this.strIngredient9 = strIngredient9;
}
public String getStrIngredient10() {
return strIngredient10;
}
public void setStrIngredient10(String strIngredient10) {
this.strIngredient10 = strIngredient10;
}
public String getStrIngredient11() {
return strIngredient11;
}
public void setStrIngredient11(String strIngredient11) {
this.strIngredient11 = strIngredient11;
}
public String getStrIngredient12() {
return strIngredient12;
}
public void setStrIngredient12(String strIngredient12) {
this.strIngredient12 = strIngredient12;
}
public String getStrIngredient13() {
return strIngredient13;
}
public void setStrIngredient13(String strIngredient13) {
this.strIngredient13 = strIngredient13;
}
public String getStrIngredient14() {
return strIngredient14;
}
public void setStrIngredient14(String strIngredient14) {
this.strIngredient14 = strIngredient14;
}
public String getStrIngredient15() {
return strIngredient15;
}
public void setStrIngredient15(String strIngredient15) {
this.strIngredient15 = strIngredient15;
}
public String getStrMeasure1() {
return strMeasure1;
}
public void setStrMeasure1(String strMeasure1) {
this.strMeasure1 = strMeasure1;
}
public String getStrMeasure2() {
return strMeasure2;
}
public void setStrMeasure2(String strMeasure2) {
this.strMeasure2 = strMeasure2;
}
public String getStrMeasure3() {
return strMeasure3;
}
public void setStrMeasure3(String strMeasure3) {
this.strMeasure3 = strMeasure3;
}
public String getStrMeasure4() {
return strMeasure4;
}
public void setStrMeasure4(String strMeasure4) {
this.strMeasure4 = strMeasure4;
}
public String getStrMeasure5() {
return strMeasure5;
}
public void setStrMeasure5(String strMeasure5) {
this.strMeasure5 = strMeasure5;
}
public String getStrMeasure6() {
return strMeasure6;
}
public void setStrMeasure6(String strMeasure6) {
this.strMeasure6 = strMeasure6;
}
public String getStrMeasure7() {
return strMeasure7;
}
public void setStrMeasure7(String strMeasure7) {
this.strMeasure7 = strMeasure7;
}
public String getStrMeasure8() {
return strMeasure8;
}
public void setStrMeasure8(String strMeasure8) {
this.strMeasure8 = strMeasure8;
}
public String getStrMeasure9() {
return strMeasure9;
}
public void setStrMeasure9(String strMeasure9) {
this.strMeasure9 = strMeasure9;
}
public String getStrMeasure10() {
return strMeasure10;
}
public void setStrMeasure10(String strMeasure10) {
this.strMeasure10 = strMeasure10;
}
public String getStrMeasure11() {
return strMeasure11;
}
public void setStrMeasure11(String strMeasure11) {
this.strMeasure11 = strMeasure11;
}
public String getStrMeasure12() {
return strMeasure12;
}
public void setStrMeasure12(String strMeasure12) {
this.strMeasure12 = strMeasure12;
}
public String getStrMeasure13() {
return strMeasure13;
}
public void setStrMeasure13(String strMeasure13) {
this.strMeasure13 = strMeasure13;
}
public String getStrMeasure14() {
return strMeasure14;
}
public void setStrMeasure14(String strMeasure14) {
this.strMeasure14 = strMeasure14;
}
public String getStrMeasure15() {
return strMeasure15;
}
public void setStrMeasure15(String strMeasure15) {
this.strMeasure15 = strMeasure15;
}
public String getDateModified() {
return dateModified;
}
public void setDateModified(String dateModified) {
this.dateModified = dateModified;
}
And my API call is as follows:
#Override
protected Cocktail doInBackground(Cocktail... cocktails) {
Call<Cocktails> call = mApiService.getCocktail(id);
try {
Response<Cocktails> response = call.execute();
this.cocktails = response.body();
this.cocktail = this.cocktails.getCocktail().get(0);
Log.i(TAG, "Success: " + response.body().toString());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e);
e.printStackTrace();
} catch (IllegalStateException e) {
Log.e(TAG, "IllegalStateException: " + e);
e.printStackTrace();
}
return cocktail;
}
I know enough to realise that a large number of variables, ingredients and measures (many of which are empty) is the wrong approach but i'm struggling to find a solution with retrofit to create an array of these values. I've not found any way to assign multiple SerializedNames to a single array variable?
The option that jumps out at me is looping through the response pulling out the key values in onSuccess but this seems to go against the simplicity of using retrofit?

How to make parse object to json using retrofit [duplicate]

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.

Assign one json value for two fields in java using GSON

I am trying to assign the value returned by some function to a field in the deserialized class of json.
FileInfo.java
public class FileInfo {
#SerializedName("Name")
private String mName;
#SerializedName("Url")
private String mUri;
#SerializedName("Size")
private Integer mSize;
#SerializedName("ModTime")
private Long mModifiedTime;
private FileType mType;
#SerializedName("Children")
private ArrayList<FileInfo> mChildren = new ArrayList<>();
public ArrayList<FileInfo> getChildren() {
return mChildren;
}
public long getModifiedTime() {
return mModifiedTime;
}
public String getName() {
return mName;
}
public Integer getSize() {
return mSize;
}
public String getUrl() {
return mUri;
}
public FileType getType() {
return mType;
}
public void setChildren(ArrayList<FileInfo> mChildren) {
this.mChildren = mChildren;
}
public void setModifiedTime(long mModifiedTime) {
this.mModifiedTime = mModifiedTime;
}
public void setName(String mName) {
this.mName = mName;
}
public void setSize(Integer mSize) {
this.mSize = mSize;
}
public void setType(FileType mType) {
this.mType = mType;
}
public void setUri(String mUri) {
this.mUri = mUri;
}
#Override
public String toString() {
return FileInfo.class.toString();
}
public FileInfo() {
}
}
The mType needs to be assigned to foo(mName). I looked up custom deserializers and instance creators but none of those helped. I also thought of TypeAdapters which i feel defeats the purpose of keeping deserialization(using GSON) simple.
This is a sample JSON string that will be deserialized.
[
{
"Name":"Airport",
"Url":"http://192.168.2.2/api/sites/Baltimore%20Airport/Airport",
"Size":0,
"ModTime":"2015-12-02T14:19:17.29824-05:00",
"Children":null
}
]
P.S. I'm not sure if this should be done during deserialization but trying anyways. Also please let me know of alternative ways to achieve this.

Categories