AutoValue: ClassCastException: LinkedTreeMap cannot be cast to - android

First of all, i'm using retrofit with gson and autovalue-gson extension
Check here : https://github.com/rharter/auto-value-gson
In API i have a different models, where API returns json with id, description etc and also array of messages, but these messages may vary depending on what type of social media i want to (facebook, twitter, instagram etc...). So i made model like this :
#AutoValue
public abstract class SocialStream<T> {
public abstract int id();
......
......
public abstract List<T> messages();
public static <T> TypeAdapter<SocialStream<T>> typeAdapter(Gson gson, TypeToken<? extends SocialStream<T>> typeToken) {
return new AutoValue_SocialStream.GsonTypeAdapter(gson, typeToken);
}
}
As you can see i also passed typetoken to AutoValue typeAdapter, and everything seems to work, i already logged whole json, but problem occurs when i try to use it as my model.
SocialStream<FacebookPost> post = getList().get(0);
method getList() returns array of these messages and this is the line where i'm getting exception:
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.example.model.FacebookPost
at

I have exactly the same problem like me. The key is creating a customized deserializer as Gson has no idea about the real class inside.
try this
https://stackoverflow.com/a/34685986/2458190

Related

How do I use the generic type T with Retrofit?

I want to use T in Retrofit, but I do not know, how to set T in Retrofit.create(X.class) method.
public interface SupportService<T> {
#GET
Flowable<BaseResponse<T>> getApi(#Url String url, #Query("data") JsonObject jsonObject);
}
HttpRetrofit.getInstance()
.getRetrofit(this)
.<SupportService<T>>create(SupportService.class)
.getApi("",null)
public class BaseResponse<T>{
public int code;
public String message;
public T data;
}
"T" stays for a generic type of your choice. In retrofit, you can define your data model class accordingly to api response, for example with #SerializedName annotation if you are using GSON as serializing library. That "T" type will be the class defined for the api response. Here you can find a simple starting point tutorial about retrofit.

Retrofit - use response class with inheritance

I'm trying make reuse of single retrofit api call by inherit from a base response class.
However I'm not able to do it.
I will try to make myself clear with example (It's not a concrete scenario. I'm just trying to figure out the main idea):
Having this response objects and api service:
public class UserDetailsResponse
{
private int userId;
}
public class ExtendedUserDetailsResponse extends UserDetailsResponse
{
private int userAdditionalId;
}
interface APIService
{
#GET("/UserDetails/")
Call<UserDetailsResponse> getUserDetails(#Query("id") String userId);
}
Is there a way of using getUserDetails api with ExtendedUserDetailsResponse object?
This one gives me compilation error:
mService.getUserDetails("123").enqueue(new Callback<ExtendedUserDetailsResponse>()
{
#Override
public void onResponse(Call<ExtendedUserDetailsResponse> call, Response<ExtendedUserDetailsResponse> response)
{
}
#Override
public void onFailure(Call<ExtendedUserDetailsResponse> call, Throwable t)
{
}
});
How can I solve this? or at least something similar to this, without using a new api call for the specific derived class?
Thanks!
You get an error because ExtendedUserDetailsResponse is a UserDetailsResponse, however, UserDetailsResponse is not necessarily an ExtendedUserDetailsResponse.
In order to make it generic, sign your method this way
Call< ExtendedUserDetailsResponse > getUserDetails(#Query("id") String userId);
Then ExtendedUserDetailsResponse will have access to userId
Remember to expose userId with getters and setters so that it get parsed.
You are getting compilation error because you are using the wrong callback object:
Just change this line:
Call<UserDetailsResponse> getUserDetails(#Query("id") String userId);
to
Call<ExtendedUserDetailsResponse> getUserDetails(#Query("id") String userId);
Or depending on the response change the object in the callback
Note that ExtendedUserDetailsResponse will have userId so you can use ExtendedUserDetailsResponse even if the server returns object of type UserDetailsResponse or ExtendedUserDetailsResponse.

deserialize complicated gson string

Hi I hope someone here can help me, I am working in an android app, I already serialize the following gson object
Screenshot:
the jsonobject has many subclasses like:
PreferencialaboraEstudio,Preferencialaboralarea, and more classes,
I transfer this gson object from an activity to a new activity, in order to deserialize this object I have implemented the following code in the new activity:
Intent intent = getIntent();
String Postulado = intent.getStringExtra("Postulado");//Postulado from extra is actually a gson object
Candidato candidato = gson.fromJson(Postulado, Candidato.class);
CandidatoPreferenciaLaboralEstado preflaboraledo = gson.fromJson(Postulado, CandidatoPreferenciaLaboralEstado.class);
I have the problem in CandidatoPreferenciaLaboralEstado, as you can see in the picture there are two items of this type class in the gson object, but my code only returns the first item and not the second one, is there a way to get all the items of this type "CandidatoPreferenciaLaboralEstado" from the gson?
Thank you very much for your time and assistance in this matter.
Not sure how your root model is, but you can have something like this:
public class Postulado {
private CandidatoPreferenciaLaboralEstado candidatoPreferenciaLaboralEstado;
private CandidatoSoftware candidatoSoftware;
public class CandidatoPreferenciaLaboralEstado {
private List<CandidatoPrefAttributes> candidatoAttributesList;
public class CandidatoPrefAttributes {
private Integer cveCandidato;
private Integer cveCandidatoPreferenciaLaboralEstado;
//More
}
}
public class CandidatoSoftware {
private List<CandidatoSoftwareAttributes> candidatoAttributesList;
public class CandidatoSoftwareAttributes {
private Integer cveCandidato;
private Integer cveCandidatoSoftware;
//More
}
}
}
With respective getters.
Also looks that the candidates (CandidatoPreferenciaLaboralEstado and CandidatoSoftware) and Candidate Preferences are very similar, maybe you can unify that models to one (Candidate and CandidatePrefferences) and use multiple serialized names like:
#SerializedName(value="candidatoPreferenciaLaboralEstado", alternate={"candidatoSoftware"})
Hope this can help you!

Which one was the best approach to implementing Asynchronous service call in android

I would like to implement a service(Web service) call in my application.
I blocked here for a while.
Previously I followed some of the below concepts.
like, AsyncTask class, Thread concepts and Handlers.
Recently I heard about the Retrofit.
Based on by experience, retrofit was good with high performance.
But it's not that much of reliable.
Example:
{
"Tag1":"Tag Value",
"TagArray":[ {"key1":"value","key2":"value"},{"key1":"value","key2":"value"},{"key1":"value","key2":"value"} ]
}
POJO:
public class Data{
String key1,key2;
sterres...
getters..
}
If the response have some other tags that are no need and the inside data only we need in our app i,e. "TagArray".
I need the handle only this response.
In such type of case this retrofit was failed.
Is there any other libraries or any other components to implement service calls in android with high performance are existed.
You can add your POJOs' or Beans' fields #Optional. This option comes from GSON that used in Retrofit as default.
EDIT :
public class ExamplePojo implements Serializable {
#SerializedName("TagArray")
public ArrayList<Keys> TagArray;
public ExamplePojo() {
TagArray = new ArrayList<>();
}
public static class Keys{
#SerializedName("key1")
public String key1;
#SerializedName("key2")
public String key2;
}
}
The attributes which you ignore shouldnt be added on POJO class or as mention above, add optional annotation if it can be null.

Haxe: How can I setup a class to store data in an array of type that I pass in the constructor

I am coding in Haxe, Lime, OpenFl. I am trying to set up a Class to store data in a Map, referenced by class instance. The class type is to be passed in the constructor, via inference. But I am quite new to all this and can't quite figure out the syntax, this is what I got so far:
class DynamicStore<A>
{
private var hashA:Map<Class<A>,String>;
public function new<A>(paramA:Class<A>) {
hashA = new Map();
}
}
But this gives me the following error:
Abstract Map has no #:to function that accepts IMap<Class<DynamicStore.A>, String>
Is there a way to do this?
A question first:
do you really want to use classes as key? or objects?
In classes should be the key
It would be much simpler to use the classe's full name as key, like "mypackage.blob.MyClass". It's safer, easier to handle and debug.
Map<String, String>
Would suffice in that case.
If objects should be keys
Then the code would look like:
import haxe.ds.ObjectMap;
class Test<A>
{
static function main() {}
private var hashA :ObjectMap<A,String>;
public function new(paramA:A) {
hashA = new ObjectMap<A,String>();
}
}
The reason "Map" cannot be directly used in this case is that "Map" is a syntactic sugar, being resolved to StringMap, IntMap or others depending on the key type. If it doesn't know what kind of map to be used, it cannot proceed (this is mainly due to cross-compiling issues).
Remark
As a final note, I would mention your construction seems a bit wacky/strange to me. It would be interesting to know what you are trying to achieve and why you structure it the way you do.
I don't think you can use Class as the key of a Map. A good work around it to use a String as a key and the fully qualified names of the types. You can also define an abstract to move from the Type to String easily ... something like the following (code not-tested);
private var hashA : Map<String, String>;
public function addClass(className : ClassId, ...)
And the abstract will look something like this:
abstract ClassId(String) {
inline public function new(name : String) this = name;
#:from public static inline function fromClass(cls : Class<Dynamic>)
return new ClassId(Type.getClassName(cls));
#:to public inline function toClass() : Class<Dynamic>
return Type.resolveClass(this);
#:to public inline function toString() : String
return this;
}

Categories

Resources