首页 > 其他分享 >序列化和反序列化的一致性

序列化和反序列化的一致性

时间:2024-11-16 23:43:10浏览次数:3  
标签:枚举 JSON objectMapper 一致性 序列化 public redisTemplate

序列化和反序列化需要确保算法一致

spring-data-redis-客户端,配置,序列化,Pipeline管道_spring data redis 配置-CSDN博客

     通过 RedisTemplate 读取 Key 为 stringRedisTemplate 的 Value,
     使用 StringRedisTemplate 读取 Key 为 redisTemplate 的 Value:
     结果是,两次都无法读取到 Value:

@SpringBootTest
public class SerialDemo {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ObjectMapper objectMapper;

    @PostConstruct
    public void init() throws JsonProcessingException {
        redisTemplate.opsForValue().set("redisTemplate", new UserBean("zhuye", "dd", 23));
        stringRedisTemplate.opsForValue().set("stringRedisTemplate",
                objectMapper.writeValueAsString(new UserBean("zhuye", "dd", 23)));
        Object stringRedisTemplate1 = redisTemplate.opsForValue().get("stringRedisTemplate");
        String redisTemplate1 = stringRedisTemplate.opsForValue().get("redisTemplate");
    }
}

  1. RedisTemplate 默认情况下 RedisTemplate 针对 Key 和 Value 使用JDK 序列化
  2. StringRedisTemplate 对于 Key 和 Value,使用的是 String 序列化方式,Key 和 Value 只能是 String:
/**
 *   启用 activateDefaultTyping 方法把类型信息作为属性写入序列化后的数据中
 *   <code>
 *  ObjectMapper objectMapper = new ObjectMapper();
 *  objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
 *  objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT);
 * Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer =
 *  *new Jackson2JsonRedisSerializer<>(objectMapper,Object .class);
 *   </code>
 *   直接 使用  RedisSerializer.json() 更简单
 */
@Configuration
public class RedisTemplateConfiguration {

    @Bean("redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 设置key和value的序列化规则
        redisTemplate.setValueSerializer(RedisSerializer.json());
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        redisTemplate.setHashValueSerializer(RedisSerializer.json());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

注意 Jackson JSON 反序列化对额外字段的处理

修改特性

不要自定义 ObjectMapper,而是直接在配置文件设置相关参数,来修改Spring 默认的 ObjectMapper 的功能。比如,直接在配置文件启用把枚举序列化为索引号

spring.jackson.serialization.write_enums_using_index=true

或者可以直接定义 Jackson2ObjectMapperBuilderCustomizer Bean 来启用新特性:

@Configuration
public class JacksonConfig {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> {
            // 启用序列化特性
            builder.featuresToEnable(
                SerializationFeature.INDENT_OUTPUT, // 使输出的 JSON 格式化
                SerializationFeature.WRITE_DATES_AS_TIMESTAMPS // 将日期对象序列化为时间戳
            );

            // 禁用序列化特性
            builder.featuresToDisable(
                SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS // 不将日期键序列化为时间戳
            );

            // 启用反序列化特性
            builder.featuresToEnable(
                DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, // 如果 JSON 数组只有一个值,则接受单个值
                DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE // 如果 JSON 中包含未知的枚举值,则使用默认值
            );

            // 禁用反序列化特性
            builder.featuresToDisable(
                DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES // 如果 JSON 中包含未知属性,则不反序列化失败
            );

            // 启用映射器特性
            builder.featuresToEnable(
                MapperFeature.AUTO_DETECT_GETTERS_SETTERS, // 自动检测 getter 和 setter 方法
                MapperFeature.AUTO_DETECT_FIELDS // 自动检测字段
            );

            // 禁用映射器特性
            builder.featuresToDisable(
                MapperFeature.SORT_PROPERTIES_ALPHABETICALLY // 不按字母顺序排序属性
            );
        };
    }
}

简单使用

Jackson 官方文档来了解这些特性,详见SerializationFeatureDeserializationFeature和 MapperFeature。

SerializationFeature 用于控制 JSON 序列化的行为。以下是一些常见的 SerializationFeature:

  1. INDENT_OUTPUT: 使输出的 JSON 格式化,便于阅读。
  2. WRITE_DATES_AS_TIMESTAMPS: 将日期对象序列化为时间戳。
  3. WRITE_DATE_KEYS_AS_TIMESTAMPS: 将日期键序列化为时间戳。
  4. WRITE_ENUMS_USING_TO_STRING: 使用枚举的 toString 方法而不是名称进行序列化。
  5. WRITE_EMPTY_JSON_ARRAYS_FOR_NULL_COLLECTIONS: 将空集合序列化为空数组而不是 null。

DeserializationFeature

DeserializationFeature 用于控制 JSON 反序列化的行为。以下是一些常见的 DeserializationFeature:

  1. FAIL_ON_UNKNOWN_PROPERTIES: 如果 JSON 中包含未知属性,则反序列化失败。
  2. ACCEPT_SINGLE_VALUE_AS_ARRAY: 如果 JSON 数组只有一个值,则接受单个值。
  3. READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE: 如果 JSON 中包含未知的枚举值,则使用默认值。

MapperFeature

MapperFeature 用于控制 ObjectMapper 的行为。以下是一些常见的 MapperFeature:

  1. AUTO_DETECT_GETTERS_SETTERS: 自动检测 getter 和 setter 方法。
  2. AUTO_DETECT_FIELDS: 自动检测字段。
  3. AUTO_DETECT_CREATORS: 自动检测构造函数。
  4. SORT_PROPERTIES_ALPHABETICALLY: 按字母顺序排序属性。
  5. USE_GETTERS_AS_SETTERS: 使用 getter 方法作为 setter 方法。

反序列化时要小心类的构造方法

        默认情况下,在反序列化的时候,Jackson 框架只会调用无参构造方法创建对象。如果走自定义的构造方法创建对象,需要通过 @JsonCreator 来指定构造方法,并通过@JsonProperty 设置构造方法中参数对应的 JSON 属性名:

@Data
public class APIResultRight {
...
 @JsonCreator
 	public APIResultRight(@JsonProperty("code") int code) {
 	this.code = code;
	if (code == 2000) success = true;
		 else success = false;
	 }
}

枚举作为 API 接口参数或返回值的两个大坑 

客户端和服务端的枚举定义不一致时,会出异常

要解决这个问题,可以开启 Jackson 的 read_unknown_enum_values_using_default_value 反序列化特性,也就是在枚举值未知的时候使用默认值:

并为枚举添加一个默认值,使用 @JsonEnumDefaultValue 注解注释:

@JsonEnumDefaultValue

UNKNOWN(-1, "未知");

RestTemplate 生效这个反序列化特性,还 需要配置 RestTemplate,来使用 Spring Boot 的 MappingJackson2HttpMessageConverter 才行:

@Bean
public RestTemplate restTemplate(MappingJackson2HttpMessageConverter mappingJac
 	return new RestTemplateBuilder()
 	.additionalMessageConverters(mappingJackson2HttpMessageConverter)
 	.build();
}

枚举序列化反序列化实现自定义的字段非常麻烦

标签:枚举,JSON,objectMapper,一致性,序列化,public,redisTemplate
From: https://blog.csdn.net/qq_26594041/article/details/143783329

相关文章

  • 序列化与反序列化-基本了解使用
    什么是序列化与反序列化        网络传输的数据必须是二进制数据,但调用方请求的出入参数都是对象。对象是不能直接在网络中传输的,所以我们需要提前把它转成可传输的二进制,并且要求转换算法是可逆的,这个过程我们一般叫做“序列化”。这时,服务提供方就可以正确地从二进......
  • Java序列化与反序列化深度解析
    一、引言在Java开发中,序列化与反序列化是非常重要的概念和技术手段。它允许我们将对象转换为字节流以便于存储或传输,然后在需要的时候再将字节流还原为对象。这一机制在很多场景中都有着广泛的应用,例如数据持久化、分布式系统中的远程方法调用(RMI)、缓存等。本文将深入探讨......
  • Java反序列化-Commons Collections3利用链分析详解
    介绍CC3与CC1和CC6的主要区别在于,CC1和CC6依赖反射机制来执行Runtime.getRuntime().exec()等危险命令,而如果服务器将这些方法列入黑名单,这两种方式就会失效。相比之下,CC3通过类加载器动态加载恶意类来执行危险函数,绕过黑名单限制,从而达到命令执行的目的。公众号:T......
  • 【Pikachu】PHP反序列化RCE实战
    痛是你活着的证明1.PHP反序列化概述在理解PHP中serialize()和unserialize()这两个函数的工作原理之前,我们需要先了解它们各自的功能及其潜在的安全隐患。接下来,我会对相关概念做更详细的扩展解释。1.序列化serialize()序列化(serialization)是指将一个对象或数据......
  • java 反序列化 cc7 复现
    复现环境:common-collections版本<=3.2.1,java版本随意.cc7就是cc6换了一个出口,整体的逻辑没有太大的变化.在Lazymap之前的还那样,我们从如何触发Lazymap的get方法开始看起.AbstractMap看他的equals方法publicbooleanequals(Objecto){if(o==this)ret......
  • 出现了智能涌现效应!Vidu 引领视觉模型迈入上下文时代,无问芯穹Infini-AI异构云平台助力
    昨日,在Vidu上线逾百日之际,生数科技宣布Vidu1.5新版本(www.vidu.studio)问世,该版本实现了世界领先水平的突破:理解多样化的输入,突破“一致性”难题。无问芯穹作为生数科技重要战略产品伙伴,以Infini-AI异构云平台的澎湃算力和训练产品,助力生数科技模型迭代,持续引领视觉模型“一致......
  • java 反序列化 cc5复现
    复现环境:common-collections版本<=3.2.1,java版本随意.cc5则是cc6的一个变形,换了一个出口.直接从有变化的位置开看.TiedMapEntrypublicclassTiedMapEntryimplementsMap.Entry,KeyValue,Serializable{privatestaticfinallongserialVersionUID=-84538693613......
  • java 反序列化 cc3 复现
    版本要求:jdk版本<=8u65,common-collections版本<=3.2.1在很多时候,Runtime会被黑名单禁用.在这些情况下,我们需要去构造自定义的类加载器来加载自定义的字节码.类加载机制双亲委派这里直接粘别人的了.实现一个自定义类加载器需要继承ClassLoader,同时覆盖findClass方法......
  • java 反序列化 cc4 复现
    复现环境:jdk<=8u65,commonsCollections=4.0CommonsCollections4.x版本移除了InvokerTransformer类不再继承Serializable,导致无法序列化.但是提供了TransformingComparator为CommonsCollections3.x所没有的,又带来了新的反序列化危险.cc4的执行命令部分依然沿用cc3的TemplatesI......
  • 自定义序列化
    #ifndefAI_PACS_JSONTOSTRUCT_H#defineAI_PACS_JSONTOSTRUCT_H#include<iostream>#include<string>#include<unordered_map>#include<variant>#include<vector>#include<nlohmann/json.hpp>#include<stdexcept>......