50% 的 Java 程序员都不知道的 Jackson 高级用法!
Jackson 是目前 Java 生态中使用最广泛的 JSON 序列化/反序列化库,但绝大多数人只用到了它的最基础功能(@JsonProperty、ObjectMapper.readValue 等),其实它还有非常多强大且实用的高级特性,能大幅提升代码质量、性能和可维护性。
下面列出 10 个非常实用但使用率明显偏低的 Jackson 高级用法(2025–2026 视角),很多都是中高级开发者和架构师才会主动用到的。
1. @JsonAnyGetter + @JsonAnySetter(动态字段)
当 JSON 中有大量不确定字段,或者你想把 Map 字段“打平”到对象里时非常有用。
public class DynamicUser {
private String name;
private Map<String, Object> extra = new LinkedHashMap<>();
@JsonAnyGetter
public Map<String, Object> getExtra() {
return extra;
}
@JsonAnySetter
public void setExtra(String key, Object value) {
extra.put(key, value);
}
}
效果:
输入 JSON:{"name":"张三", "age":18, "city":"北京"}
对象中 extra 会自动包含 age 和 city,而不需要提前定义所有字段。
2. @JsonUnwrapped(打平嵌套对象)
public class Address {
private String city;
private String street;
}
public class Person {
private String name;
@JsonUnwrapped
private Address address;
}
序列化后:
{
"name": "李四",
"city": "上海",
"street": "南京路"
}
非常适合把嵌套对象“展平”到顶层,常见于 DTO 与数据库实体转换。
3. @JsonInclude + @JsonInclude.Include.NON_EMPTY / NON_DEFAULT
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class UserDTO {
private String name;
private String email; // null 不输出
private Integer age = 0; // 0 不输出(NON_EMPTY 对数字无效)
private List<String> roles = Collections.emptyList(); // 空集合不输出
}
常用变体:
NON_NULL:null 不输出(最常见)NON_EMPTY:空集合、空字符串、空 Map 不输出NON_DEFAULT:默认值不输出(boolean false、int 0 等)
4. @JsonProperty.Access(读写控制)
public class User {
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long id; // 只读,序列化有,反序列化忽略
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password; // 只写,反序列化有,序列化忽略
@JsonProperty(access = JsonProperty.Access.AUTO) // 默认
private String username;
}
常用于:隐藏敏感字段、保护 id 不被前端修改等。
5. @JsonNaming(统一命名策略)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class UserInfo {
private String firstName;
private String lastLoginTime;
}
输出:
{
"first_name": "张",
"last_login_time": "2025-12-01"
}
支持的策略:
SnakeCaseStrategy(snake_case)KebabCaseStrategy(kebab-case)UpperCamelCaseStrategy(UpperCamelCase)LowerCaseStrategy(全小写)
6. @JsonView(视图控制,按需返回字段)
public class Views {
public static class Public {}
public static class Internal extends Public {}
}
public class User {
@JsonView(Views.Public.class)
private String username;
@JsonView(Views.Internal.class)
private String password;
@JsonView(Views.Internal.class)
private String phone;
}
使用:
ObjectMapper mapper = new ObjectMapper();
mapper.writerWithView(Views.Public.class).writeValueAsString(user);
// 只输出 username
非常适合不同接口返回不同字段集的场景(用户列表 vs 用户详情)。
7. @JsonFormat(自定义日期格式)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createTime;
支持的类型:Date、LocalDate、LocalDateTime、Instant、ZonedDateTime 等。
8. @JsonRootName(根节点名称)
@JsonRootName("response")
public class ApiResult<T> {
private int code;
private String msg;
private T data;
}
序列化后:
{
"response": {
"code": 200,
"msg": "success",
"data": {...}
}
}
常用于统一响应结构。
9. Mix-in Annotations(不侵入实体类)
当你不能修改第三方类或想把注解放在 DTO 而不是实体时使用:
// Mix-in 类
public abstract class UserMixIn {
@JsonIgnore
public abstract String getPassword();
}
// 配置
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(User.class, UserMixIn.class);
效果:User 类本身不加任何注解,但序列化时 password 被忽略。
10. 自定义 Deserializer / Serializer(终极武器)
public class MoneyDeserializer extends JsonDeserializer<BigDecimal> {
@Override
public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String text = p.getText();
// 支持 "123.45", "¥123.45", "123,45" 等
return new BigDecimal(text.replaceAll("[¥,]", ""));
}
}
@JsonDeserialize(using = MoneyDeserializer.class)
private BigDecimal amount;
快速总结:你最应该立刻掌握的 5 个
@JsonAnyGetter+@JsonAnySetter—— 处理动态字段@JsonUnwrapped—— 打平嵌套对象@JsonView—— 接口返回字段控制- Mix-in Annotations —— 不侵入第三方类
- 自定义 Deserializer —— 处理非标准格式(金额、枚举、日期等)
这些特性一旦熟练使用,能让你的 JSON 处理代码更优雅、更安全、维护成本更低。
你项目里现在用 Jackson 遇到过哪些最痛苦的场景?可以告诉我,我帮你针对性给出最优解法。