序列化与反序列化
- 含义
- 序列化:指把Java对象转换为字节序列的过程
- 反序列化:指把字节序列恢复为Java对象的过程。
- 作用
- 序列化作用:在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。
- 反序列化作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
总结:核心作用就是对象状态的保存和重建。(整个过程核心点就是字节流中所保存的对象状态及描述信息)。可见,有序列化,就有反序列化,两者是相辅相成,缺一不可。要想写,就得序列化,要想读,就得反序列化。
那么接下来,我遇到的问题就是对序列化与反序列化造成的问题。
- 场景介绍
在SpringBoot使用Redis做自动化缓存,而且结果存储的形式是JSON格式。由于业务需要,前端需要将BigDecimal的类型的属性结果值需要精确到小数点后两位,经过查找,找到如下解决方案:
如下图代码所示,即可在json序列化时,将BigDecimal类型的结果值精确到小数点后两位。由于这涉及到了自定义jackson序列化的类。@JsonSerialize(using = DataSerializerUtils.class) private BigDecimal payMoney; // 序列化类: public class DataSerializerUtils extends JsonSerializer<BigDecimal> { @Override public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider provider) throws IOException { if (value != null) { gen.writeString(value.setScale(2, BigDecimal.ROUND_HALF_DOWN) + ""); } else { gen.writeString(""); } } }
但是,在使用Redis做自动化缓存时候,结果存储形式为JSON格式时候,却频频出错。博主也是经历过千辛万苦,才得以解决。当Jackson序列化时候,会报如下错误:Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Type id handling not implemented for type java.math.BigDecimal (by serializer of type org.springblade.common.json.DataSerializerUtils) (through reference chain: org.springblade.modules.bill.vo.BillVO["incomeMoney"])。
如上所示,可以看出是jackson序列化的时候,DataSerializerUtils没有找到type id。经过从查看JsonSerializer源码,发现有两个方法,如下所示:
public void serializeWithType(T value, JsonGenerator gen, SerializerProvider serializers,
TypeSerializer typeSer);
public Class<T> handledType() { return null; }
第一个方法会根据字段的类型来序列化,第二个方法来决定序列化类型的类。这两个方法是重中之重。解决方法如下:
@Override
public void serializeWithType(BigDecimal value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
serialize(value, gen, serializers);
}
@Override
public Class<BigDecimal> handledType() {
return BigDecimal.class;
}
在serializeWithType这个方法调用serialize即可。好了,到了这一步序列化的坑是走完了。
接下来说说反序列化的坑。有序列化当然也就有反序列化,如果没有这个概念,报错你也不会往上面想的。没有反序列化,那么Spring使用自动化注解从Redis读取就会报错,如下所示:
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (VALUE_STRING), expected START_ARRAY:need JSON Array to contain As.WRAPPER_ARRAY type information for class java.math.BigDecimal。
这个就是jackson不知道去如何从Redis反序列化数据,其实反序列化的过程就是读取数据。解决方案如下:
@JsonSerialize(using = DataSerializerUtils.class)
@JsonDeserialize(using = DataDeserializerUtils.class)
private BigDecimal incomeMoney;
public class DataDeserializerUtils extends JsonDeserializer<BigDecimal>{
@Override
public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException{
String value = p.getValueAsString();
return new BigDecimal(value);
}
@Override
public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException{
return deserialize(p, ctxt);
}
@Override
public Class<?> handledType() {
return BigDecimal.class;
}
}
这样,就能够反序列化。以上就是我使用SpringBoot整合Redis解决序列化与反序列化的坑的历程。