I am trying to implement the server connections with retrofit library.
Everything seems fine but when I receive the data on success callback it crashes with the below exception.
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to aandroid.com.retrofitframework.requestData.DataList
at cuiserve.com.volleyframework.activity.RetrofitActivity$1.onDataReceived(RetrofitActivity.java:18)
at cuiserve.com.volleyframework.httpConnection.ConnectionHelper.success(ConnectionHelper.java:44)
at retrofit.CallbackRunnable$1.run(CallbackRunnable.java:45)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
here is the activity class making the server calls
public class RetrofitActivity extends SuperActivity {
private ConnectionHelper.ServerListener<DataList> httpListener = new ConnectionHelper.ServerListener<DataList>() {
#Override
public void onDataReceived(DataList data) {
hideProgressBar();
Log.d("ANSH",data.getBalance());
}
#Override
public void onErrorReceived(String errorMsg) {
hideProgressBar();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showProgressBar();
ConnectionHelper<DataList> helper = new ConnectionHelper<DataList>(HttpRequestConstant.LOGIN_REQUEST,httpListener);
helper.getResponse();
}
#Override
public View getLayoutResource() {
return null;
}
#Override
protected void internetAvailable() {
}
}
ConnectionHelper.class making the request
public class ConnectionHelper<T> implements Callback<T> {
private int requestType;
private ServerListener<T> listener;
public ConnectionHelper(int requestType, ServerListener listener) {
this.requestType = requestType;
this.listener = listener;
}
public void getResponse() {
switch (requestType) {
case HttpRequestConstant.LOGIN_REQUEST:
IServerConnection<T> connection = restAdapter.create(IServerConnection.class);
connection.login(this);
break;
}
}
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("http://www.json-generator.com/api")
.setLogLevel(RestAdapter.LogLevel.FULL)
.setConverter(new JacksonConverter(Mapper.get()))
.build();
#Override
public void success(T t, Response response) {
listener.onDataReceived(t);
// success callback false here with the exception
// as ClassCastException and says LinkedHashMap can not be cast to DataList(which i pass as class that the response has to be mapped to)
}
#Override
public void failure(RetrofitError error) {
}
public interface ServerListener<T> {
public void onDataReceived(T data);
public void onErrorReceived(String errorMsg);
}
}
The interface and the method with retrofit annotation
public interface IServerConnection<T> {
#GET(HttpRequestConstant.JACKSON_FETCH)
void login(Callback<T> cb);
}
The custom JacksonConverter which is my suspicion
public class JacksonConverter implements Converter {
private ObjectMapper mapper = new ObjectMapper();
public JacksonConverter(ObjectMapper objectMapper) {
this.mapper = objectMapper;
}
#Override
public Object fromBody(TypedInput body, Type type) throws ConversionException {
JavaType javaType = mapper.getTypeFactory().constructType(type);
try {
return mapper.readValue(body.in(), javaType);
} catch (IOException e) {
throw new ConversionException(e);
}
}
#Override
public TypedOutput toBody(Object object) {
try {
String charset = "UTF-8";
String json = mapper.writeValueAsString(object);
return new JsonTypedOutput(json.getBytes(charset));
} catch (IOException e) {
throw new AssertionError(e);
}
}
private static class JsonTypedOutput implements TypedOutput {
private final byte[] jsonBytes;
JsonTypedOutput(byte[] jsonBytes) {
this.jsonBytes = jsonBytes;
}
#Override
public String fileName() {
return null;
}
#Override
public String mimeType() {
return "application/json; charset=UTF-8";
}
#Override
public long length() {
return jsonBytes.length;
}
#Override
public void writeTo(OutputStream out) throws IOException {
out.write(jsonBytes);
}
}
}
and the DataList
package cuiserve.com.volleyframework.requestData;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* Created by ansh on 5/4/15.
*/
#JsonIgnoreProperties(ignoreUnknown = true)
public class DataList extends SomeClass{
private String _id;
private int index;
private String guid;
private boolean isActive;
private String balance;
private String picture;
private int age;
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean isActive) {
this.isActive = isActive;
}
public String getBalance() {
return balance;
}
public void setBalance(String balance) {
this.balance = balance;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Now the problem is when i do it without using generics(which i have done in the code) things work fine and don't give any exception but in case of generics it fails.
Why am I getting LinkedHashMap classCastException where nothing is related to that in my code.Please help.
By using a generic parameter the actual type information is completely lost to the runtime and cannot be inferred. It essentially ends up being the same as Object. When Gson sees that you want an Object type, it uses a Map to place the JSON information in. This way, if you re-serialize that object instance the data will be retained.
You cannot use generic interfaces with Retrofit. An exception has been added when you try to do this rather than letting it fail in this manner for the next release.
Here is what I do to handle such cases:
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;
public abstract class ModelCallback<Model> implements Callback<Object> {
Class classOfT;
public ModelCallback(Class modelClass){
this.classOfT = modelClass;
}
#Override
public void success(Object model, Response response) {
Gson gson = new Gson();
onSuccess((Model) gson.fromJson(gson.toJson(model),classOfT));
}
#Override
public void failure(RetrofitError error) {
onError(new Exception(error.getMessage()));
}
public abstract void onSuccess(Model model);
public abstract void onError(ClyngException e);
}
Related
I want to show Json result in textview using retrofit2, but I can't get the desired result.
json
{
"rows" : [ {
"playerId" : "f8a49812eb9c3e5c8e738c3664e0ebd1",
"nickname" : "Yuichuan",
"grade" : 89
} ]
}
Model.class
public class Model {
public String playerId;
public String nickname;
public int grade;
public String getPlayerId() {
return playerId;
}
public void setPlayerId(String playerId) {
this.playerId = playerId;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
}
PlayerModel.class
public class PlayerModel {
public List<Model> rows;
}
**RetrofitFactory.class**
public class RetrofitFactory {
private static String BASE_URL="https://api.neople.co.kr/";
public static RetrofitService create(){
Retrofit retrofit=new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonC`enter code here`onverterFactory.create()).build();
return retrofit.create(RetrofitService.class);
}
}
RetrofitService.interface
public interface RetrofitService {
#GET("cy/players/")
Call<PlayerModel> getlist(#Query("nickname") String nickname,
#Query("apikey") String apikey);
}
MainActivityt
public class MainActivity extends AppCompatActivity {
private static final String API_KEY = "8yTuVMwy2DirHl2sWaZ3C8IJLslOfTpQ";
private static final String TAG ="Main" ;
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView=findViewById(R.id.test);
RetrofitService networkService=RetrofitFactory.create();
networkService.getlist("Yuichuan",API_KEY)
.enqueue(new Callback<PlayerModel>() {
#Override
public void onResponse(Call<PlayerModel> call, Response<PlayerModel> response) {
if(!response.isSuccessful()){
textView.setText(response.code());
return;
}
Log.d(TAG, "onResponse: ConfigurationListener::"+call.request().url());
}
#Override
public void onFailure(Call<PlayerModel> call, Throwable t) {
textView.setText(t.getMessage());
}
});
}
}
I want to print out these json files, but it doesn't work as I want, so I want you to give me some help or advice.It seems like a simple problem, but it is very difficult for me because I am not used to json.
The textView.setText(response.code()); give you a code of response. To get your data model you need a body of response response.body()
I'm trying to display some json data to textviews. My "getTitle" getter method works fine and the data is shown in the textview widget. However when I should pass the "getDescription" getter method, it doesn't comes up for suggestion.
I would really love some help with this, or also if I'm not going about it the right way someone could point me in the right direction.
call.enqueue(new Callback<Campaign>() {
#Override
public void onResponse(Call<Campaign> call, Response<Campaign> response) {
if (response.isSuccessful()) {
String id = response.body().getId();
campaignName.setText(getTitle());
campaignDesc.setText();
} else {
Toast.makeText(StartSurveyActivity.this, "Error Retrieving Id", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<Campaign> call, Throwable t) {
// Log error here if request failed
Log.e(TAG, t.toString());
}
});
}
Here is my java campaign model class. Also I thought it was important to mention that my "getDescription" getter and setter is shown in a pale greyish color while the "getTitle" getter and setter is the gold looking color. Thanks for your assistance in advance.
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public Boolean getDeleted() {
return deleted;
}
public void setDeleted(Boolean deleted) {
this.deleted = deleted;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSurveyUrl() {
return surveyUrl;
}
public void setSurveyUrl(String surveyUrl) {
this.surveyUrl = surveyUrl;
}
public Integer getTotalResponseCount() {
return totalResponseCount;
}
public void setTotalResponseCount(Integer totalResponseCount) {
this.totalResponseCount = totalResponseCount;
}
public String getLanguageCode() {
return languageCode;
}
public void setLanguageCode(String languageCode) {
this.languageCode = languageCode;
}
public List<Question> getQuestions() {
return questions;
}
public void setQuestions(List<Question> questions) {
this.questions = questions;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public String getOrganisationLogoUrl() {
return organisationLogoUrl;
}
public void setOrganisationLogoUrl(String organisationLogoUrl) {
this.organisationLogoUrl = organisationLogoUrl;
}
public String getOrganisationName() {
return organisationName;
}
public void setOrganisationName(String organisationName) {
this.organisationName = organisationName;
}
Try below, you are calling method on response
campaignName.setText(response.body().getDescription())
The body of the response will hold the data or response object you have defined. So to call any getter or setter method of the response object you have to use body of the response for example response.body().getDescription(), response.body().getCreated(). To show description in the TextView try this
campaignDesc.setText(response.body().getDescription())
I have some api that contains JSON with partner names.
I've set up interface and pojo model. I'll post below my code.
Here is my POJO model Partner:
public class Partner {
#SerializedName("name")
#Expose
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Now here is my interface:
public interface APIService {
#GET("Partner")
Call<List<Partner>> getPartners();
}
And here is my APIHelper:
public class APIHelper {
public static final String PARTNERS_URL = "https://part-of-url.herokuapp.com/partners.json/";
public static APIService apiService;
public static APIService getApiService() {
if (apiService == null) {
Retrofit retrofit = new Retrofit.Builder().baseUrl(PARTNERS_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
apiService = retrofit.create(APIService.class);
}
return apiService;
}
}
And this is Fragment which contains Button where onClick method needs to get data from web.
public class DownloadMain extends Fragment implements Callback<Partner> {
private static final String TAG = DownloadMain.class.getSimpleName();
private Button dloadPartners;
private Call callPartners;
public DownloadMain() {}
public DownloadMain newInstance() { return new DownloadMain(); }
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.download_main, container, false);
dloadPartners = (Button) view.findViewById(R.id.downloadPartners);
dloadPartners.setOnClickListener(btnListener);
callPartners = APIHelper.getApiService().getPartners();
return view;
}
Button.OnClickListener btnListener = (new Button.OnClickListener() {
#Override
public void onClick(View v) {
callPartners.clone().enqueue(DownloadMain.this);
}
});
#Override
public void onResponse(Call call, Response response) {
if(response.body() == null) {
try {
response.errorBody().string();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getActivity(), "No Partners!", Toast.LENGTH_SHORT).show();
} else {
List<String> partners = (List<String>) response.body();
Log.d(TAG, "Number of partners received: " + partners.size());
Toast.makeText(getActivity(), "Partners downloaded!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call call, Throwable t) {
}
}
This is all my code for getting Partners from web.
I'm getting this error on server side and can't resolve it:
No route matches [GET] "/partners.json/Partner"
QUESTION: Can someone look at this code and say what is wrong and why I'm not getting data from web and also how should I resolve this no route error?
change your get path like so
public interface APIService {
#GET("partners.json")
Call<List<Partner>> getPartners();
}
and remove that path from your base url.
public class APIHelper {
public static final String PARTNERS_URL = "https://part-of-url.herokuapp.com/";
public static APIService apiService;
public static APIService getApiService() {
if (apiService == null) {
Retrofit retrofit = new Retrofit.Builder().baseUrl(PARTNERS_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
apiService = retrofit.create(APIService.class);
}
return apiService;
}
}
I hava a function which is returning an object containing a list from a html page :
#Override
public Observable<MediaList> getMediaListFromUrl(String url) {
return getHtml(url)
.map(new Func1<String, MediaList>() {
#Override
public MediaList call(String s) {
return interpreter.interpretMediaResultsFromHtml(s);
}
});
}
What I would like to do next is:
for(Media media : mediaList.getMedias()) {
if (media.getImageUrl().contains("couvertureAjax")) {
// fetch media.getImageUrl
// replace the image url with the result
}
}
and at the end, return the original MediaList object with the replaced image urls.
I think I should use flatmap and from somewhere, but I don't know exactly how.
MediaList.java:
import android.os.Parcel;
import android.os.Parcelable;
import java.util.List;
public class MediaList implements Parcelable {
public static final String TAG = MediaList.class.getSimpleName();
private List<Media> medias;
private String nextPageUrl;
public MediaList() {}
protected MediaList(Parcel in) {
medias = in.createTypedArrayList(Media.CREATOR);
nextPageUrl = in.readString();
}
public List<Media> getMedias() {
return medias;
}
public void setMedias(List<Media> medias) {
this.medias = medias;
}
public String getNextPageUrl() {
return nextPageUrl;
}
public void setNextPageUrl(String nextPageUrl) {
this.nextPageUrl = nextPageUrl;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(medias);
dest.writeString(nextPageUrl);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<MediaList> CREATOR = new Creator<MediaList>() {
#Override
public MediaList createFromParcel(Parcel in) {
return new MediaList(in);
}
#Override
public MediaList[] newArray(int size) {
return new MediaList[size];
}
};
}
As I am not having all classes that are involved here, so I have written a Rx code that would help to achieve what you want:
getHtml(url)
.flatMap(new Func1<String, Media>() {
#Override
public Media call(String s) {
// Here update code interpreter.interpretMediaResultsFromHtml(s) and make sure your return List<Media> from here
return Observable.from(interpreter.interpretMediaResultsFromHtml(s));
}
})
.map(new Func1<Media, Media>() {
#Override
public Media call(Media media) {
// Write code here to update Url in media and return it
return null; // Return updated media object from here
}
})
.toList()
.subscribe(new Action1<List<Media>>() {
#Override
public void call(List<Media> mediaList) {
// Here MediaLkist object will be your updated List<Media>
}
});
Let me know if it fix your issue or you need more details. It's definitely possible what you want to achieve via RxJava.
One way to do this :
#Override
public Observable<MediaList> getMediaList(String url) {
return getHtml(url)
.flatMap(new Func1<String, Observable<MediaList>>() {
#Override
public Observable<MediaList> call(String s) {
MediaList mediaList = interpreter.interpretMediaResultsFromHtml(s);
Observable<List<Media>> list = Observable.from(mediaList.getMedias())
.flatMap(new Func1<Media, Observable<Media>>() {
#Override
public Observable<Media> call(Media media) {
if (media.needImagePreload()) {
return getMediaLoadedImage(media.getImageUrl(), media);
} else {
return Observable.just(media);
}
}
})
.toList();
return Observable.zip(Observable.just(mediaList.getNextPageUrl()), list, new Func2<String, List<Media>, MediaList>() {
#Override
public MediaList call(String s, List<Media> medias) {
return zipMediaList(s, medias);
}
});
}
});
}
private MediaList zipMediaList(String s, List<Media> medias) {
MediaList mediaList = DefaultFactory.MediaList.constructDefaultInstance();
mediaList.setNextPageUrl(s);
mediaList.setMedias(medias);
return mediaList;
}
I think they are easier ways to do this, but it works.
I'm using Retrofit for my Android app, calling it like this:
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.build();
ApiEndpointInterface apiService = restAdapter.create(ApiEndpointInterface.class);
apiService.getFeed(9, new Callback<Post>() {
#Override
public void success(Post post, Response response) {
// loop
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
}
});
The JSON is formatted like this:
{
"success":true,
"data":[
{
"id":"1",
"user_id":"2",
"message":"Hello, world!"
},
{
"id":"2",
"user_id":"1",
"message":"Another hello!"
}
]
}
How can I iterate through each item and, for example, print its message to console? Each item belongs to the Post model:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Post {
public String id;
public String userId;
public String message;
public String getMessage() {
return message;
}
}
Your Main model class look like this.
public class Post {
private String success;
private List<data> data;
public List<data> getData() {
return data;
}
}
Here is your data class.You need to create another class to retrieve json arary(For you it is data.)
public class data {
public String id;
public String userId;
public String message;
public String getMessage() {
return message;
}
}
apiService.getFeed(9, new Callback<Post>() {
#Override
public void success(Post post, Response response) {
post.getData().getPositoin(YourPosition).getMessage(); //or you can use for loop
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
}
});