spring/jackson:实现对保存JSON字符串的字段自动序列化和反序列化

Posted 10km

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring/jackson:实现对保存JSON字符串的字段自动序列化和反序列化相关的知识,希望对你有一定的参考价值。

对于spring-web项目,在数据库设计时,当我们想增加一个字段时,并不希望修改表结构,希望设计一个专用的扩展字段,将增加的扩展字段以一个JSON字符串形式保存在这个专用字段中。
spring对JSON的序列化和反序列化是依赖jackson来完成的。
数据发送给前端的时候,我们希望jackson在序列化一个数据库记录对象时以JSON的形式返回这个JSON扩展字段的内容,而不是一个String,
同时前端也能以一个JSON的形式定义这个JSON扩展字段,服务端在收到请求jackson在反序列化时能自动将这个JSON字段反序列化为String.这样省去了手工写代码转换的过程才是最方便的。
举例说明一下吧,以下是一个数据库记录对象,props字段为一个JSON扩展字段可以存储任意字段数据

public static class JsonTestUser
		private Integer id;
		private String name;
		/** (JSON格式)扩展字段 */
		private String props;
		......//

我们希望它序列化时,将props字段以原始内容输出,也就是一个JSON对象,而不这种带转义符的字符串:\\"phone\\":\\"13088927898\\","email":\\"hello@qq.com\\"


  "id":0,
  "name":"tom",
  "props":
    "phone":"13088927898",
    "email":"hello@qq.com"
  

序列化

将上面的JsonTestUser#props以原始内容输出,并不复杂,利用jackson的注解@JsonRawValue注解就可以完美支持,
如下在props字段定义上增加@JsonRawValue注解,在序列化props字段时就会不加转义符直接原内容输出。

@JsonRawValue
private String props;

反序列化

如果希望将JSON对象反序列化保存到String字段,就需要自己实现一个JsonDeserializer
代码如下:

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
/**
 * Deserializing JSON property as String with Jackson<br>
 * 实现将有@link com.fasterxml.jackson.annotation.JsonRawValue注解的
 * 内容为JSON的String类型字段反序列化为String的反序列化器实现
 * copy from <a ref="https://cassiomolin.com/2017/01/24/deserializing-json-property-as-string-with-jackson/">《Deserializing JSON property as String with Jackson》</a>
 *
 */
public class RawJsonDeserializer extends JsonDeserializer<String> 

    @Override
    public String deserialize(JsonParser jp, DeserializationContext ctxt)
           throws IOException, JsonProcessingException 
        /*
         * [实现方案一][推荐]
         * 输入的JSON字符串解析为JSON对象(JsonNode),再输出为JSON字符串,
         * 相当于对JSON字符串进行了格式化
         */
        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        JsonNode node = mapper.readTree(jp);
        return mapper.writeValueAsString(node);
    	/**
    	 * [实现方案二]
    	 * 如果希望保存原始字符串内容,空格,tab,换行,则采用如下方式,不解析为JSON对象直接将原字符串返回
    	 */
        //long begin = jp.getCurrentLocation().getCharOffset();
        //jp.skipChildren();
        //long end = jp.getCurrentLocation().getCharOffset();

        //String json = jp.getCurrentLocation().getSourceRef().toString();
        //return json.substring((int) begin - 1, (int) end);
    

上面的反序列化器(JsonDeserializer)实现代码中提供了两种实现方案,
区别就是方案一对输入的JSON字段进行了解析,再输出为JSON字符串,输出的数据是格式化过的,原始内容中的空格,制表符(TAB),换行都会被清除掉。推荐使用此方案
方案二则相反,不会对输入JSON字段进行解析,直接输出原始的JSON字符串。

然后再使用@JsonDeserialize注解指定props字段使用我们定义的反序列化器.
如下,就可以完美实现JSON字段的自动序列化和反序列化

@JsonRawValue
@JsonDeserialize(using = RawJsonDeserializer.class)
private String props;

参考资料

《Deserializing JSON property as String with Jackson》

以上是关于spring/jackson:实现对保存JSON字符串的字段自动序列化和反序列化的主要内容,如果未能解决你的问题,请参考以下文章

spring.jackson.default-property-inclusion 被忽略

Spring boot + Jackson - 始终将日期转换为 UTC

SpringBoot全局Jackson配置未生效

如果 POJO 扩展了 Spring Jackson 中的抽象类,如何忽略它的大小写?

springboot 设置页面返回json的时间格式

Jackson 在我的 Spring Boot 应用程序中忽略了 spring.jackson.properties