详细分析Java中的@JsonSerialize注解

前言

对应序列化的相关知识可看我之前的文章:详解Java中的serialVersionUID概念以及作用(附上Demo)

在这里插入图片描述

通过理解核心知识,再去品味总结的基本知识,可能理解更加透彻

对于序列化的场景,也可用于序列化JSON数据给前端的时候,某些值如果为空的时候,需要返回给前端的状态信息,对应需要使用到@JsonSerialize

1. 核心知识

@JsonSerialize 是 Jackson 库中的一个注解,用于指定在将 Java 对象序列化为 JSON 格式时,如何进行自定义的序列化处理。

通过这个注解,指定一个自定义的序列化器(serializer),以控制对象的序列化过程。

通过代码看总结:

import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;

// 继承 JsonSerializer<T> 实现自定义序列化逻辑
public class CustomSerializer extends JsonSerializer<MyObject> {

    @Override
    public void serialize(MyObject value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 在这里定义自己的序列化逻辑
        gen.writeString(value.toString());
    }
}

在Jackson库中,为了实现自定义的序列化逻辑,通常会创建一个类,该类继承自 JsonSerializer<T> 接口或其子类。JsonSerializer<T> 是一个泛型接口,其中的 <T> 表示要序列化的对象的类型。

继承 JsonSerializer<T> 接口的主要目的是为了实现 serialize 方法,该方法定义了如何将指定类型的对象序列化为 JSON 格式。

通过继承该接口,提供自定义的序列化逻辑,从而满足特定对象的序列化需求。

具体来说,继承 JsonSerializer<T> 需要实现以下方法:

serialize(T value, JsonGenerator gen, SerializerProvider serializers):

该方法定义了如何将对象 value 序列化为 JSON 格式,并使用 JsonGenerator 对象进行输出。

2. 基本知识

常使用的using以及nullsUsing

  • JsonSerialize 注解: 用于指定自定义序列化器的注解。
  • JsonSerializer 接口: 自定义序列化器需要实现这个接口,然后通过 @JsonSerialize 注解的 using 属性指定使用哪个序列化器。

该注解可以应用在类中,也可应用在属性中,对类的不同属性使用不同的序列化逻辑,从而更加灵活地控制 JSON 序列化的过程。

除了using的注解也还有nullsUsing 等注解,@JsonSerialize(nullsUsing = xx.class) 的含义是,当某个属性的值为 null 时,使用指定的自定义序列化器 xx.class 来处理该属性的序列化。

  • nullsUsing: 该属性用于指定在属性值为 null 时使用的序列化器。

  • xx.class: 自定义的序列化器类,它实现了 Jackson 的 JsonSerializer 接口,定义了处理 null 值的序列化逻辑。

示例代码如下:

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;

// 自定义处理 null 值的序列化器
class NullSerializer extends JsonSerializer<Object> {

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 在这里定义处理 null 值的序列化逻辑
        gen.writeString("CustomNullValue");
    }
}

// 包含使用 @JsonSerialize 注解的类
class MyClass {
    // 当属性值为 null 时,使用 NullSerializer 处理序列化
    @JsonSerialize(nullsUsing = NullSerializer.class)
    private String nullableField;

    // 其他属性和方法...
}

在上述例子中,nullableField 属性上使用了 @JsonSerialize(nullsUsing = NullSerializer.class) 注解。当 nullableField 的值为 null 时,将使用 NullSerializer 类中定义的逻辑来处理该属性的序列化。

在这个例子中,处理 null 值的逻辑是将其序列化为字符串 "CustomNullValue"


总的来说,其作用如下:

  1. 定制化需求: 继承可以提供更大的灵活性,允许开发者完全控制序列化过程。
  2. 特定类型处理: 可以为不同类型的对象创建不同的序列化逻辑,以满足特定的业务需求。
  3. 重用性: 可以将自定义序列化器用于多个类,提高代码的重用性。

总的来说,通过继承 JsonSerializer<T> 接口,开发者可以更加精细地控制对象的序列化过程,以适应各种复杂的场景和需求。

3. Demo

假设有一个包含日期信息的类 CustomDate,并且将其序列化为 JSON 格式时,按照特定的格式输出日期。

通过继承 JsonSerializer<T> 来实现自定义的日期序列化逻辑。

注意看两个Demo的区分,分别应用在类或者属性上,以及使用using或者nullsUsing的区别!

3.1 jsontest1

注解应用在类上,且属性都会被序列化为某个特性:

对于序列化的方式如下:

package com.example.demo;

import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

// 自定义序列化器
class CustomDateSerializer extends JsonSerializer<CustomDate> {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // 在这里定义自己的序列化逻辑
    @Override
    public void serialize(CustomDate customDate, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        Date date = customDate.getDate();
        String formattedDate = dateFormat.format(date);
        gen.writeString(formattedDate);
    }
}



// 被序列化的对象
@JsonSerialize(using = CustomDateSerializer.class)
class CustomDate {

    private Date date;

    public  CustomDate(){}

    public CustomDate(Date date) {
        this.date = date;
    }

    public Date getDate() {
        return date;
    }
}

public class jsontest1 {
    public static void main(String[] args) throws IOException {
        // 创建一个 实例
        CustomDate customDate = new CustomDate(new Date());

        // 使用 Jackson 库将 MyObject 序列化为 JSON 字符串
        String json = new ObjectMapper().writeValueAsString(customDate);

        // 输出结果
        System.out.println(json);


    }
}

截图如下:

在这里插入图片描述

3.2 jsontest2

对应序列化的类如下:(序列化的值为空!)

class CustomDateSerializer extends JsonSerializer<CustomDate> {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // 在这里定义自己的序列化逻辑
    @Override
    public void serialize(CustomDate customDate, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString("");
    }
}

其运行的主函数如下:(注意传输的值为空!)

public class jsontest2 {
    public static void main(String[] args) throws IOException {
        // 创建一个 实例
        CustomDate customDate = new CustomDate();

        // 使用 Jackson 库将 MyObject 序列化为 JSON 字符串
        String json = new ObjectMapper().writeValueAsString(customDate);

        // 输出结果
        System.out.println(json);


    }
}

如果代码为如下:

class CustomDate {
    @JsonSerialize(using = CustomDateSerializer.class)
    private Date date;

    public  CustomDate(){}

    public CustomDate(Date date) {
        this.date = date;
    }

    public Date getDate() {
        return date;
    }
}

输出结果为:(这说明序列化失败),但注意如果这样放在类上,是可以成功的!

在这里插入图片描述

为了在属性上可以序列化,应该使用如下方式:

class CustomDate {
    @JsonSerialize(nullsUsing = CustomDateSerializer.class)
    private Date date;

    public  CustomDate(){}

    public CustomDate(Date date) {
        this.date = date;
    }

    public Date getDate() {
        return date;
    }
}

截图如下所示:

在这里插入图片描述

对应的将该注解放在类上,序列化可以成功!

4. 总结

  • using作用类,生效!
  • using在作用属性时,如果非空属性值的序列化转换,值为null,序列化不生效。需要使用nullsUsing来实现
  • 29
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,针对您的问题,我可以给出以下实现步骤: 1. 定义注解类,用于标记需要序列化和反序列化的字段。 2. 定义序列化器和反序列化器,使用反射获取被注解标记的字段,并将其转换为字符串或从字符串转换回来。 3. 在需要进行序列化和反序列化的类使用注解标记需要进行操作的字段。 以下是一个简单的示例代码: ```java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @interface Serialize { } class Serializer { public static String serialize(Object obj) throws IllegalAccessException { StringBuilder sb = new StringBuilder(); for (Field field : obj.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(Serialize.class)) { field.setAccessible(true); sb.append(field.getName()).append("=").append(field.get(obj)).append(";"); } } return sb.toString(); } } class Deserializer { public static void deserialize(Object obj, String str) throws NoSuchFieldException, IllegalAccessException { for (String fieldString : str.split(";")) { String[] parts = fieldString.split("="); Field field = obj.getClass().getDeclaredField(parts[0]); if (field.isAnnotationPresent(Serialize.class)) { field.setAccessible(true); if (field.getType() == int.class) { field.setInt(obj, Integer.parseInt(parts[1])); } else if (field.getType() == String.class) { field.set(obj, parts[1]); } } } } } class Person { @Serialize private String name; @Serialize private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String toString() { return "Person{name='" + name + "', age=" + age + "}"; } } public class Main { public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException { Person person = new Person("Alice", 30); String serialized = Serializer.serialize(person); System.out.println(serialized); Person deserialized = new Person("", 0); Deserializer.deserialize(deserialized, serialized); System.out.println(deserialized); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农研究僧

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值