SpringBoot序列化与反序列化引起的车祸

本文介绍了SpringBoot在使用Redis作为缓存时遇到的序列化和反序列化问题,特别是针对BigDecimal类型的数据。在序列化时,通过自定义Jackson序列化类解决了精度问题,但遇到了DataSerializerUtils找不到type id的错误,通过调整serializeWithType方法解决了问题。在反序列化过程中,由于缺少相应处理导致Spring自动化注解从Redis读取数据报错,通过添加反序列化配置成功解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

序列化与反序列化

  1. 含义
    • 序列化:指把Java对象转换为字节序列的过程
    • 反序列化:指把字节序列恢复为Java对象的过程。
  2. 作用
    • 序列化作用:在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。
    • 反序列化作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
      总结:核心作用就是对象状态的保存和重建。(整个过程核心点就是字节流中所保存的对象状态及描述信息)。可见,有序列化,就有反序列化,两者是相辅相成,缺一不可。要想写,就得序列化,要想读,就得反序列化。
      那么接下来,我遇到的问题就是对序列化与反序列化造成的问题。
  3. 场景介绍
    在SpringBoot使用Redis做自动化缓存,而且结果存储的形式是JSON格式。由于业务需要,前端需要将BigDecimal的类型的属性结果值需要精确到小数点后两位,经过查找,找到如下解决方案:
    		@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("");
    				}
    			}
    		}
    
    如下图代码所示,即可在json序列化时,将BigDecimal类型的结果值精确到小数点后两位。由于这涉及到了自定义jackson序列化的类。
    但是,在使用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解决序列化与反序列化的坑的历程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值