文章目录
-
- [一、@JsonValue 详解](#一、@JsonValue 详解)
-
- [1. 核心作用](#1. 核心作用)
- [2. 关键特性](#2. 关键特性)
- [3. 典型使用场景](#3. 典型使用场景)
- [二、@JsonCreator 详解](#二、@JsonCreator 详解)
-
- [1. 核心作用](#1. 核心作用)
- [2. 关键特性](#2. 关键特性)
- [3. 典型使用场景](#3. 典型使用场景)
- [三、@JsonValue + @JsonCreator 完整示例(枚举)](#三、@JsonValue + @JsonCreator 完整示例(枚举))
- 四、关键对比与注意事项
- 总结
你想了解Jackson中的 @JsonValue和 @JsonCreator注解的核心用法,这两个注解是Jackson中用于 自定义对象序列化/反序列化规则 的关键注解,常用来解决枚举、自定义对象的JSON转换问题,以下从定义、用法、场景对比等方面详细讲解,结合示例让你快速掌握。
核心概念先厘清
在讲解注解前,先明确两个基础概念:
- 序列化(Serialization) :Java对象 → JSON字符串(如
User对象 →{"name":"张三"}); - 反序列化(Deserialization) :JSON字符串 → Java对象(如
{"name":"张三"}→User对象)。
@JsonValue负责序列化 ,@JsonCreator负责反序列化,两者常配合使用。
一、@JsonValue 详解
1. 核心作用
标记在方法/字段上,指定该对象序列化时只输出此方法的返回值/此字段的值(而非对象的所有属性),实现自定义序列化规则。
2. 关键特性
- 一个类中只能有一个
@JsonValue注解(多了会报错); - 标记在方法上时,方法不能有参数(getter方法风格);
- 优先级高于默认序列化规则(覆盖Jackson默认的字段序列化)。
3. 典型使用场景
场景1:枚举类的自定义序列化(最常用)
默认枚举序列化会输出枚举名(如MALE),通过@JsonValue可自定义输出值(如数字/中文):
java
import com.fasterxml.jackson.annotation.JsonValue;
public enum GenderEnum {
MALE(1, "男"),
FEMALE(2, "女");
private final int code;
private final String desc;
GenderEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
// 序列化时,只输出desc的值(如"男"/"女")
@JsonValue
public String getDesc() {
return desc;
}
// 若想序列化输出code,只需把@JsonValue移到这里
// @JsonValue
// public int getCode() {
// return code;
// }
// 常规getter
public int getCode() {
return code;
}
}
测试序列化:
java
import com.fasterxml.jackson.databind.ObjectMapper;
public class Test {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
// 序列化结果:"男"(而非"MALE")
String json = objectMapper.writeValueAsString(GenderEnum.MALE);
System.out.println(json);
}
}
场景2:自定义对象的简化序列化
将复杂对象序列化为单一值(如用户对象序列化为用户名):
java
import com.fasterxml.jackson.annotation.JsonValue;
public class User {
private Long id;
private String username;
private Integer age;
public User(Long id, String username, Integer age) {
this.id = id;
this.username = username;
this.age = age;
}
// 序列化时,只输出username(而非{"id":1,"username":"张三","age":20})
@JsonValue
public String getUsername() {
return username;
}
// 常规getter
public Long getId() {
return id;
}
public Integer getAge() {
return age;
}
}
测试序列化:
java
User user = new User(1L, "张三", 20);
// 序列化结果:"张三"(而非完整对象JSON)
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
二、@JsonCreator 详解
1. 核心作用
标记在构造方法/静态工厂方法上,指定反序列化时如何将JSON值转换为Java对象,解决自定义反序列化规则(尤其是枚举/不可变对象)。
2. 关键特性
- 用于反序列化,与
@JsonValue配合实现"自定义序列化→自定义反序列化"闭环; - 构造方法参数需用
@JsonProperty指定JSON字段名(JDK 8+若编译时保留参数名可省略,但建议显式指定); - 支持单一值反序列化(如JSON字符串→枚举)、多字段反序列化(如JSON对象→自定义对象)。
3. 典型使用场景
场景1:枚举类的自定义反序列化(配合@JsonValue)
承接上面的GenderEnum,实现从"男/女"反序列化为枚举:
java
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public enum GenderEnum {
MALE(1, "男"),
FEMALE(2, "女");
private final int code;
private final String desc;
GenderEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
// 序列化:输出desc
@JsonValue
public String getDesc() {
return desc;
}
// 反序列化:从desc值(如"男")转换为枚举
@JsonCreator
public static GenderEnum fromDesc(String desc) {
for (GenderEnum gender : GenderEnum.values()) {
if (gender.desc.equals(desc)) {
return gender;
}
}
throw new IllegalArgumentException("无效的性别描述:" + desc);
}
// 若需要从code反序列化,可新增方法:
// @JsonCreator
// public static GenderEnum fromCode(Integer code) {
// for (GenderEnum gender : GenderEnum.values()) {
// if (gender.code == code) {
// return gender;
// }
// }
// throw new IllegalArgumentException("无效的性别编码:" + code);
// }
public int getCode() {
return code;
}
}
测试反序列化:
java
// 从JSON字符串"男"反序列化为GenderEnum.MALE
GenderEnum gender = objectMapper.readValue("\"男\"", GenderEnum.class);
System.out.println(gender); // 输出:MALE
场景2:不可变对象的反序列化(构造方法标注)
不可变对象(字段为final)无法通过setter反序列化,需用@JsonCreator标记构造方法:
java
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
// 不可变用户对象(字段final,无setter)
public class ImmutableUser {
private final Long id;
private final String username;
private final Integer age;
// 反序列化时,通过此构造方法创建对象
@JsonCreator
public ImmutableUser(
@JsonProperty("id") Long id, // 指定JSON字段名
@JsonProperty("username") String username,
@JsonProperty("age") Integer age) {
this.id = id;
this.username = username;
this.age = age;
}
// 常规getter
public Long getId() {
return id;
}
public String getUsername() {
return username;
}
public Integer getAge() {
return age;
}
}
测试反序列化:
java
String json = "{\"id\":1,\"username\":\"张三\",\"age\":20}";
ImmutableUser user = objectMapper.readValue(json, ImmutableUser.class);
System.out.println(user.getUsername()); // 输出:张三
场景3:静态工厂方法实现反序列化(替代构造方法)
java
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Product {
private Long id;
private String name;
private Double price;
// 私有构造方法(禁止外部new)
private Product(Long id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
// 静态工厂方法作为反序列化入口
@JsonCreator
public static Product create(
@JsonProperty("id") Long id,
@JsonProperty("name") String name,
@JsonProperty("price") Double price) {
// 可在此处添加参数校验逻辑
if (price < 0) {
throw new IllegalArgumentException("价格不能为负数");
}
return new Product(id, name, price);
}
// getter省略
}
三、@JsonValue + @JsonCreator 完整示例(枚举)
实现枚举的"编码序列化/解码反序列化"闭环:
java
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public enum StatusEnum {
SUCCESS(200, "成功"),
FAIL(500, "失败");
private final int code;
private final String msg;
StatusEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
// 序列化:输出code(如200/500)
@JsonValue
public int getCode() {
return code;
}
// 反序列化:从code(如200)转换为枚举
@JsonCreator
public static StatusEnum fromCode(Integer code) {
for (StatusEnum status : StatusEnum.values()) {
if (status.code == code) {
return status;
}
}
throw new IllegalArgumentException("无效的状态码:" + code);
}
public String getMsg() {
return msg;
}
}
测试闭环:
java
// 序列化:StatusEnum.SUCCESS → 200
String json = objectMapper.writeValueAsString(StatusEnum.SUCCESS);
System.out.println(json); // 输出:200
// 反序列化:200 → StatusEnum.SUCCESS
StatusEnum status = objectMapper.readValue("200", StatusEnum.class);
System.out.println(status.getMsg()); // 输出:成功
四、关键对比与注意事项
| 注解 | 作用阶段 | 标记位置 | 核心场景 |
|---|---|---|---|
| @JsonValue | 序列化(→JSON) | 无参方法/字段 | 枚举自定义输出、对象简化序列化 |
| @JsonCreator | 反序列化(←JSON) | 构造方法/静态工厂方法 | 枚举自定义解析、不可变对象反序列化 |
注意事项
- @JsonCreator的参数标注 :
若构造方法/工厂方法的参数名与JSON字段名不一致,必须用@JsonProperty("字段名")指定,否则反序列化失败; - 枚举的反序列化容错 :
建议在@JsonCreator方法中处理非法值(如返回默认值/抛自定义异常),避免程序崩溃; - 优先级 :
@JsonValue/@JsonCreator的优先级高于Jackson的默认序列化/反序列化规则,也高于自定义Serializer/Deserializer(若同时配置); - 空值处理 :
反序列化时若JSON值为null,@JsonCreator方法需处理空值(如返回默认枚举),否则会抛空指针。
总结
- @JsonValue:控制Java对象序列化为JSON的格式,一个类仅能标注一个,常用于枚举自定义输出值;
- @JsonCreator :控制JSON反序列化为Java对象的逻辑,标记在构造方法/静态工厂方法上,需配合
@JsonProperty指定参数映射; - 核心配合场景:枚举类的自定义序列化(@JsonValue)+ 反序列化(@JsonCreator),实现JSON值与枚举的灵活转换;
- 扩展场景:不可变对象、复杂自定义对象的反序列化,替代传统的setter方式,更符合面向对象设计原则。
这两个注解是Jackson中处理自定义JSON转换的基础,尤其在枚举、不可变对象的场景中不可或缺,也是你在链路切换需求中处理参数/返回值JSON转换的常用工具。