通过配置 `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.As: JsonTypeInfo是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
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |