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

目录
相关文章
|
2天前
|
XML 存储 JSON
Twaver-HTML5基础学习(19)数据容器(2)_数据序列化_XML、Json
本文介绍了Twaver HTML5中的数据序列化,包括XML和JSON格式的序列化与反序列化方法。文章通过示例代码展示了如何将DataBox中的数据序列化为XML和JSON字符串,以及如何从这些字符串中反序列化数据,重建DataBox中的对象。此外,还提到了用户自定义属性的序列化注册方法。
15 1
|
1月前
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
|
7天前
|
NoSQL Java API
Redis数据淘汰策略的详细介绍
通过上述步骤,我们不仅解决了一个实际问题,也进一步了解了Java 8时间API的强大功能和灵活性。希望这个解答能够帮助你在日常开发中更加自如地处理时间和时区相关的问题。
17 0
|
1月前
|
NoSQL Redis 数据库
Redis AOF重写问题之同一数据产生两次磁盘IO如何解决
Redis AOF重写问题之同一数据产生两次磁盘IO如何解决
Redis AOF重写问题之同一数据产生两次磁盘IO如何解决
|
1月前
|
缓存 NoSQL 算法
【Azure Redis 缓存】Redis导出数据文件变小 / 在新的Redis复原后数据大小压缩近一倍问题分析
【Azure Redis 缓存】Redis导出数据文件变小 / 在新的Redis复原后数据大小压缩近一倍问题分析
|
1月前
|
NoSQL 调度 Redis
Redis AOF重写问题之aof_rewrite_buf遗留数据如何解决
Redis AOF重写问题之aof_rewrite_buf遗留数据如何解决
|
1月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
1月前
|
存储 开发框架 .NET
解锁SqlSugar新境界:利用Serialize.Linq实现Lambda表达式灵活序列化与反序列化,赋能动态数据查询新高度!
【8月更文挑战第3天】随着软件开发复杂度提升,数据查询的灵活性变得至关重要。SqlSugar作为一款轻量级、高性能的.NET ORM框架,简化了数据库操作。但在需要跨服务共享查询逻辑时,直接传递Lambda表达式不可行。这时,Serialize.Linq库大显身手,能将Linq表达式序列化为字符串,实现在不同服务间传输查询逻辑。结合使用SqlSugar和Serialize.Linq,不仅能够保持代码清晰,还能实现复杂的动态查询逻辑,极大地增强了应用程序的灵活性和可扩展性。
89 2
|
6天前
|
JSON fastjson Java
niubility!即使JavaBean没有默认无参构造器,fastjson也可以反序列化。- - - - 阿里Fastjson反序列化源码分析
本文详细分析了 Fastjson 反序列化对象的源码(版本 fastjson-1.2.60),揭示了即使 JavaBean 沲有默认无参构造器,Fastjson 仍能正常反序列化的技术内幕。文章通过案例展示了 Fastjson 在不同构造器情况下的行为,并深入探讨了 `ParserConfig#getDeserializer` 方法的核心逻辑。此外,还介绍了 ASM 字节码技术的应用及其在反序列化过程中的角色。
31 10
|
6天前
|
存储 Java 开发者
Java编程中的对象序列化与反序列化
【9月更文挑战第20天】在本文中,我们将探索Java编程中的一个核心概念——对象序列化与反序列化。通过简单易懂的语言和直观的代码示例,你将学会如何将对象状态保存为字节流,以及如何从字节流恢复对象状态。这不仅有助于理解Java中的I/O机制,还能提升你的数据持久化能力。准备好让你的Java技能更上一层楼了吗?让我们开始吧!