我是靠谱客的博主 多情水池,这篇文章主要介绍FastJson反序列化后,子类类型转换问题及解决办法,现在分享给大家,希望可以做个参考。

FastJson反序列化后,子类类型转换问题及解决办法

1. 问题描述

  • 使用FastJson序列化的时候,如果用于序列化的对象中将子类用父类类型保存进去,在反序列化的之后,将对象中该子类对象取出,如果强转为子类类型,就会抛出类型转换异常
  • 在使用String类型报文或者json字符串传输的系统中,该问题会比较常见

2. 问题重现

  • 问题代码
  1. 调用类
public class FastJsonIssue {
    public static void main(String[] args) {
        new FastJsonIssue().test();
    }

    public void test() {
        List<Fruit> fruits = new ArrayList<>();
        // 可以看到Apple类作为Fruit的子类,将其放入List<Fruit>中
        fruits.add(new Apple(10));
        // 将List<Fruit>放入BuyFruits类中
        BuyFruits buyFruits = new BuyFruits(new BigDecimal(10), fruits);
        // 将BuyFruits类对象序列化为json字符串的过程
        String json = JSON.toJSONString(buyFruits);
        // 模拟收到报文并将其反序列化为buyFruitsResult对象
        BuyFruits buyFruitsResult = JSON.parseObject(json, BuyFruits.class);
        // 从BuyFruits中取出List<Fruit>
        List<Fruit> fruits1 = buyFruitsResult.getFruits();
        // 将之前存入集合的Apple类对象取出,并强转成Apple类型,报类型转换错误
        Apple apple = (Apple) fruits1.get(0);
    }

}
  1. 相关类
/**
 * BuyFruits类,里面存有父类Fruit类的List
 * @author August_Z
 */
public class BuyFruits implements Serializable {
    private BigDecimal price;
    private List<Fruit> fruits;

    public BuyFruits(BigDecimal price, List<Fruit> fruits) {
        this.price = price;
        this.fruits = fruits;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public List<Fruit> getFruits() {
        return fruits;
    }

    public void setFruits(List<Fruit> fruits) {
        this.fruits = fruits;
    }

}

/**
 * 水果类,是各种具体水果类的父类
 * @author August_Z
 */
public class Fruit implements Serializable {
    private int amount;

    public Fruit(int amount) {
        this.amount = amount;
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }
}

/**
 * 苹果类,是水果类的子类
 * @author August_Z
 */
public class Apple extends Fruit implements Serializable {

    public Apple(int amount) {
        super(amount);
    }

}
  • 报错信息
  1. 报错信息为类型转换异常,显然子类信息在经过FastJson的序列化和反序列化之后,并没有得到保留
java.lang.ClassCastException: com.forms.lego.sysm.bfs.Fruit cannot be cast to com.forms.lego.sysm.bfs.Apple
  1. 进一步查看源码可以发现,反序列过程中,FastJson只能通过BuyFruits.class获取到相应Fruit类信息,并进行相应的反序列化,并不能获取到存入的子类信息,以至于反序列化之后的只有Fruit对象,强转之后抛出类型转换异常

3. 解决方案

  • 方案描述

    实际生产中可以将该对象通过IO流转化为byte[]再通过FastJson转换为json字符串,在使用时先将json字符串转换为byte[],再通过IO流转化为JavaBean对象, 可以发现子类信息依然保留,不会出现类型转换异常信息。

  • 代码实施
public class FastJsonIssue {
    public static void main(String[] args) {
        new FastJsonIssue().test();
    }

    public void test() {
        List<Fruit> fruits = new ArrayList<>();
        // 可以看到Apple类作为Fruit的子类,将其放入List<Fruit>中
        fruits.add(new Apple(10));
        // 将List<Fruit>放入BuyFruits类中
        BuyFruits buyFruits = new BuyFruits(new BigDecimal(10), fruits);
        // 通过工具类将BuyFruits类对象转换为byte[]
        byte[] bytes = ObjectAndByteUtils.toByteArray(buyFruits);
        // 用FastJson将byte[]序列化为json字符串
        String json = JSON.toJSONString(bytes);
        // 模拟收到报文并将其反序列化成byte[]
        byte[] bytesResult = JSON.parseObject(json,byte[].class);
        // 使用用具类将byte[]转换为Object再强转为BuyFruits类对象
        BuyFruits buyFruitsResult = (BuyFruits)ObjectAndByteUtils.toObject(bytesResult);
        // 从BuyFruits中取出List<Fruit>
        List<Fruit> fruits1 = buyFruitsResult.getFruits();
        // 可以看到通过io转换之后再使用FastJson序列化不会有异常抛出
        Apple apple = (Apple) fruits1.get(0);
    }
}

/**
 * Object和byte[]互相转换类
 *
 * @author August_Z
 * @date 2020/7/20 19:32
 */
public class ObjectAndByteUtils {
    /**
     * 对象转数组
     *
     * @param obj 传入对象
     * @return byte[]数组
     */
    public static byte[] toByteArray(Object obj) {
        byte[] bytes = null;
        ByteArrayOutputStream bos =null;
        ObjectOutputStream oos=null;
        try {
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray();
        } catch (IOException ex) {
            ex.printStackTrace();
        }finally {
            try {
                if (oos != null) {
                    oos.close();
                }
                if (bos != null) {
                    bos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }

    /**
     * 数组转对象
     *
     * @param bytes byte数组
     * @return 响应对象
     */
    public static Object toObject(byte[] bytes) {
        Object obj = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            bis = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bis);
            obj = ois.readObject();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (ois != null) {
                    ois.close();
                }
                if (bis != null) {
                    bis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return obj;
    }
}

最后

以上就是多情水池最近收集整理的关于FastJson反序列化后,子类类型转换问题及解决办法的全部内容,更多相关FastJson反序列化后内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部