Retrofit parse empty array [] - android

I need to parse list of object, whith can be emply. {"data":[]}
I use tamplated callback CallBack<T>called with
public static DataList {
public List<Data> data
};
api.getData(new Callback<DataList>() {...});
it crashed with error:java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com...DataList
Please help

Your model should work fine. Perhaps your server isn't returning what you think it does, or maybe its not application/json what it's returning?
Here's a quick demo:
Doing a GET on the url http://www.mocky.io/v2/5583c7fe2dda051e04bc699a will return the following json:
{
data: [ ]
}
If you run the following class, you'll see it works just fine:
public class RetrofitDemo {
interface API {
#GET("/5583c7fe2dda051e04bc699a")
void getDataList(Callback<DataList> cb);
}
static class DataList {
List<Data> data;
}
static class Data {
}
public static void main(String[] args) {
API api = new RestAdapter.Builder()
.setEndpoint("http://www.mocky.io/v2")
.build()
.create(API.class);
api.getDataList(new Callback<DataList>() {
#Override
public void success(DataList dataList, Response response) {
System.out.println("dataList=" + dataList);
}
#Override
public void failure(RetrofitError retrofitError) {
throw retrofitError;
}
});
}
}

Your issue is your java model doesn't reflect the data it's trying to deserialize to.
//{"data":[]} does not map to List<Data> data.
// If the server was just returning an array only then it would work.
// It will match to the entity below make sure your cb = Callback<MyItem>
public class MyItem {
List<Data> data;
}

Related

how to deserialize json object and add response to arraylist

I am creating an app using soundcloud api but I am getting error while parsing json object, I am new in this things so don't know what I am doing wrong here
Here is my interface
ScService.java
public interface SCService
{
#GET("/resolve.json?url=https://m.soundcloud.com/kshmr/sets/materia&client_id=iZIs9mchVcX5lhVRyQGGAYlNPVldzAoX")
Call<Track> getTrack();
}
Here is my model class
Track.java
public class Track
{
#SerializedName("title")
private String mTitle;
#SerializedName("stream_url")
private String mStreamUrl;
public String getTitle()
{
return mTitle;
}
public String getStreamUrl()
{
return mStreamUrl;
}
}
MainActivity.class
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Config.API_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
SCService Scservice = retrofit.create(SCService.class);
Call<Track> call = Scservice.getTrack();
call.enqueue(new Callback<Track>(){
#Override
public void onResponse(Call<Track> call, Response<Track> response)
{
// TODO: Implement this method
if(response.isSuccessful())
{
//String track = response.body().toString();
//Log.e("jsonres",track);
//gson = new GsonBuilder().create();
gson = new Gson();
Track track = gson.fromJson(response.body().toString(), Track.class);
}
#Override
public void onFailure(Call p1, Throwable p2)
{
// TODO: Implement this method
}
});
}
Here is the JSON response from api callcall
enter code here
{"kind":"track","id":399448641,"created_at":"2018/02/14 11:40:02 +0000","user_id":319295181,"duration":188726,"commentable":true,"state":"finished","original_content_size":33279566,"last_modified":"2018/03/10 17:33:18 +0000","sharing":"public","tag_list":"KSHMR \"House of Cards\" \"Sidnie Tipton\" Dharma \"Spinnin' \"","permalink":"houseofcards-mixmaster-05b","streamable":true,"embeddable_by":"all","purchase_url":"http://www.spinninrecords.com/releases/house-of-cards","purchase_title":"Download/Stream","label_id":null,"genre":"Dance & EDM","title":"KSHMR - House of Cards (Ft. Sidnie Tipton)","description":"KSHMR and Sidnie Tipton team up again, this time for the bittersweet sound of \"House of Cards\" \n\nDownload / Stream here: https://www.spinninrecords.com/releases/house-of-cards/","label_name":null,"release":null,"track_type":null,"key_signature":null,"isrc":null,"video_url":null,"bpm":null,"release_year":null,"release_month":null,"release_day":null,"original_format":"wav","license":"all-rights-reserved","uri":"https://api.soundcloud.com/tracks/399448641","user":{"id":319295181,"kind":"user","permalink":"dharmaworldwide","username":"Dharma Worldwide","last_modified":"2018/03/09 12:08:27 +0000","uri":"https://api.soundcloud.com/users/319295181","permalink_url":"http://soundcloud.com/dharmaworldwide","avatar_url":"https://i1.sndcdn.com/avatars-000324744374-jdrkyv-large.jpg"},"permalink_url":"https://soundcloud.com/dharmaworldwide/houseofcards-mixmaster-05b","artwork_url":"https://i1.sndcdn.com/artworks-000302088414-recq7g-large.jpg","stream_url":"https://api.soundcloud.com/tracks/399448641/stream","download_url":"https://api.soundcloud.com/tracks/399448641/download","playback_count":135077,"download_count":0,"favoritings_count":7351,"reposts_count":1354,"comment_count":120,"downloadable":false,"waveform_url":"https://w1.sndcdn.com/0Bcy6WpC8dzY_m.png","attachments_uri":"https://api.soundcloud.com/tracks/399448641/attachments","policy":"ALLOW","monetization_model":"NOT_APPLICABLE"}
I can't use gson.fromJson(...) method, how could I fix this?
Ps-I have pretty much changed my code.
You should do:
EDIT:
ScService.java
public interface SCService
{
#GET("users/17586135/tracks?client_id=iZIs9mchVcX5lhVRyQGGAYlNPVldzAoX")
Call<Track> getTrack();
}
MainActivity.class
Call<Track> call = Scservice.getTracks();
call.enqueue(new Callback<Track>(){
#Override
public void onResponse(Call call, Response<Track> response)
{
// Get the result
Track track = response.body();
}
#Override
public void onFailure(Call p1, Throwable p2)
{
// TODO: Implement this method
}
});
}
More here
The Gson object should be used in this way:
gson = new GsonBuilder().create();
Track track = gson.fromJson(response.body().toString(),Track.class);

How to load data from local realm db?

I have populated data from server in UI through realm and volley.
Is it possible to store that data locally and show in UI from local db? And how to do it?
Any example would be very helpful.Thanks.
Actually I am trying to get the data locally after fetching and populating the data from the server like this.
if(realm!=null){
Log.d(AppConstants.TAG, "realm fetching");
RealmResults<SellerProducts> sellerProductItems=realm.where(SellerProducts.class).findAll();
adapter.setData(sellerProductItems);
adapter.notifyDataUpdate();
}else {
//network fetch operation
// getting data
//populating data like this
sellerProductItems= gson.fromJson(products.toString(), new TypeToken<List<SellerProducts>>(){}.getType());
//Products is from server response
realm.beginTransaction();
realm.copyToRealmOrUpdate(sellerProductItems);
realm.commitTransaction();
adapter.setData(sellerProductItems);
adapter.notifyDataUpdate();
}
Is it correct?
To save data in realm create a realm object and do Transaction like this
myRealm.beginTransaction();
// Create an object
Country country1 = myRealm.createObject(Country.class);
country1.setName("Norway");
country1.setPopulation(5165800);
country1.setCode("NO");
myRealm.commitTransaction();
To read the data saved
RealmResults<Country> results1 =
myRealm.where(Country.class).findAll();
for(Country c:results1) {
Log.d("results1", c.getName());
}
For complete information visit
http://code.tutsplus.com/tutorials/up-and-running-with-realm-for-android--cms-25241
No, you're completely wrong. If you're doing it right, realm can never be null at that point in your code.
Anyways it works vaguely like this (based on this):
public class GsonRequest<T extends RealmObject> extends Request<T> {
private final Gson gson = new Gson();
private final Listener<T> listener;
/**
* Make a GET request and return a parsed object from JSON.
*
* #param url URL of the request to make
*/
public GsonRequest(Method method, String url,
Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.listener = listener;
}
#Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
final List<T> result = gson.fromJson(json, new TypeToken<ArrayList<T>>() {}.getType());
Realm realm = null;
try {
realm = Realm.getInstance(realmConfiguration); //get realm config
realm.executeTransaction(new Realm.Transaction() {
for(T t : result) {
realm.copyToRealmOrUpdate(t);
}
});
} finally {
if(realm != null) {
realm.close();
}
}
return Response.success(null, //returning null because
//Realm handles all reload of data on UI thread
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
}
And
Realm realm;
RealmResults<SellerProducts> results;
final RealmChangeListener<RealmResults<SellerProducts>> realmChangeListener;
SellerProductsAdapter adapter;
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
realm = Realm.getInstance(this);
results = realm.where(SellerProducts.class).findAll();
realmChangeListener = new RealmChangeListener<RealmResults<SellerProducts>>() {
#Override
public void onChange(RealmResults<SellerProducts> element) {
adapter.notifyDataSetChanged();
}
}
setContentView(R.layout.retrofit_is_better_than_volley);
ListView whyIsThisNotRecyclerView = (ListView) findViewById(R.id.not_recycler_for_some_reason_view);
adapter = new SellerProductsAdapter(this, results);
whyIsThisNotRecyclerView.setAdapter(adapter);
results.addChangeListener(realmChangeListener);
}
#Override
public void onDestroy() {
if(results != null && results.isValid()) {
results.removeChangeListener(realmChangeListener);
}
if(realm != null) {
realm.close();
}
super.onDestroy();
}
And then something like
GsonRequest<SellerProducts> request = new GsonRequest(Method.GET, url,
new Response.Listener<SellerProducts>() {
#Override
public void onResponse(SellerProducts nullObject) {
// hide dialog or something
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Error: " + error.getMessage()/*, exception? */);
// hide dialog or something
}
});
//add to request queue
If you are planning to bring Realm to your production code, it takes more than what is discussed here, Realm is a major library and there are also some limitations like Realm, RealmObject and RealmResults can not be passed across threads.
To solve this problem, you need a good architecture, where Realm is isolated from rest of the code. Create a realmModel for each jsonModel and a DAO (Data Access Object). All Realm related calculations should be part of DAO, so that none of your code base needs to know about Realm.
Here is an article about Realm best practices with a good architechture https://medium.com/#Viraj.Tank/realm-integration-in-android-best-practices-449919d25f2f
Also a sample project demonstrating Integration of Realm on Android with MVP(Model View Presenter), RxJava, Retrofit, Dagger, Annotations & Testing. https://github.com/viraj49/Realm_android-injection-rx-test

How to bind Json response to class using volley

In my application, I want to bind Json response to a target class using Volley library, But am not able to do that.
My Code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerComponentDownload(GalleryParser.class, Const.api.URL_GALLERY);
}//on create
private void makeJsonObjectRequest(final Class<? extends BaseModel> className, String urlJsonArry) {
JsonObjectRequest jsonObjectRequest=new JsonObjectRequest(Request.Method.GET,urlJsonArry,null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//start gallery activity
}
} , new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
AppController.getInstance().addToRequestQueue(jsonObjectRequest);
}
private void registerComponentDownload(Class<? extends BaseModel> aClass, String url) {
makeJsonObjectRequest(aClass,Const.buildUrl(url));
}
}
Is it possible to get response in class? Or am trying in wrong direction.
Please suggest me.
Thank you.
I think you can refer to this using volley with gson library to make a Gson request
https://developer.android.com/training/volley/request-custom.html
Add Gson Library in you lib folder .
this is class formate
public class TestData {
public int success;
public String message;
public TestDatail data;
public class TestDatail
{
public int is_friend;
public int is_following;
}
}
Gson gs=new Gson();
return gs.fromJson(your Volley Library Response,TestData.class);
Method 1:Using Bundle object-->
In my case i'm passing an array from Activity A to Activity B something like this:
public void onResponse(JSONObject response)
{
ArrayList<Images> imagesArrayList = new ArrayList<Images>();
try{
if(response.has("images"))
{
JSONArray imagesList = response.getJSONArray("images");
Intent i = newIntent(ActivityA.this,ActivityB.class);
i.putExtra("jsonArray",imagesList.toString());
startActivity(i);
}
}catch(JSONException e){}
}
And in Activity B's onCreate method check for the that passed bundle something like this:
Intent i = getIntent();
if (i.hasExtra("jsonArray"))
{
String jsonArray = i.getStringExtra("jsonArray");
try {
JSONArray array = new JSONArray(jsonArray);
// do whatever you need with this array
} catch (JSONException e) {
e.printStackTrace();
}
}
Method 2: Using pojo/getters & setter
Create a pojo
Extract the required data once you receive the response using volley.
set it using setters of pojo.
start gallery activity.
get the data using getters of pojo.

How to get different objects with Retrofit Android

I'm using Retrofit 1.9.0 in Android Studio to get a response from my REST API.
The method I want to do is GET, on this URL: http://dotfreeride.com/api/rest/adventures.php
I successfully retrieved the response for another API but that had only 1 object, this has 3 big objects.
My IApiMethods interface is like this:
#GET("/adventures.php")
JSONObject getAdventures(
Callback<AdventuresApi> cb
);
My AdventuresApi (Model class) is like this:
public class AdventuresApi {
public String adventure_id;
public String trimaps_context;
public String name;
public String video_url;
public List<ArrayPoi> array_poi;
public class ArrayPoi {
String poi_id;
String name;
String lat;
String lng;
String video_url;
}
}
My Retrofit call in the Activity is like this:
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(API_URL)
.build();
IApiMethods methods = restAdapter.create(IApiMethods.class);
Callback callback = new Callback() {
#Override
public void success(Object o, Response response) {
}
#Override
public void failure(RetrofitError error) {
Log.e("JSON", "NO DATA!");
}
};
methods.getAdventures(callback);
I don't really know how to get the objects, I want to get the name of the object (Example: where trimaps_context is "verb", I need the name "Powder Hound")
For a single object I successfully did it like this in onResponse(Object o, Response response):
(ProfileApi) profileData = (ProfileApi) o;
Log.e("JSON", profileData.name + " " + profileData.email);
1) You are trying to combine both synchronous and asynchronous call. If you want to perform a request asynchronously you have to define it like this:
#GET("/adventures.php")
void getAdventures(
Callback<List<AdventuresApi>> cb
);
2) Do not create RestAdapter instance everytime you call request. It's really heavyweight operation. Use singleton pattern. You can then simply call:
ApiManager.getAdapter().getAdventures(...);
3) Object mapping is provided by parametrized Callback class:
ApiManager.getAdapter().getAdventures(
new Callback<List<AdventuresApi>>() {
#Override
public void success(List<AdventuresApi> adventures, Response response) {
// here you can access the adventures list
}
#Override
public void failure(RetrofitError error) {
// handle error
}
});

Strongloop/Loopback findAll feature returns null

I'm developing an Android application in conjunction with Strongloop/Loopback. I've stored my data in a MySQL database and have no problem mapping this with Strongloop/Loopback. However, when retrieving the values from the database using Strongloop/Loopback, the list always return a size but with null values. Can't figure out what is wrong. Can anybody help me with this? Many thanks :)
Here is my json response for the database when access from Strongloop:
[
{
"rewards_image_name": "http://x.x.x.x/projects/images/rewards_1.png",
"rewards_equivalent_points": "10",
"id": 1 }, {
"rewards_image_name": "http://x.x.x.x/projects/images/rewards_2.png",
"rewards_equivalent_points": "20",
"id": 2 }, {
"rewards_image_name": "http://x.x.x.x/projects/images/rewards_3.png",
"rewards_equivalent_points": "30",
"id": 3 }, {
"rewards_image_name": "http://x.x.x.x/projects/images/rewards_4.png",
"rewards_equivalent_points": "40",
"id": 4 }
]
Here is my code for getting the list:
StrongloopClient strongloopClient = new StrongloopClient(this.context);
RestAdapter adapter = strongloopClient.getLoopBackAdapter("Rewards", "GET");
StrongloopRewardsModelRepository strongloopRewardsModelRepository = adapter.createRepository(StrongloopRewardsModelRepository.class);
strongloopRewardsModelRepository.findAll(new ListCallback<StrongloopRewardsModel>() {
#Override
public void onSuccess(List<StrongloopRewardsModel> arg0) {
Log.e("", "GetAllRewards success: " + arg0.get(0).getEquivalentPoints());
}
#Override
public void onError(Throwable arg0) {
Log.e("", "GetAllRewards error: " + arg0);
}
});
Here is the StrongloopClient:
public class StrongloopClient {
private Context context;
private RestAdapter adapter;
public StrongloopClient(Context contxt) {
context = contxt;
}
public RestAdapter getLoopBackAdapter(String transaction, String operation) {
if (adapter == null) {
adapter = new RestAdapter(context, "http://192.168.44.101:3000/api");
adapter.getContract().addItem(
new RestContractItem("/" + transaction, operation),
transaction);
}
return adapter;
}
Here is the code for Repository:
public class StrongloopRewardsModelRepository extends ModelRepository<StrongloopRewardsModel>{
public StrongloopRewardsModelRepository() {
super("Rewards", "Rewards", StrongloopRewardsModel.class);
}
}
And this is the Model:
public class StrongloopRewardsModel extends Model {
private Integer rewardsImageId;
private String rewardImageName;
private String equivalentPoints;
public Integer getRewardsImageId() {
return rewardsImageId;
}
public void setRewardsImageId(Integer rewardsImageId) {
this.rewardsImageId = rewardsImageId;
}
public String getRewardImageName() {
return rewardImageName;
}
public void setRewardImageName(String rewardImageName) {
this.rewardImageName = rewardImageName;
}
public String getEquivalentPoints() {
return equivalentPoints;
}
public void setEquivalentPoints(String equivalentPoints) {
this.equivalentPoints = equivalentPoints;
}
}
Finally, I've found what was wrong. POJOs should match the fields of models created in models.json. Thanks for your time.
However, my other question is that, when I used filters for querying such as passing the filters as part of "parameters" being passed to Strongloop adapter, it seems to return all of the model instances instead of filtered ones. Same code from my question, just that getLoopbackAdapter("Rewards","GET") becomes "Rewards?filter[where][rewards_equivalent_points]=10","GET"). Any ideas why it behaved like that? Thanks :)
This is because your search didn't find any instance. I'm not sure if you need to handle this on your App or if the SDK deals with that.
For example, when trying to search by an element[1] through the rest interface, it gets converted to 404 (not found): rest: {after: convertNullToNotFoundError}
https://github.com/strongloop/loopback-datasource-juggler/blob/master/lib/dao.js#L771

Categories

Resources