需求

开发接口的时候,偶尔会遇到这样的需求,开发一个接口,请求参数字段名称是固定的,但是响应参数的字段名称是不一样的,也就是说,我们在开发一个通用接口,能够返回各种各样的数据。我们返回的数据是一般是定义在对象中,如果返回数据放置在 Map 中,就没有办法写 swagger 文档(swagger 注解需要写在对象属性上)。如果把 Map 属性变成实体属性,即使牺牲了部分文档,在某些场景下还是可以使用的。

@JsonAnyGetter

@JsonAnyGetter 注解能够把 Map 属性变成实体属性。例如,ExtendableBean 实体具有 name 属性和一组键/值对形式的可扩展属性。

ExtendableBean

  1. @Data
  2. public class ExtendableBean {
  3. public String name;
  4. private Map<String, String> properties;
  5. @JsonAnyGetter
  6. public Map<String, String> getProperties() {
  7. return properties;
  8. }
  9. public ExtendableBean(String name) {
  10. this.name = name;
  11. }
  12. public void add(String attr, String value) {
  13. if (properties == null) {
  14. properties = new HashMap<>();
  15. }
  16. properties.put(attr, value);
  17. }
  18. }

test

  1. @Test
  2. public void anyGetter() throws JsonProcessingException {
  3. ExtendableBean bean = new ExtendableBean("My bean");
  4. bean.add("attr1", "val1");
  5. bean.add("attr2", "val2");
  6. String result = new ObjectMapper().writeValueAsString(bean);
  7. System.out.println("result: ".concat(result));
  8. }

序列化结果

  1. {
  2. "name": "My bean",
  3. "attr2": "val2",
  4. "attr1": "val1"
  5. }

禁用

我们还可以使用启用为 false 的可选参数来禁用 @JsonAnyGetter。在这种情况下,Map 将转换为 JSON,并在序列化后显示在 properties 变量下。

  1. @JsonAnyGetter(enabled = false)
  2. public Map<String, String> getProperties() {
  3. return properties;
  4. }

序列化结果

  1. {
  2. "name": "My bean",
  3. "properties": {
  4. "attr2": "val2",
  5. "attr1": "val1"
  6. }
  7. }