jackson @JsonAnyGetter @JsonAnySetter 使用说明

@JsonAnyGetter@JsonAnySetter 是 Jackson 库中两个用于处理动态或未定义属性的注解,非常适合处理字段不固定的 JSON 数据。下面我将为你详细解释它们的用法。

@JsonAnyGetter - 动态序列化属性

@JsonAnyGetter 注解用于序列化 过程,它能将一个 Map 中的所有键值对平铺 到 JSON 中,与对象原有的其他字段处于同一级别

核心要点与示例

  • 方法要求 :该注解通常标注在一个无参数、返回 Map 对象 的方法上。这个 Map 包含了所有你希望平铺序列化的动态属性。
  • 示例场景 :假设你有一个 User 类,它有一些固定字段(如 id, name),同时希望灵活地添加其他属性(如 address, age
java 复制代码
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import java.util.HashMap;
import java.util.Map;

public class User {
    private String id;
    private String name;
    private Map<String, Object> dynamicFields = new HashMap<>(); // 存储动态属性

    // 标准的getter和setter方法
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    @JsonAnyGetter // 关键注解:序列化时,dynamicFields Map中的所有条目将被平铺输出
    public Map<String, Object> getDynamicFields() {
        return dynamicFields;
    }

    // 一个用于向动态字段添加属性的方法
    public void addDynamicField(String key, Object value) {
        this.dynamicFields.put(key, value);
    }
}

使用这个类并序列化:

java 复制代码
User user = new User();
user.setId("10001");
user.setName("小明");
user.addDynamicField("address", "浙江省杭州市");
user.addDynamicField("age", 22);

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
System.out.println(json);

输出结果

java 复制代码
{
  "id": "10001",
  "name": "小明",
  "address": "浙江省杭州市",
  "age": 22
}

如你所见,addressage 这两个存储在 dynamicFields Map 中的属性,被平铺到了最终的 JSON 里,与 idname 同级

@JsonAnySetter - 动态反序列化属性

@JsonAnySetter 注解用于反序列化 过程。当 JSON 中包含未在 Java 类中明确定义的字段时,Jackson 会调用被此注解标注的方法,将这些未知的键值对收集起来

核心要点与示例

  • 方法要求 :该注解标注在一个接受两个参数(String key, Object value) 的方法上
  • 示例场景:在反序列化时,处理 JSON 中超出已知字段的额外属性。
java 复制代码
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;

public class User {
    private String id;
    private String name;
    private Map<String, Object> dynamicFields = new HashMap<>();

    // ... (固定字段的getter和setter同上)

    @JsonAnySetter // 关键注解:反序列化时,未知属性会通过此方法存入dynamicFields
    public void setDynamicField(String key, Object value) {
        this.dynamicFields.put(key, value);
    }

    public Map<String, Object> getDynamicFields() {
        return dynamicFields;
    }

    public static void main(String[] args) throws Exception {
        String json = "{\"id\":\"10001\",\"name\":\"小明\",\"address\":\"浙江省杭州市\",\"age\":22}";

        ObjectMapper mapper = new ObjectMapper();
        User user = mapper.readValue(json, User.class);

        System.out.println("ID: " + user.getId()); // ID: 10001
        System.out.println("Name: " + user.getName()); // Name: 小明
        System.out.println("Dynamic Fields: " + user.getDynamicFields()); 
        // Dynamic Fields: {address=浙江省杭州市, age=22}
    }
}

在这个例子中,JSON 里的 addressageUser 类中没有对应的明确定义,因此它们被 @JsonAnySetter 标注的方法捕获,并放入了 dynamicFields Map 中

组合使用与注意事项

  1. 组合使用 :你可以同时使用 @JsonAnyGetter@JsonAnySetter,让一个类能够完美地处理动态属性的序列化与反序列化
java 复制代码
public class FlexibleBean {
    private Map<String, Object> extraProps = new HashMap<>();
    
    @JsonAnyGetter
    public Map<String, Object> getExtraProps() { return extraProps; }
    
    @JsonAnySetter
    public void setExtraProps(String key, Object value) { this.extraProps.put(key, value); }
}
  1. 关于Kotlin :请注意,在Kotlin的data class中,如果属性在构造函数中声明,@JsonAnySetter可能无法直接用于不可变的val属性。一种解决方法是将其声明为类体内普通的var属性,或者在反序列化时使用可变Map
  2. 方法访问权限 :确保被注解的方法具有公共public)的访问权限,否则Jackson可能无法访问它们

总结

  • @JsonAnyGetter :让你的对象在序列化为JSON时,能将Map中的键值对作为平铺的同级字段输出。
  • @JsonAnySetter :让你的对象在从JSON反序列化时,能捕获所有未知字段,并将其存入Map。

这两个注解联手,为你提供了一种非常灵活的方式来处理那些结构不固定或者包含动态自定义字段的JSON数据

希望这些解释和示例能帮助你理解并使用这两个注解。如果你在处理更复杂的嵌套结构时遇到问题,Jackson也提供了如@JsonUnwrapped等其他注解,或许可以进一步探索。

相关推荐
我命由我123452 分钟前
PHP - PHP 基本随机数生成函数
开发语言·ide·后端·java-ee·php·intellij-idea·intellij idea
楼田莉子8 分钟前
C#学习之C#入门学习
开发语言·后端·学习·c#
海上彼尚11 分钟前
Nodejs也能写Agent - 6.基础篇 - Agent
前端·人工智能·后端·node.js
字节高级特工23 分钟前
C++11(一) 革新:右值引用与移动语义
java·开发语言·c++·人工智能·后端
青云计划29 分钟前
Synchronized 锁升级:从偏向锁到重量级锁的性能进化之路
java·后端
candyTong11 小时前
Claude Code 的 Edit 工具是怎么工作的
javascript·后端·架构
GetcharZp12 小时前
GitHub 2.4 万 Star!D2 正在重新定义程序员画图方式
后端
zhangxingchao13 小时前
多 Agent 架构到底怎么选?从 Claude Agent Teams、Cognition/Devin 到工程落地原则
前端·人工智能·后端
IT_陈寒13 小时前
SpringBoot那个自动配置的坑,害我排查到凌晨三点
前端·人工智能·后端
ServBay13 小时前
OpenCode 和它的7款必备插件
后端·github·ai编程