fastjson泛型反序列化如何不写死?或者有什么替换思路?

Blogs
  • 425

测试代码,可直接复制运行

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class User<T>  {
        private Integer age;
        private T t;
    }
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Attribute {
        private String attrName;
        private Object attrValue;
    }
    public static void main(String[] args) {
        String json = "{\"age\":18,\"t\":{\"attrName\":\"define\",\"attrValue\":123}}";
//        User<Attribute> attributeUser = JSON.parseObject(json, new TypeReference<User<Attribute>>(){}); right: 但是写死了代码
        Deserialization<Attribute> attributeDeserialization = new Deserialization<>(json);
        // 测试序列化是否成功
        System.out.println(attributeDeserialization.getUser().getT().getAttrValue()); // X 通用,但是泛型不行
        // error:java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to com.printerx.SFTest$Attribute
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Deserialization<T> {
        private String json;
        public User<T> getUser() {
            return JSON.parseObject(json, new TypeReference<User<T>>(){});
        }
    }

详情,方便查看

image.png

运行报错信息

image.png

回复
阅读 1.7k
2 个回答
imango
  • 2.9k
✓ 已被采纳

我平常也用fastjson,也用过TypeReference参数,但也一般是集合那种带泛型,倒是题主的情况或者说想法之前没有想过。

确实某种意义来说这种情况的问题在于TypeReference写好泛型后是一种Java语法的规则,但是不可动态编程替换的,也就是写死了的感觉。

不过呢,我这次再看注意到JSON.parseObject的第二个参数,往往我们一般用XXX.class或者TypeReference

XXX.class时,参数的类型并不是Class,而是Type
image.png

这一下注意的点让我瞬间打通任督二脉,哈哈哈

既然是Type,那我们知道除了Class是一种Type,带泛型的也是一种Type,这种情况下不就是咱们的ParameterizedType

这就简单了,我们可以根据User<T>中需要的类型直接造一个ParameterizedType即可。我这里选用的是Java基础库自带的实现sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl

ParameterizedTypeImpl parameterizedType = ParameterizedTypeImpl.make(User.class, new Class[]{Attribute.class}, null);
User<Attribute> user = JSON.parseObject(json, parameterizedType);

当然这个自带的实现用起来是不太美观,你可以用咱们老朋友apache commons包下的 org.apache.commons.lang3.reflect.TypeUtils;

ParameterizedType type = TypeUtils.parameterize(User.class, Attribute.class);

感觉应该能解决你的问题叭ヾ( ̄▽ ̄)Bye~Bye~

public static class Deserialization<T extends Attribute> {
    private String json;
    public User<T> getUser() {
        return JSON.parseObject(json, new TypeReference<User<T>>(){});
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏