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 httpListener = new ConnectionHelper.ServerListener() {
@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 helper = new ConnectionHelper(HttpRequestConstant.LOGIN_REQUEST,httpListener);
helper.getResponse();
}
@Override
public View getLayoutResource() {
return null;
}
@Override
protected void internetAvailable() {
}
}
ConnectionHelper.class making the request
public class ConnectionHelper implements Callback {
private int requestType;
private ServerListener listener;
public ConnectionHelper(int requestType, ServerListener listener) {
this.requestType = requestType;
this.listener = listener;
}
public void getResponse() {
switch (requestType) {
case HttpRequestConstant.LOGIN_REQUEST:
IServerConnection 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 {
public void onDataReceived(T data);
public void onErrorReceived(String errorMsg);
}
}
The interface and the method with retrofit annotation
public interface IServerConnection {
@GET(HttpRequestConstant.JACKSON_FETCH)
void login(Callback 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.