Skip to content
This repository was archived by the owner on Aug 9, 2020. It is now read-only.
This repository was archived by the owner on Aug 9, 2020. It is now read-only.

RxCache not support generic paradigm #73

Closed
@ml-bright

Description

@ml-bright

like this:

class Response<T> {

    int code;

   T data;

 }

I want to cast to Response<List<City>> use the T

while throw exception java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap

Activity

ml-bright

ml-bright commented on Dec 24, 2016

@ml-bright
Author

I solved this problem use other method

before

 Observable<List<City>> getHotCityList(Observable<Response<List<City>>> hotCitys, EvictProvider evictProvider);

change like this:

 Observable<List<City>> getHotCityList(Observable<String> hotCitys, EvictProvider evictProvider);

we just change Observable<Response<List<City>>> hotCitys to Observable<String> hotCitys use retrofit.

the next step:

use rxjava compose to String -> Response<List<City>>

apiServiceCache.getHotCityList(stringObservable, new EvictProvider(false))
            .compose(ComposeString2List.newCompose(new TypeToken<Response<List<City>>>(){}))

ComposeString2List.java:

 public class ComposeString2List<T> implements Observable.Transformer<String, List<T>> {

     public TypeToken<Response<List<T>>> typeToken;

     public static ComposeString2List newCompose(TypeToken typeToken) {
        return new ComposeString2List(typeToken);
    }

    public ComposeString2List(TypeToken<Response<List<T>>> typeToken) {
        this.typeToken = typeToken;
    }

    @Override
     public Observable<List<T>> call(Observable<String> responseObservable) {
         return NetworkUtils.isNetworkAvailableObservable()
                 .flatMap(aBoolean -> responseObservable)
                 .flatMap(new ReadListFunc(typeToken))
                 .onErrorResumeNext(ResponseErrorHandle.errorResumeFunc())
                 .subscribeOn(Schedulers.io())
                 .observeOn(AndroidSchedulers.mainThread());
     }

     // 读取列表数据
     private static class ReadListFunc<E> implements Func1<String, Observable<List<E>>> {

         private TypeToken<Response<List<E>>> typeToken;

         public ReadListFunc(TypeToken<Response<List<E>>> typeToken) {
             this.typeToken = typeToken;
         }

        @Override
         public Observable<List<E>> call(String responseReply) {
             Response<List<E>> response = new Gson().fromJson(responseReply, typeToken.getType());
             if (response != null && response.code == ReturnCode.CODE_SUCCESS) {
                 return Observable.just(response.data);
             } else {
                 return Observable.error(new Throwable());
             }
         }
     }

 }

hope this to help you

VictorAlbertos

VictorAlbertos commented on Dec 24, 2016

@VictorAlbertos
Owner

RxCache delegate this kind of responsibility to the current jolyglot provider.

In your case, it is Gson, so you will need to be aware about its limitations (configuration) when marshalling/unmarshalling data.

vihuela

vihuela commented on Jun 20, 2017

@vihuela

There is another way
Use Explicit Type

public class BaseResponse<T> {
    public int code;
    public List<T> results;
}
public class ApiResponse extends BaseResponse<ApiResponse.FocusListItem> {

    public static class FocusListItem {
        。。。
    }
}
Observable<Reply<ApiResponse>> getFocusList(Observable<ApiResponse> observable, EvictProvider evictProvider);
XiFanYin

XiFanYin commented on Aug 27, 2017

@XiFanYin

能不能来个中文版本的解决方案,本人就是遇到这个问题,不知道什么原因导致的

JessYanCoding

JessYanCoding commented on Feb 5, 2018

@JessYanCoding
Contributor

@XiFanYin 其实上面已经给出解决方案了, 很多人没看懂? 那我来总结一下, 之前的写法是, 自己创建一个实体类, 如 User, 然后使用 BaseData< User > 作为服务器返回的结果,
由于 RxCache 的一些限制, 导致 BaseData 中, 范型为 T 的字段 data 的实际类型没有作为缓存被正常保存到本地, 所以导致获取缓存时不能正常解析 data , 从而报错 java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap

现在的解决方案是, 稍微修改下之前定义的 User, 然后直接使用 User 作为服务器返回的结果, 这个解决方案对之前的代码改变较小, 也比较简单, 代码如下:

public class BaseData<T> {
    private int code;
    private String msg;
    private T data;

    public T getData() {
        return data;
    }
}

只要继承 BaseData 并指定范型 (如果不是集合则继承 BaseData<User>) 即可, 其他都不用改
public class User extends BaseData<List<User>> {
    private int id;
    private String name;

    public int getId() {
        return id;
    }
}

Observable<User> getUsers(Observable<User> users, DynamicKey idLastUserQueried, EvictProvider evictProvider);

....

这是获取数据的方式
List<User> data = user.getData();
int id = data.get(0).getId();
jonenet

jonenet commented on Jun 6, 2018

@jonenet

User会持有List ,List data中又存在User ,请问这种方式不会有问题吗?

JessYanCoding

JessYanCoding commented on Jun 6, 2018

@JessYanCoding
Contributor

@jonenet User 作为 的时候, 它即是 BaseData 又是 JavaBean,但当 User 被解析为对象进行操作时,只是把它看作是两种角色中的一个,这个方式在理解上可能比较绕,但是确不会对结果产生什么影响, 也是现在最简单的解决方案,只是需要注意 User 对象在不同的角色做不同的操作即可

如果你觉得这个方式不好理解,你也可以使用上面那个兄弟在 User 中定义一个内部类的方式,其实达到的目的都是一样的

IurKwan

IurKwan commented on Jun 7, 2018

@IurKwan

直接用 T 作为缓存应该可以吧

ghost

ghost commented on Sep 8, 2018

@ghost

@VictorAlbertos Hi, I meet the same issue with @ml-bright , and I also tried JacksonSpeaker, but also got the error "java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX.entity.HomeFloorBean" , my response class is BaseResponse<List<HomeFloorBean>>,
I am using MVPArms @JessYanCoding

4 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @VictorAlbertos@ml-bright@xilost@vihuela@JessYanCoding

        Issue actions

          RxCache not support generic paradigm · Issue #73 · VictorAlbertos/RxCache