Android NetworkBoundResource using repository pattern API error - java

Hi I am just started with mvvm with repository pattern I am stuck with the API error
I am using the generic API Response class as per google official repo in java
/**
* Generic class for handling responses from Retrofit
*
* #param <T>
*/
public class ApiResponse<T> {
public ApiResponse<T> create(Throwable error) {
return new ApiErrorResponse<>(error.getMessage().equals("") ? error.getMessage() : "Unknown error\nCheck network connection");
}
public ApiResponse<T> create(Response<T> response) {
if (response.isSuccessful()) {
T body = response.body();
if (body instanceof GithubApiResponse) {
if (AppUtils.isValid((GithubApiResponse) body)) {
String errorMsg = "Empty Response.";
return new ApiErrorResponse<>(errorMsg);
}
}
if (body == null || response.code() == 204) { // 204 is empty response
return new ApiEmptyResponse<>();
} else {
return new ApiSuccessResponse<>(body);
}
} else {
String errorMsg = "";
try {
errorMsg = response.errorBody().string();
} catch (IOException e) {
e.printStackTrace();
errorMsg = response.message();
}
return new ApiErrorResponse<>(errorMsg);
}
}
/**
* Generic success response from api
*
* #param <T>
*/
public class ApiSuccessResponse<T> extends ApiResponse<T> {
private T body;
ApiSuccessResponse(T body) {
this.body = body;
}
public T getBody() {
return body;
}
}
/**
* Generic Error response from API
*
* #param <T>
*/
public class ApiErrorResponse<T> extends ApiResponse<T> {
private String errorMessage;
ApiErrorResponse(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getErrorMessage() {
return errorMessage;
}
}
/**
* separate class for HTTP 204 resposes so that we can make ApiSuccessResponse's body non-null.
*/
public class ApiEmptyResponse<T> extends ApiResponse<T> {
}
}
and My networkBoundResource as like this
public abstract class NetworkBoundResource<ResultType, RequestType> {
private AppExecutors appExecutors;
private MediatorLiveData<Resource<ResultType>> results = new MediatorLiveData<>();
public NetworkBoundResource(AppExecutors appExecutors) {
this.appExecutors = appExecutors;
init();
}
private void init() {
// update LiveData for loading status
results.setValue((Resource<ResultType>) Resource.loading(null));
// observe LiveData source from local db
final LiveData<ResultType> dbSource = loadFromDb();
results.addSource(dbSource, new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
results.removeSource(dbSource);
if (shouldFetch(ResultType)) {
// get data from the network
fetchFromNetwork(dbSource);
} else {
results.addSource(dbSource, new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(Resource.success(ResultType));
}
});
}
}
});
}
/**
* 1) observe local db
* 2) if <condition/> query the network
* 3) stop observing the local db
* 4) insert new data into local db
* 5) begin observing local db again to see the refreshed data from network
*
* #param dbSource
*/
private void fetchFromNetwork(final LiveData<ResultType> dbSource) {
Timber.d("fetchFromNetwork: called.");
// update LiveData for loading status
results.addSource(dbSource, new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(Resource.loading(ResultType));
}
});
final LiveData<ApiResponse<RequestType>> apiResponse = createCall();
results.addSource(apiResponse, new Observer<ApiResponse<RequestType>>() {
#Override
public void onChanged(#Nullable final ApiResponse<RequestType> requestObjectApiResponse) {
results.removeSource(dbSource);
results.removeSource(apiResponse);
/*
3 cases:
1) ApiSuccessResponse
2) ApiErrorResponse
3) ApiEmptyResponse
*/
if (requestObjectApiResponse instanceof ApiResponse.ApiSuccessResponse) {
Timber.d("onChanged: ApiSuccessResponse.");
appExecutors.diskIO().execute(new Runnable() {
#Override
public void run() {
// save the response to the local db
saveCallResult((RequestType) processResponse((ApiResponse.ApiSuccessResponse) requestObjectApiResponse));
appExecutors.mainThread().execute(new Runnable() {
#Override
public void run() {
results.addSource(loadFromDb(), new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(Resource.success(ResultType));
}
});
}
});
}
});
} else if (requestObjectApiResponse instanceof ApiResponse.ApiEmptyResponse) {
Timber.d("onChanged: ApiEmptyResponse");
appExecutors.mainThread().execute(new Runnable() {
#Override
public void run() {
results.addSource(loadFromDb(), new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(Resource.success(ResultType));
}
});
}
});
} else if (requestObjectApiResponse instanceof ApiResponse.ApiErrorResponse) {
Timber.d("onChanged: ApiErrorResponse.");
results.addSource(dbSource, new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(
Resource.error(
((ApiResponse.ApiErrorResponse) requestObjectApiResponse).getErrorMessage(),
ResultType
)
);
}
});
}
}
});
}
private ResultType processResponse(ApiResponse.ApiSuccessResponse response) {
return (ResultType) response.getBody();
}
private void setValue(Resource<ResultType> newValue) {
if (results.getValue() != newValue) {
results.setValue(newValue);
}
}
// Called to save the result of the API response into the database.
#WorkerThread
protected abstract void saveCallResult(#NonNull RequestType item);
// Called with the data in the database to decide whether to fetch
// potentially updated data from the network.
#MainThread
protected abstract boolean shouldFetch(#Nullable ResultType data);
// Called to get the cached data from the database.
#NonNull
#MainThread
protected abstract LiveData<ResultType> loadFromDb();
// Called to create the API call.
#NonNull
#MainThread
protected abstract LiveData<ApiResponse<RequestType>> createCall();
// Returns a LiveData object that represents the resource that's implemented
// in the base class.
public final LiveData<Resource<ResultType>> getAsLiveData() {
return results;
}
}
my Repository looks like this
#Singleton
public class GithubRepository {
private GithubDao githubDao;
private GithubTrendingApiService githubApiService;
public GithubRepository(GithubDao githubDao, GithubTrendingApiService githubApiService) {
this.githubDao = githubDao;
this.githubApiService = githubApiService;
}
public LiveData<Resource<List<GithubEntity>>> getRepositories() {
return new NetworkBoundResource<List<GithubEntity>, GithubApiResponse>(AppExecutors.getInstance()) {
#Override
protected void saveCallResult(#NonNull GithubApiResponse item) {
List<GithubEntity> repositories = item.getItems();
githubDao.insertRepositories(repositories);
}
#Override
protected boolean shouldFetch(#Nullable List<GithubEntity> data) {
// Timber.d("shouldFetch: repo: " + data.toString());
// int currentTime = (int) (System.currentTimeMillis() / 1000);
// Timber.d("shouldFetch: current time: " + currentTime);
// int lastRefresh = data.getTimestamp();
// Timber.d("shouldFetch: last refresh: " + lastRefresh);
// Timber.d("shouldFetch: it's been " + ((currentTime - lastRefresh) / 60 / 60 / 24) +
// " days since this recipe was refreshed. 30 days must elapse before refreshing. ");
// if ((currentTime - data.getTimestamp()) >= Constants.RECIPE_REFRESH_TIME) {
// Timber.d("shouldFetch: SHOULD REFRESH RECIPE?! " + true);
// return true;
// }
// Timber.d("shouldFetch: SHOULD REFRESH RECIPE?! " + false);
return true;
}
#NonNull
#Override
protected LiveData<List<GithubEntity>> loadFromDb() {
return githubDao.getTrendingRepository();
}
#NonNull
#Override
protected LiveData<ApiResponse<GithubApiResponse>> createCall() {
return githubApiService.fetchTrendingRepositories();
}
}.getAsLiveData();
}
}
Can anyone tell me whats I am doing wrong because I am getting an API error? somehow I am not able to get the correct data that's why the database is also not filling up
my GithubAPi response class is this
public class GithubApiResponse {
public GithubApiResponse() {
this.items = new ArrayList<>();
}
public GithubApiResponse(List<GithubEntity> items) {
this.items = items;
}
private List<GithubEntity> items;
public List<GithubEntity> getItems() {
return items;
}
public void setItems(List<GithubEntity> items) {
this.items = items;
}
}
and the Entity class is this
#Entity
public class GithubEntity implements Parcelable {
public GithubEntity(#NonNull Long id, String author, String name, String avatar,
String url, String description, Integer stars, Integer forks, Integer currentPeriodStars, String language, String languageColor) {
this.id = id;
this.author = author;
this.name = name;
this.avatar = avatar;
this.url = url;
this.description = description;
this.stars = stars;
this.forks = forks;
this.currentPeriodStars = currentPeriodStars;
this.language = language;
this.languageColor = languageColor;
}
#NonNull
#PrimaryKey
private Long id;
#SerializedName("author")
#Expose
private String author;
#SerializedName("name")
#Expose
private String name;
#SerializedName("avatar")
#Expose
private String avatar;
#SerializedName("url")
#Expose
private String url;
#SerializedName("description")
#Expose
private String description;
#SerializedName("stars")
#Expose
private Integer stars;
#SerializedName("forks")
#Expose
private Integer forks;
#SerializedName("currentPeriodStars")
#Expose
private Integer currentPeriodStars;
#SerializedName("language")
#Expose
private String language;
#SerializedName("languageColor")
#Expose
private String languageColor;
#NonNull
public Long getId() {
return id;
}
public void setId(#NonNull Long id) {
this.id = id;
}
protected GithubEntity(Parcel in) {
author = in.readString();
name = in.readString();
avatar = in.readString();
url = in.readString();
description = in.readString();
if (in.readByte() == 0) {
stars = null;
} else {
stars = in.readInt();
}
if (in.readByte() == 0) {
forks = null;
} else {
forks = in.readInt();
}
if (in.readByte() == 0) {
currentPeriodStars = null;
} else {
currentPeriodStars = in.readInt();
}
language = in.readString();
languageColor = in.readString();
}
public static final Creator<GithubEntity> CREATOR = new Creator<GithubEntity>() {
#Override
public GithubEntity createFromParcel(Parcel in) {
return new GithubEntity(in);
}
#Override
public GithubEntity[] newArray(int size) {
return new GithubEntity[size];
}
};
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStars() {
return stars;
}
public void setStars(Integer stars) {
this.stars = stars;
}
public Integer getForks() {
return forks;
}
public void setForks(Integer forks) {
this.forks = forks;
}
public Integer getCurrentPeriodStars() {
return currentPeriodStars;
}
public void setCurrentPeriodStars(Integer currentPeriodStars) {
this.currentPeriodStars = currentPeriodStars;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getLanguageColor() {
return languageColor;
}
public void setLanguageColor(String languageColor) {
this.languageColor = languageColor;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(author);
dest.writeString(name);
dest.writeString(avatar);
dest.writeString(url);
dest.writeString(description);
if (stars == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(stars);
}
if (forks == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(forks);
}
if (currentPeriodStars == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(currentPeriodStars);
}
dest.writeString(language);
dest.writeString(languageColor);
}
}
can anyone guide me so that I can fix this issue? stuck here for 2 days

Related

How to implelement this on retrofit?

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

How to retrieve data using retofit in Android Studio

https://pro-api.coinmarketcap.com/v1/tools/price-conversion?symbol=NGN&amount=1000897.01&convert=BTC&CMC_PRO_API_KEY=*********************************
That's the url and here is the json returned from querying that url:
{"status":{"timestamp":"2021-04-20T08:48:16.990Z","error_code":0,"error_message":null,"elapsed":17,"credit_count":1,"notice":null},"data":{"id":2819,"symbol":"NGN","name":"Nigerian Naira","amount":1000897.01,"last_updated":"2021-04-20T08:48:07.000Z","quote":{"BTC":{"price":0.0444454708294559,"last_updated":"2021-04-20T08:48:02.000Z"}}}}
the following is my code in android studio to get data from the above api en point
My pojo classes:
import com.google.gson.annotations.SerializedName;
public class CurrencyModel {
#SerializedName("name")
private String currencyName;
#SerializedName("Amount")
private int currencyAmount;
#SerializedName("quote")
Quota quota;
public CurrencyModel(Quota quota) {
this.quota = quota;
// quota.bitcoinModel.getCoinPrice();
}
public CurrencyModel(String currencyName, int currencyAmount, Quota quota) {
this.currencyName = currencyName;
this.currencyAmount = currencyAmount;
this.quota = quota;
}
public String getCurrencyName() {
return currencyName;
}
public void setCurrencyName(String currencyName) {
this.currencyName = currencyName;
}
public int getCurrencyAmount() {
return currencyAmount;
}
public void setCurrencyAmount(int currencyAmount) {
this.currencyAmount = currencyAmount;
}
public Quota getQuota() {
return quota;
}
public void setQuota(Quota quota) {
this .quota = quota;
}
public class Quota {
int price;
#SerializedName("BTC")
BitcoinModel bitcoinModel;
public Quota(BitcoinModel bitcoinModel) {
this.bitcoinModel = bitcoinModel;
}
public BitcoinModel getBitcoinModel() {
return bitcoinModel = new BitcoinModel(price);
}
public void setBitcoinModel(BitcoinModel bitcoinModel) {
this.bitcoinModel = bitcoinModel;
}
}
public class BitcoinModel {
#SerializedName("price")
private int coinPrice;
public BitcoinModel(int coinPrice) {
this.coinPrice = coinPrice;
}
public int getCoinPrice() {
return coinPrice;
}
public void setCoinPrice(int coinPrice) {
this.coinPrice = coinPrice;
}
}
My activity
public class BitcoinConversionActivity extends AppCompatActivity {
TextInputEditText amountConverted;
Button conversionButton, buyCoinButton;
TextView amountInCurrency;
int amount;
String amountEntered;
Quota quota;
CurrencyModel currencyModel;
JsonPojo pojo;
String symbol = "NGN";
String convert = "BTC";
int amountneeded = 1024587;
String apiKey = "b34416c7-2bb9-44b1-aa76-1293edd14dda";
String currencyName;
int amountnm;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coinconversion);
amountConverted = findViewById(R.id.amount_edit_text);
amountInCurrency = findViewById(R.id.conversion_rate_tv);
conversionButton = findViewById(R.id.conversion_button);
buyCoinButton = findViewById(R.id.buy_exchange_coin_button);
conversionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
amount = Integer.parseInt(amountConverted.getText().toString());
if (TextUtils.isEmpty(Double.toString(amount))){
Toast.makeText(BitcoinConversionActivity.this, "Please Enter a valid Amount", Toast.LENGTH_LONG).show();
}else{
CoinExchange();
}
}
});
}
private void CoinExchange() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://pro-api.coinmarketcap.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
BitcoinInterface service = retrofit.create(BitcoinInterface.class);
Call<CurrencyModel> call = service.loadNairaToBitcionExchange(symbol,amountneeded,convert,apiKey);
call.enqueue(new Callback<CurrencyModel>() {
#Override
public void onResponse(Call<CurrencyModel> call, Response<CurrencyModel> response) {
if (response.isSuccessful()){
String price = response.body().toString();
//amountInCurrency.setText(price);
amountInCurrency.setText("https://pro-api.coinmarketcap.com/"+symbol+amount+convert+apiKey);
Toast.makeText(BitcoinConversionActivity.this, "Data: " + response.body().getQuota().getBitcoinModel().getCoinPrice(), Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(Call<CurrencyModel> call, Throwable t) {
Toast.makeText(BitcoinConversionActivity.this, "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
API interface:
public interface BitcoinInterface {
#GET("v1/tools/price-conversion?")
Call<CurrencyModel> loadNairaToBitcionExchange(#Query("symbol") String coinsSymbol,
#Query("amount") int currencyaAmount,
#Query("convert") String convertedToCurrency,
#Query("CMC_PRO_API_KEY") String ApiKey);
}
The call is returning null and at times zero.
From the API you are not getting exactly the CurrencyModel as response. You are getting another object which is CurrencyModel is a child object.
You have to create resposne object like below:
public class ResponseObject{
//#SerializedName("status")
//private int status;
#SerializedName("data")
private CurrencyModel currencyModel;
//getters and setters goes here
}
And then your interface should be like below as you are expecting ResponseObject here
public interface BitcoinInterface {
#GET("v1/tools/price-conversion?")
Call<ResponseObject> loadNairaToBitcionExchange(#Query("symbol") String coinsSymbol,
#Query("amount") int currencyaAmount,
#Query("convert") String convertedToCurrency,
#Query("CMC_PRO_API_KEY") String ApiKey);
}

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.

JSON Exception - No value for in Android

I am getting this error message in my logcat 03-18 12:06:36.972: W/System.err(24574): org.json.JSONException: No value for title an I am stuck here. I am using Gson to parse JSON data. Here is my MainActivity and Model class.
I looked into other questions posted for same JSON Exception but I couldn't find the solution so I posted this question for my project
Also please advise if I am using correct method to display the data in the textview.
MainActivity
public class MainActivity extends AppCompatActivity {
public static final String Logcat = "vmech";
Button searchButton;
EditText editTextSearch;
TextView textViewDisplayResult;
String newText;
String urlstring;
public static final String MyAPIKey = "Your_Api_Key";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
searchButton = (Button) findViewById(R.id.buttonSerch);
editTextSearch = (EditText) findViewById(R.id.editTextSearch);
textViewDisplayResult = (TextView) findViewById(R.id.textViewDisplayResult);
searchButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
newText = editTextSearch.getText().toString();
if(newText.length()>0){
newText = newText.replace(" ", "+");
urlstring = "https://www.googleapis.com/books/v1/volumes?q=";
urlstring = urlstring + newText + "&maxResults=5" + "&key=" + MyAPIKey;
}
else {
Toast.makeText(MainActivity.this, "Please enter a book name to search.", Toast.LENGTH_LONG).show();
}
new JSONTask().execute(urlstring);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater=getMenuInflater();
inflater.inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
Toast.makeText(this, "This is the Settings item", Toast.LENGTH_LONG).show();
return true;
}
public class JSONTask extends AsyncTask<String, String, List<BookInfoModel>>{
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected List<BookInfoModel> doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader bufferedReader = null;
try {
URL url = new URL(urlstring);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream inputstream = connection.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputstream));
StringBuffer stringbuffer = new StringBuffer();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
stringbuffer.append(line);
}
String finalJson = stringbuffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("items");
List<BookInfoModel> bookInfoModelList = new ArrayList<>();
String idText = null;
Gson gson = new Gson();
for(int i=0; i<parentArray.length(); i++){
JSONObject finalObject = parentArray.getJSONObject(i);
BookInfoModel bookInfoModel = gson.fromJson(finalObject.toString(),BookInfoModel.class);
bookInfoModelList.add(bookInfoModel);
}
return bookInfoModelList;
} catch (IOException e){
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} finally {
if (connection != null)
{
connection.disconnect();
}
try {
if (bufferedReader != null){
bufferedReader.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(List<BookInfoModel> result) {
super.onPostExecute(result);
textViewDisplayResult.setText((CharSequence) result);
}
}
}
Here is my model class for JSON data.
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class BookInfoModel {
private List<Items> items;
private String totalItems;
private String kind;
public List<Items> getItems() {
return items;
}
public void setItems(List<Items> items) {
this.items = items;
}
public String getTotalItems ()
{
return totalItems;
}
public void setTotalItems (String totalItems)
{
this.totalItems = totalItems;
}
public String getKind ()
{
return kind;
}
public void setKind (String kind)
{
this.kind = kind;
}
public class Items
{
private SaleInfo saleInfo;
private String id;
private SearchInfo searchInfo;
private String etag;
private List<VolumeInfo> volumeInfo;
private String selfLink;
private AccessInfo accessInfo;
private String kind;
public SaleInfo getSaleInfo ()
{
return saleInfo;
}
public void setSaleInfo (SaleInfo saleInfo)
{
this.saleInfo = saleInfo;
}
public String getId ()
{
return id;
}
public void setId (String id)
{
this.id = id;
}
public SearchInfo getSearchInfo ()
{
return searchInfo;
}
public void setSearchInfo (SearchInfo searchInfo)
{
this.searchInfo = searchInfo;
}
public String getEtag ()
{
return etag;
}
public void setEtag (String etag)
{
this.etag = etag;
}
public List<VolumeInfo> getVolumeInfo() {
return volumeInfo;
}
public void setVolumeInfo(List<VolumeInfo> volumeInfo) {
this.volumeInfo = volumeInfo;
}
public String getSelfLink ()
{
return selfLink;
}
public void setSelfLink (String selfLink)
{
this.selfLink = selfLink;
}
public AccessInfo getAccessInfo ()
{
return accessInfo;
}
public void setAccessInfo (AccessInfo accessInfo)
{
this.accessInfo = accessInfo;
}
public String getKind ()
{
return kind;
}
public void setKind (String kind)
{
this.kind = kind;
}
public class SearchInfo
{
private String textSnippet;
public String getTextSnippet ()
{
return textSnippet;
}
public void setTextSnippet (String textSnippet)
{
this.textSnippet = textSnippet;
}
}
public class AccessInfo
{
private String webReaderLink;
private String textToSpeechPermission;
private String publicDomain;
private String viewability;
private String accessViewStatus;
private Pdf pdf;
private Epub epub;
private String embeddable;
private String quoteSharingAllowed;
private String country;
public String getWebReaderLink ()
{
return webReaderLink;
}
public void setWebReaderLink (String webReaderLink)
{
this.webReaderLink = webReaderLink;
}
public String getTextToSpeechPermission ()
{
return textToSpeechPermission;
}
public void setTextToSpeechPermission (String textToSpeechPermission)
{
this.textToSpeechPermission = textToSpeechPermission;
}
public String getPublicDomain ()
{
return publicDomain;
}
public void setPublicDomain (String publicDomain)
{
this.publicDomain = publicDomain;
}
public String getViewability ()
{
return viewability;
}
public void setViewability (String viewability)
{
this.viewability = viewability;
}
public String getAccessViewStatus ()
{
return accessViewStatus;
}
public void setAccessViewStatus (String accessViewStatus)
{
this.accessViewStatus = accessViewStatus;
}
public Pdf getPdf ()
{
return pdf;
}
public void setPdf (Pdf pdf)
{
this.pdf = pdf;
}
public Epub getEpub ()
{
return epub;
}
public void setEpub (Epub epub)
{
this.epub = epub;
}
public String getEmbeddable ()
{
return embeddable;
}
public void setEmbeddable (String embeddable)
{
this.embeddable = embeddable;
}
public String getQuoteSharingAllowed ()
{
return quoteSharingAllowed;
}
public void setQuoteSharingAllowed (String quoteSharingAllowed)
{
this.quoteSharingAllowed = quoteSharingAllowed;
}
public String getCountry ()
{
return country;
}
public void setCountry (String country)
{
this.country = country;
}
public class Pdf
{
private String acsTokenLink;
private String isAvailable;
public String getAcsTokenLink ()
{
return acsTokenLink;
}
public void setAcsTokenLink (String acsTokenLink)
{
this.acsTokenLink = acsTokenLink;
}
public String getIsAvailable ()
{
return isAvailable;
}
public void setIsAvailable (String isAvailable)
{
this.isAvailable = isAvailable;
}
}
public class Epub
{
private String acsTokenLink;
private String isAvailable;
public String getAcsTokenLink ()
{
return acsTokenLink;
}
public void setAcsTokenLink (String acsTokenLink)
{
this.acsTokenLink = acsTokenLink;
}
public String getIsAvailable ()
{
return isAvailable;
}
public void setIsAvailable (String isAvailable)
{
this.isAvailable = isAvailable;
}
}
}
public class SaleInfo
{
private RetailPrice retailPrice;
private String saleability;
private ListPrice listPrice;
private Offers[] offers;
private String buyLink;
private String isEbook;
private String country;
public RetailPrice getRetailPrice ()
{
return retailPrice;
}
public void setRetailPrice (RetailPrice retailPrice)
{
this.retailPrice = retailPrice;
}
public String getSaleability ()
{
return saleability;
}
public void setSaleability (String saleability)
{
this.saleability = saleability;
}
public ListPrice getListPrice ()
{
return listPrice;
}
public void setListPrice (ListPrice listPrice)
{
this.listPrice = listPrice;
}
public Offers[] getOffers ()
{
return offers;
}
public void setOffers (Offers[] offers)
{
this.offers = offers;
}
public String getBuyLink ()
{
return buyLink;
}
public void setBuyLink (String buyLink)
{
this.buyLink = buyLink;
}
public String getIsEbook ()
{
return isEbook;
}
public void setIsEbook (String isEbook)
{
this.isEbook = isEbook;
}
public String getCountry ()
{
return country;
}
public void setCountry (String country)
{
this.country = country;
}
public class Offers
{
private RetailPrice retailPrice;
private ListPrice listPrice;
private String finskyOfferType;
public RetailPrice getRetailPrice ()
{
return retailPrice;
}
public void setRetailPrice (RetailPrice retailPrice)
{
this.retailPrice = retailPrice;
}
public ListPrice getListPrice ()
{
return listPrice;
}
public void setListPrice (ListPrice listPrice)
{
this.listPrice = listPrice;
}
public String getFinskyOfferType ()
{
return finskyOfferType;
}
public void setFinskyOfferType (String finskyOfferType)
{
this.finskyOfferType = finskyOfferType;
}
}
public class RetailPrice
{
private String amount;
private String currencyCode;
public String getAmount ()
{
return amount;
}
public void setAmount (String amount)
{
this.amount = amount;
}
public String getCurrencyCode ()
{
return currencyCode;
}
public void setCurrencyCode (String currencyCode)
{
this.currencyCode = currencyCode;
}
}
public class ListPrice
{
private String amount;
private String currencyCode;
public String getAmount ()
{
return amount;
}
public void setAmount (String amount)
{
this.amount = amount;
}
public String getCurrencyCode ()
{
return currencyCode;
}
public void setCurrencyCode (String currencyCode)
{
this.currencyCode = currencyCode;
}
}
}
public class VolumeInfo
{
private String pageCount;
private String averageRating;
private ReadingModes readingModes;
private String infoLink;
private String printType;
private String allowAnonLogging;
private String publisher;
private String[] authors;
private String canonicalVolumeLink;
#SerializedName("title")
private String title;
private String previewLink;
private String description;
private String ratingsCount;
private ImageLinks imageLinks;
private String contentVersion;
private String[] categories;
private String language;
private String publishedDate;
private IndustryIdentifiers[] industryIdentifiers;
private String maturityRating;
public String getPageCount ()
{
return pageCount;
}
public void setPageCount (String pageCount)
{
this.pageCount = pageCount;
}
public String getAverageRating ()
{
return averageRating;
}
public void setAverageRating (String averageRating)
{
this.averageRating = averageRating;
}
public ReadingModes getReadingModes ()
{
return readingModes;
}
public void setReadingModes (ReadingModes readingModes)
{
this.readingModes = readingModes;
}
public String getInfoLink ()
{
return infoLink;
}
public void setInfoLink (String infoLink)
{
this.infoLink = infoLink;
}
public String getPrintType ()
{
return printType;
}
public void setPrintType (String printType)
{
this.printType = printType;
}
public String getAllowAnonLogging ()
{
return allowAnonLogging;
}
public void setAllowAnonLogging (String allowAnonLogging)
{
this.allowAnonLogging = allowAnonLogging;
}
public String getPublisher ()
{
return publisher;
}
public void setPublisher (String publisher)
{
this.publisher = publisher;
}
public String[] getAuthors ()
{
return authors;
}
public void setAuthors (String[] authors)
{
this.authors = authors;
}
public String getCanonicalVolumeLink ()
{
return canonicalVolumeLink;
}
public void setCanonicalVolumeLink (String canonicalVolumeLink)
{
this.canonicalVolumeLink = canonicalVolumeLink;
}
public String getTitle ()
{
return title;
}
public void setTitle (String title)
{
this.title = title;
}
public String getPreviewLink ()
{
return previewLink;
}
public void setPreviewLink (String previewLink)
{
this.previewLink = previewLink;
}
public String getDescription ()
{
return description;
}
public void setDescription (String description)
{
this.description = description;
}
public String getRatingsCount ()
{
return ratingsCount;
}
public void setRatingsCount (String ratingsCount)
{
this.ratingsCount = ratingsCount;
}
public ImageLinks getImageLinks ()
{
return imageLinks;
}
public void setImageLinks (ImageLinks imageLinks)
{
this.imageLinks = imageLinks;
}
public String getContentVersion ()
{
return contentVersion;
}
public void setContentVersion (String contentVersion)
{
this.contentVersion = contentVersion;
}
public String[] getCategories ()
{
return categories;
}
public void setCategories (String[] categories)
{
this.categories = categories;
}
public String getLanguage ()
{
return language;
}
public void setLanguage (String language)
{
this.language = language;
}
public String getPublishedDate ()
{
return publishedDate;
}
public void setPublishedDate (String publishedDate)
{
this.publishedDate = publishedDate;
}
public IndustryIdentifiers[] getIndustryIdentifiers ()
{
return industryIdentifiers;
}
public void setIndustryIdentifiers (IndustryIdentifiers[] industryIdentifiers)
{
this.industryIdentifiers = industryIdentifiers;
}
public String getMaturityRating ()
{
return maturityRating;
}
public void setMaturityRating (String maturityRating)
{
this.maturityRating = maturityRating;
}
public class ImageLinks
{
private String thumbnail;
private String smallThumbnail;
public String getThumbnail ()
{
return thumbnail;
}
public void setThumbnail (String thumbnail)
{
this.thumbnail = thumbnail;
}
public String getSmallThumbnail ()
{
return smallThumbnail;
}
public void setSmallThumbnail (String smallThumbnail)
{
this.smallThumbnail = smallThumbnail;
}
}
public class ReadingModes
{
private String text;
private String image;
public String getText ()
{
return text;
}
public void setText (String text)
{
this.text = text;
}
public String getImage ()
{
return image;
}
public void setImage (String image)
{
this.image = image;
}
}
public class IndustryIdentifiers
{
private String type;
private String identifier;
public String getType ()
{
return type;
}
public void setType (String type)
{
this.type = type;
}
public String getIdentifier ()
{
return identifier;
}
public void setIdentifier (String identifier)
{
this.identifier = identifier;
}
}
}
}
}
Here is the JSON data I m trying to Parse.
{
"kind": "books#volumes",
"totalItems": 1557,
"items": [
{
"kind": "books#volume",
"id": "An4_e3Cr3zAC",
"etag": "DWmqBRkB8dw",
"selfLink": "https://www.googleapis.com/books/v1/volumes/An4_e3Cr3zAC",
"volumeInfo": {
"title": "The Rules of the Game",
"authors": [
"Neil Strauss"
],
"publisher": "Canongate Books",
"publishedDate": "2011-09-29",
"description": "If you want to play The Game you need to know The Rules This book is not a story.",
"industryIdentifiers": [
{
"type": "ISBN_13",
"identifier": "9781847673558"
},
{
"type": "ISBN_10",
"identifier": "1847673554"
}
],
"readingModes": {
"text": true,
"image": true
},
"pageCount": 352,
"printType": "BOOK",
"categories": [
"Biography & Autobiography"
],
"averageRating": 3.5,
"ratingsCount": 82,
"maturityRating": "NOT_MATURE",
"allowAnonLogging": true,
"contentVersion": "1.7.6.0.preview.3",
"imageLinks": {
"smallThumbnail": "http://books.google.co.in/books/content?id=An4_e3Cr3zAC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
"thumbnail": "http://books.google.co.in/books/content?id=An4_e3Cr3zAC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
},
"language": "en",
"previewLink": "http://books.google.co.in/books?id=An4_e3Cr3zAC&printsec=frontcover&dq=game&hl=&cd=1&source=gbs_api",
"infoLink": "http://books.google.co.in/books?id=An4_e3Cr3zAC&dq=game&hl=&source=gbs_api",
"canonicalVolumeLink": "http://books.google.co.in/books/about/The_Rules_of_the_Game.html?hl=&id=An4_e3Cr3zAC"
},
"saleInfo": {
"country": "IN",
"saleability": "FOR_SALE",
"isEbook": true,
"listPrice": {
"amount": 399.0,
"currencyCode": "INR"
},
"retailPrice": {
"amount": 279.3,
"currencyCode": "INR"
},
"buyLink": "http://books.google.co.in/books?id=An4_e3Cr3zAC&dq=game&hl=&buy=&source=gbs_api",
"offers": [
{
"finskyOfferType": 1,
"listPrice": {
"amountInMicros": 3.99E8,
"currencyCode": "INR"
},
"retailPrice": {
"amountInMicros": 2.793E8,
"currencyCode": "INR"
}
}
]
},
"accessInfo": {
"country": "IN",
"viewability": "PARTIAL",
"embeddable": true,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": true,
"acsTokenLink": "http://books.goo"
},
"pdf": {
"isAvailable": true,
"acsTokenLink": "http://books.google.co.in/books/download/The_Rules_of_the_Game-sample-pdf.acsm?id=An4_e3Cr3zAC&format=pdf&output=acs4_fulfillment_token&dl_type=sample&source=gbs_api"
},
"webReaderLink": "http://books.google.co.in/books/reader?id=An4_e3Cr3zAC&hl=&printsec=frontcover&output=reader&source=gbs_api",
"accessViewStatus": "SAMPLE",
"quoteSharingAllowed": false
},
"searchInfo": {
"textSnippet": "He's tested the specific material."
}
}
]
}
Here is the stacktrace form logcat. https://codeshare.io/Ag78v
Replace your Items class with below:
public class Items
{
private SaleInfo saleInfo;
private String id;
private SearchInfo searchInfo;
private String etag;
private VolumeInfo volumeInfo;
private String selfLink;
private AccessInfo accessInfo;
private String kind;
public SaleInfo getSaleInfo ()
{
return saleInfo;
}
public void setSaleInfo (SaleInfo saleInfo)
{
this.saleInfo = saleInfo;
}
public String getId ()
{
return id;
}
public void setId (String id)
{
this.id = id;
}
public SearchInfo getSearchInfo ()
{
return searchInfo;
}
public void setSearchInfo (SearchInfo searchInfo)
{
this.searchInfo = searchInfo;
}
public String getEtag ()
{
return etag;
}
public void setEtag (String etag)
{
this.etag = etag;
}
public VolumeInfo getVolumeInfo() {
return volumeInfo;
}
public void setVolumeInfo(VolumeInfo volumeInfo) {
this.volumeInfo = volumeInfo;
}
public String getSelfLink ()
{
return selfLink;
}
public void setSelfLink (String selfLink)
{
this.selfLink = selfLink;
}
public AccessInfo getAccessInfo ()
{
return accessInfo;
}
public void setAccessInfo (AccessInfo accessInfo)
{
this.accessInfo = accessInfo;
}
public String getKind ()
{
return kind;
}
public void setKind (String kind)
{
this.kind = kind;
}
}
You are not using the serializedName annotation. Use it as follows in your model.
public class Items
{
#SerializedName("Your-key-from JSON Response")
private SaleInfo saleInfo;
#SerializedName("Your-key-from JSON Response")
private String id;
#SerializedName("Your-key-from JSON Response")
private SearchInfo searchInfo;
#SerializedName("Your-key-from JSON Response")
private String etag;
#SerializedName("Your-key-from JSON Response")
private VolumeInfo volumeInfo;
#SerializedName("Your-key-from JSON Response")
private String selfLink;
#SerializedName("Your-key-from JSON Response")
private AccessInfo accessInfo;
#SerializedName("Your-key-from JSON Response")
private String kind;
public SaleInfo getSaleInfo ()
{
return saleInfo;
}
public void setSaleInfo (SaleInfo saleInfo)
{
this.saleInfo = saleInfo;
}
public String getId ()
{
return id;
}
public void setId (String id)
{
this.id = id;
}
}
One of Your ListItem VolumeInfo have null value for title. By default Gson wont parse null value. But you can make to ignore null values when parsing. by doing the following.
Gson gson = new GsonBuilder().serializeNulls().create();
Try this.

Inheritance + RPC GWT

It seems that I don't understand inheritance.
I have these classes : PicaAsset, VideoAsset that inherit from a class names Assets.
This is the Assets class declaration :
public class Assets {
protected int book=0;
protected int fromChapter=0;
protected int toChapter=0;
protected int fromVerse=0;
protected int toVerse=0;
protected String creator=null;
protected String discription=null;
protected String source=null;
protected String title=null;
protected String duration=null;
protected String url=null;
public Assets(int book, int fromChapter, int toChapter, int fromVerse,
int toVerse, String creator, String discription, String source,
String title, String duration, String url) {
this.book = book;
this.fromChapter = fromChapter;
this.toChapter = toChapter;
this.fromVerse = fromVerse;
this.toVerse = toVerse;
this.creator = creator;
this.discription = discription;
this.source = source;
this.title = title;
this.duration = duration;
this.url = url;
}
public Assets() {
}
public int getBook() {
return book;
}
public void setBook(int book) {
this.book = book;
}
public int getFromChapter() {
return fromChapter;
}
public void setFromChapter(int fromChapter) {
this.fromChapter = fromChapter;
}
public int getToChapter() {
return toChapter;
}
public void setToChapter(int toChapter) {
this.toChapter = toChapter;
}
public int getFromVerse() {
return fromVerse;
}
public void setFromVerse(int fromVerse) {
this.fromVerse = fromVerse;
}
public int getToVerse() {
return toVerse;
}
public void setToVerse(int toVerse) {
this.toVerse = toVerse;
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
this.creator = creator;
}
public String getDiscription() {
return discription;
}
public void setDiscription(String discription) {
this.discription = discription;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDuration() {
return duration;
}
public void setDuration(String duration) {
this.duration = duration;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
PicAsset :
public class PicAsset extends Assets implements IsSerializable {
private int picId=0;
public PicAsset(){
}
public PicAsset(int picId, int book, int fromChapter, int toChapter,
int fromVerse, int toVerse, String creator, String discription,
String source, String title, String duration, String url) {
super( book, fromChapter, toChapter,
fromVerse, toVerse, creator, discription,
source, title, duration, url);
this.picId = picId;
}
public int getIdpic() {
return picId;
}
public void setIdpic(int idpic) {
this.picId = idpic;
}
}
Now I use an RPC call to use methods declared in the server side to get info from my datbase, as you can see the method return a List of PicAsset , List.
rpcService.getPicture((books.getSelectedIndex()+1), (chapters.getSelectedIndex()+1), new AsyncCallback<List<PicAsset>>(){
public void onFailure(Throwable caught) {
Window.alert("Can't connect to database" + books.getSelectedIndex() + chapters.getSelectedIndex());
}
public void onSuccess(List<PicAsset> result) {
int listSize = result.size();
int i;
int flag = 0;
assetPicPanel.clear();
Label frameTitle = new Label("Pictures");
for(i=0;i<listSize;i++)
{
if(flag == 0)
{
assetPicPanel.add(frameTitle);
flag = 1;
}
HorizontalPanel vPanelPic = new HorizontalPanel();
System.out.print("heeeeey" +" " + result.get(i).getFromChapter());
Grid g = result.get(i).AssetGrid(result.get(i));
vPanelPic.add(g);
assetPicPanel.add(vPanelPic);
}
}
});
Now when I print the ..get().getFromChapter() on the server side it brings the right values.
But when I print the values that have been returned to the RPC call I get the default constructor values... and not what have to be sent back.
Here also the getPicture implementation on the server side :
public List<PicAsset> getPicture(int book, int chapter) throws Exception
{
System.out.print("getPicture ok " + book +"," + chapter);
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet result = null;
List<PicAsset> relevantAssets = new ArrayList<PicAsset>();
PicAsset relAsset;
try {
conn = getConnection();
pstmt = conn.prepareStatement("SELECT * FROM picasset WHERE book = ? AND fromChapter <= ? AND toChapter >= ?");
//System.out.print("connection" + conn);
pstmt.setInt(1, book);
pstmt.setInt(2, chapter);
pstmt.setInt(3, chapter);
result = pstmt.executeQuery();
// System.out.print(result);
while (result.next()) {
//System.out.print("in while");
relAsset = new PicAsset(result.getInt("picId"),result.getInt("book"), result.getInt("fromChapter"), result.getInt("toChapter"),result.getInt("fromVerse"),result.getInt("toVerse"),result.getString("creator"),result.getString("discription"),result.getString("source"),result.getString("title"),result.getString("duration"),result.getString("url"));
relevantAssets.add(relAsset);
}
}
catch (SQLException sqle)
{
sqle.printStackTrace();
}
finally
{
// Cleanup
result.close();
pstmt.close();
conn.close();
}
System.out.print("In MySql get Chapter " + relevantAssets.get(0).getFromChapter() + " " + relevantAssets.get(0).getIdpic());
return relevantAssets;
}
Within GWT RPC it would be much better to use raw arrays rather than collection interfaces - return from your method PicAsset[] instead of List. This will allow you (a) solve your problem and (b) escape unnecessary classes to be compiled into client code.
See "Raw Types" section at gwtproject.org

Categories