FastJson反序列化后,子类类型转换问题及解决办法
1. 问题描述
- 使用FastJson序列化的时候,如果用于序列化的对象中将子类用父类类型保存进去,在反序列化的之后,将对象中该子类对象取出,如果强转为子类类型,就会抛出类型转换异常。
- 在使用String类型报文或者json字符串传输的系统中,该问题会比较常见
2. 问题重现
-
问题代码
- 调用类
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);
}
}
- 相关类
/**
* 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);
}
}
-
报错信息
- 报错信息为类型转换异常,显然子类信息在经过FastJson的序列化和反序列化之后,并没有得到保留
java.lang.ClassCastException: com.forms.lego.sysm.bfs.Fruit cannot be cast to com.forms.lego.sysm.bfs.Apple
- 进一步查看源码可以发现,反序列过程中,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反序列化后内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复