微信IAccessTokenCache泛型问题

我自己实现IAccessTokenCache接口,把token存在数据库中,我是通过序列化成JSON字符串存到数据库的,存入的时候没问题。

但是取出来的时候,反序列化成一个泛型对象是有问题的(这个应该是java泛型实现的不好),泛型反序列化的时候,java的类型参数作为另一个方法的参数好像无效....

public class MySqlAccessTokenCache implements IAccessTokenCache {
    private String keyPre = "WX_";

    @Override
    public <T> T get(String s) {
        DictCache dictCache = DictCacheService.instance.get(keyPre + s);
        if (dictCache != null) {
            //******************************************************************
            //这里返回的不是T类型的对象,而是fastjson里的com.alibaba.fastjson.JSONObject
            //gson也是一样,返回com.google.gson.internal.LinkedTreeMap
            //******************************************************************
            return JSON.parseObject(dictCache.getValue(), new TypeReference<T>() {});
        } else {
            return null;
        }
    }
    @Override
    public void set(String s, Object o) {
        String json = JSON.toJSONString(o);
        DictCache dictCache = new DictCache();
        dictCache.setKey(keyPre + s);
        dictCache.setValue(json);
        DictCacheService.instance.set(dictCache);
    }

    @Override
    public void remove(String s) {
        DictCacheService.instance.remove(keyPre+s);
    }
}

我感觉你是要用这个接口同时存取AccessToken和SnsAccessToken,所以我也不能在反序列化的时候把T写AccessToken或SnsAccessToken

评论区

JFinal

2016-07-19 22:09

接收返回值的类型是怎样的? java 的泛型的确有缺陷,如果没有办法得到正确的类型,建议在 key 值中添加类型信息,这样在 get 时通过 key 判断类型,在 parse 时再用明确地类型。例如 key 为 "atoken_xxx" 或 "sToken_xxx"。 @如梦技术

JFinal

2016-07-19 22:09

@dreamelu

JFinal

2016-07-19 22:10

loogn

2016-07-19 22:59

@JFinal 嗯,但是key是由内部传过来的,所以估计要内部来该,可以在 public T get(String s)这个方法上再加个Class类型的参数,内部调用的时候传AccessToken.class和SnsAccessToken.class

Dreamlu

2016-07-20 09:26

@loogn 我也是这样想的,我先试验一遍,搞不定就加一个参数。

JFinal

2016-07-20 10:10

@Dreamlu 假如重载一个 set 方法呢? 一共两个 set 方法,将 Object 参数改成实际的AccessToken 确切类型,此外建议将 set 方法改成 put 方法,这个在 cache 系统中更符合使用习惯,put 兼有覆盖相同 key 缓存的意思

Dreamlu

2016-07-20 10:17

这里面的对象不能简单的用json做序列化和反序列化。@loogn 这块是设计的时候始料未及的。这就有点尴尬了,这块你可以这么来弄,稍后贴代码

loogn

2016-07-20 10:28

@Dreamlu 更通用的做法可以是把缓存对象变成String类型,内部负责序列化和反序列化。
public String get(String s) ;
public void set(String s, String o);

Dreamlu

2016-07-20 10:31

@Override
public T get(String key) {
String json = "xxx";
//z这里的json从数据库获取
if (null == json) {
return null;
}
JSONObject oo = JSONObject.parseObject(json);
String xx = oo.getString("json");
if (key.indexOf(":") != -1) {
return (T) new JsTicket(xx);
} else {
return (T) new AccessToken(xx);
}
}

@Override
public void set(String key, Object object) {
String json = JSONObject.toJSONString(object);
// 设定到数据库
}

Dreamlu

2016-07-20 10:46

@loogn 恩恩,是的抛String出来这个想法不错。就怕影响老用户的数据。还得斟酌一下,先把它备注到JFinal-weixin的issues中