摘要:在该篇文章中,我们介绍了通过两种主要方式来自定义JSON的序列化:注解和编程方式。注解方式允许我们在类、字段或方法上使用特定的标记来指示JSON序列化的行为。然而,有时我们可能需要更细粒度的控制,这时就可以使用编程方式来实现。
1. 简介
在之前的一篇文章中详细的介绍了如何优雅的定制Json数据格式的响应,文章地址如下:
SpringBoot优雅地定制JSON响应数据
在该篇文章中,我们介绍了通过两种主要方式来自定义JSON的序列化:注解和编程方式。注解方式允许我们在类、字段或方法上使用特定的标记来指示JSON序列化的行为。然而,有时我们可能需要更细粒度的控制,这时就可以使用编程方式来实现。
本篇文章将重点介绍如何通过编程方式自定义JSON的序列化和反序列化。编程方式通常涉及到实现特定的接口或扩展框架提供的类,以便在序列化和反序列化过程中插入自定义的逻辑。
在Spring Boot中使用Jackson库时,我们可以创建自定义的序列化器和反序列化器来处理JSON的转换。自定义序列化器需要实现JsonSerializer、JsonObjectSerializer 接口,而自定义反序列化器则需要实现JsonDeserializer、JsonObjectDeserializer接口。这些接口提供了必要的方法来定义如何将Java对象转换为JSON字符串(序列化),以及如何将JSON字符串转换为Java对象(反序列化)。
2. 实战案例
在Spring Boot环境下你可以自定义 JsonSerializer、JsonDeserializer 或 KeyDeserializer 的实现类上直接使用 @JsonComponent 注解。也可以在包含序列化器/解序列化器作为内部类的类中使用。
2.1 自定义JsonSerializer/Deserializer
@JsonComponentpublic class PackJsonComponent { // 自定义序列化 public static class Serializer extends JsonSerializer { @Override public void serialize(User value, JsonGenerator jgen, SerializerProvider serializers) throws IOException { jgen.writeStartObject ; jgen.writeStringField("name", value.getName) ; jgen.writeNumberField("age", value.getAge) ; jgen.writeEndObject ; } } // 自定义反序列化 public static class Deserializer extends JsonDeserializer { @Override public User deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException { ObjectCodec codec = jsonParser.getCodec ; JsonNode tree = codec.readTree(jsonParser) ; String name = tree.get("name").textValue ; int age = tree.get("age").intValue ; // 为了区分这里故意做了+操作,以表示生效 Long id = tree.get("id").longValue + 1000L ; return new User(id, name, age) ; } }}上面自定义PackJsonComponent类中定义了序列化和反序列化组件,他们的父类都指定了泛型的类型,这里你也可以指定Object,在进行处理时再进行类型的判断。
测试接口
@RestController@RequestMapping("/jackson")public class JacksonController { @GetMapping("/user") public User queryUser { return new User(1L, "张三", 10) ; } @PostMapping("/save") public User queryUser(@RequestBody User user) { return user ; }}// User对象public class User { private Long id ; private String name ; private Integer age ; // getter, setter}测试/queryUser接口
测试/save接口
注意:在测试该/save接口时,你需要先将序列号的类注释了,不然你看不到效果。
ApplicationContext容器中的所有 @JsonComponent Bean 都会自动向 Jackson 注册。因为 @JsonComponent 是用 @Component 元标注的,所以通常的组件扫描规则也适用。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Componentpublic @interface JsonComponent { // ...}接下来介绍另外一种自定义的方式。
2.2 自定义JsonObjectSerializer/Deserializer
Spring Boot 还提供了 JsonObjectSerializer 和 JsonObjectDeserializer基类,在序列化对象时,它们为标准的 Jackson 版本提供了有用的替代方法。
@JsonComponentpublic class PackJsonComponent { public static class Serializer extends JsonObjectSerializer { @Override protected void serializeObject(User value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeNumberField("id", value.getId) ; jgen.writeStringField("name", value.getName) ; jgen.writeNumberField("age", value.getAge); // 添加新的属性 jgen.writeStringField("nation", "中国") ; // 自定义写入其它的对象 Map params = new HashMap ; params.put("q", "java") ; params.put("s", "pack") ; jgen.writeObjectField("params", params) ; } } public static class Deserializer extends JsonObjectDeserializer { @Override protected User deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec, JsonNode tree) throws IOException { long id = nullSafeValue(tree.get("id"), Long.class) + 1L ; String name = nullSafeValue(tree.get("name"), String.class); int age = nullSafeValue(tree.get("age"), Integer.class) ; return new User(id, name, age) ; } }}通过以上的方式都可以自定义JSON对象的序列化和反序列化。
// 不允许这样操作,这会报错;但你可以像上面那样输出其它的对象jgen.writeObject(value);上面不管你通过什么方式自定义JSON的序列化和反序列化,都将只针对你指定的泛型类型有效,其它对象类型不会生效。
来源:散文随风想一点号