redis序列化数据时,如何包含clsss类型信息?

简介: 通过配置 `com.fasterxml.jackson.databind.ObjectMapper` 的 `enableDefaultTyping` 方法,可以使序列化后的 JSON 包含类信息。

大家可能留意过,在redis里缓存的数据经常有下面两种形式。不难发现,这两者的区别就是后者包含了JavaObject类型信息。

  • {"levyName":"test","levyCode":1}
  • {"@class":"jstudy.jacksoncodec.JacksonObjectMapperTest$ChannelLevyDTO","levyName":"test","levyCode":1}



要让redis序列化时包含class类型,自然是对程序里定义的 com.fasterxml.jackson.databind.ObjectMapper实例进行设置。没错,我们使用它的 enableDefaultTyping(com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping, com.fasterxml.jackson.annotation.JsonTypeInfo.As) 方法。

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, 
      JsonTypeInfo.As.PROPERTY);

关于这个方法的第2个参数JsonTypeInfo.AsJsonTypeInfo是Jackson库里的一个注解,JsonTypeInfo.As枚举用于指定在 JSON 中包含类型信息的方式。 默认值是 JsonTypeInfo.As.PROPERTY

我们用上面代码中的 objectMapper 写个demo↓

ChannelLevyDTO channelLevyDTO = new ChannelLevyDTO1();
channelLevyDTO.levyCode=1;
channelLevyDTO.levyName="test";
String s = objectMapper.writeValueAsString(channelLevyDTO);

执行demo程序可以看到,s对应的json串是
{"@class":"jstudy.jacksoncodec.JacksonObjectMapperTest$ChannelLevyDTO","levyName":"test","levyCode":1}

JsonTypeInfo.As 枚举类型定义了以下几种类型信息包含方式:

  • WRAPPER_ARRAY:将类型信息包装在 JSON 数组中。
  • WRAPPER_OBJECT:将类型信息包装在 JSON 对象中。
  • PROPERTY:将类型信息作为属性添加到 JSON 中。
  • EXISTING_PROPERTY:将类型信息添加到现有的属性中。
  • EXTERNAL_PROPERTY:将类型信息作为外部属性引用。

上面demo使用的是As.PROPERTY。

使用As.WRAPPER_OBJECT则是:{"jstudy.jacksoncodec.JacksonObjectMapperTest$ChannelLevyDTO":{"levyName":"test","levyCode":1}}

使用As.WRAPPER_ARRAY 则是:["jstudy.jacksoncodec.JacksonObjectMapperTest$ChannelLevyDTO",{"levyName":"test","levyCode":1}]

补充一点,Jackson库ObjectMapper类弃用了enableDefaultTyping,取而代之的是 activateDefaultTyping 。

// /**/m3/com/fasterxml/jackson/core/jackson-databind/2.11.0/jackson-databind-2.11.0-sources.jar!/com/fasterxml/jackson/databind/ObjectMapper.java

/**
 * @deprecated Since 2.10 use {@link #activateDefaultTyping(PolymorphicTypeValidator,DefaultTyping,JsonTypeInfo.As)} instead
 */
@Deprecated
public ObjectMapper enableDefaultTyping(DefaultTyping applicability, JsonTypeInfo.As includeAs) {
   
    return activateDefaultTyping(getPolymorphicTypeValidator(), applicability, includeAs);
}

public ObjectMapper activateDefaultTyping(PolymorphicTypeValidator ptv,
        DefaultTyping applicability, JsonTypeInfo.As includeAs) {
   
    ...

    TypeResolverBuilder<?> typer = _constructDefaultTypeResolverBuilder(applicability, ptv);
    // we'll always use full class name, when using defaulting
    typer = typer.init(JsonTypeInfo.Id.CLASS, null);
    typer = typer.inclusion(includeAs);
    return setDefaultTyping(typer);
}

相比较可见,activateDefaultTyping 方法多了一个参数 PolymorphicTypeValidator,是用于验证多态类型信息的验证器。

activateDefaultTyping 这个方法允许我们指定如何处理多态类型信息以及如何在序列化和反序列化过程中包含类型信息。

需要说明的是,在未指定包括类型信息时,序列化后是仅包含数据的json串{"levyName":"test","levyCode":1},我们可以将一个JavaObjectA对象反序列化为JavaObjectB对象(前提是JavaObjectB包含JavaObjectA的所有field)。

而一旦在指定了包含类型信息后,将严格按照model类型进行反序列化。也就是说,这种情况下,把JavaObjectA反序列为JavaObjectB,程序会抛出异常:Could not resolve type id '%s' as a subtype of %s,其中第1个%s表示序列化对象JavaObjectA,第2个%s表示要反序列化的目标类型JavaObjectB↓

com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'jstudy.jacksoncodec.JacksonObjectMapperTest$ChannelLevyDTO' as a subtype of [simple type, class jstudy.jacksoncodec.JacksonObjectMapperTest$ChannelLevyDTO1]: Not a subtype

目录
相关文章
|
5天前
|
NoSQL Redis
Redis的数据淘汰策略有哪些 ?
Redis 提供了 8 种数据淘汰策略,分为淘汰易失数据和淘汰全库数据两大类。易失数据淘汰策略包括:volatile-lru、volatile-lfu、volatile-ttl 和 volatile-random;全库数据淘汰策略包括:allkeys-lru、allkeys-lfu 和 allkeys-random。此外,还有 no-eviction 策略,禁止驱逐数据,当内存不足时新写入操作会报错。
34 16
|
25天前
|
监控 NoSQL Java
场景题:百万数据插入Redis有哪些实现方案?
场景题:百万数据插入Redis有哪些实现方案?
35 1
场景题:百万数据插入Redis有哪些实现方案?
|
5天前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
33 14
|
5天前
|
存储 NoSQL 算法
Redis分片集群中数据是怎么存储和读取的 ?
Redis集群采用哈希槽分区算法,共有16384个哈希槽,每个槽分配到不同的Redis节点上。数据操作时,通过CRC16算法对key计算并取模,确定其所属的槽和对应的节点,从而实现高效的数据存取。
28 13
|
5天前
|
存储 NoSQL Redis
Redis的数据过期策略有哪些 ?
Redis 采用两种过期键删除策略:惰性删除和定期删除。惰性删除在读取键时检查是否过期并删除,对 CPU 友好但可能积压大量过期键。定期删除则定时抽样检查并删除过期键,对内存更友好。默认每秒扫描 10 次,每次检查 20 个键,若超过 25% 过期则继续检查,单次最大执行时间 25ms。两者结合使用以平衡性能和资源占用。
28 11
|
5天前
|
监控 NoSQL 测试技术
【赵渝强老师】Redis的AOF数据持久化
Redis 是内存数据库,提供数据持久化功能,支持 RDB 和 AOF 两种方式。AOF 以日志形式记录每个写操作,支持定期重写以压缩文件。默认情况下,AOF 功能关闭,需在 `redis.conf` 中启用。通过 `info` 命令可监控 AOF 状态。AOF 重写功能可有效控制文件大小,避免性能下降。
|
5天前
|
存储 监控 NoSQL
【赵渝强老师】Redis的RDB数据持久化
Redis 是内存数据库,提供数据持久化功能以防止服务器进程退出导致数据丢失。Redis 支持 RDB 和 AOF 两种持久化方式,其中 RDB 是默认的持久化方式。RDB 通过在指定时间间隔内将内存中的数据快照写入磁盘,确保数据的安全性和恢复能力。RDB 持久化机制包括创建子进程、将数据写入临时文件并替换旧文件等步骤。优点包括适合大规模数据恢复和低数据完整性要求的场景,但也有数据完整性和一致性较低及备份时占用内存的缺点。
|
8天前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
16天前
|
存储 消息中间件 NoSQL
Redis数据结构:List类型全面解析
Redis数据结构——List类型全面解析:存储多个有序的字符串,列表中每个字符串成为元素 Eelement,最多可以存储 2^32-1 个元素。可对列表两端插入(push)和弹出(pop)、获取指定范围的元素列表等,常见命令。 底层数据结构:3.2版本之前,底层采用**压缩链表ZipList**和**双向链表LinkedList**;3.2版本之后,底层数据结构为**快速链表QuickList** 列表是一种比较灵活的数据结构,可以充当栈、队列、阻塞队列,在实际开发中有很多应用场景。
|
27天前
|
存储 NoSQL Redis
redis-set类型
【10月更文挑战第6天】
36 1