需求
开发接口的时候,偶尔会遇到这样的需求,开发一个接口,请求参数字段名称是固定的,但是响应参数的字段名称是不一样的,也就是说,我们在开发一个通用接口,能够返回各种各样的数据。我们返回的数据是一般是定义在对象中,如果返回数据放置在 Map 中,就没有办法写 swagger 文档(swagger 注解需要写在对象属性上)。如果把 Map 属性变成实体属性,即使牺牲了部分文档,在某些场景下还是可以使用的。
@JsonAnyGetter
@JsonAnyGetter 注解能够把 Map 属性变成实体属性。例如,ExtendableBean 实体具有 name 属性和一组键/值对形式的可扩展属性。
ExtendableBean
@Data
public class ExtendableBean {
public String name;
private Map<String, String> properties;
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
public ExtendableBean(String name) {
this.name = name;
}
public void add(String attr, String value) {
if (properties == null) {
properties = new HashMap<>();
}
properties.put(attr, value);
}
}
test
@Test
public void anyGetter() throws JsonProcessingException {
ExtendableBean bean = new ExtendableBean("My bean");
bean.add("attr1", "val1");
bean.add("attr2", "val2");
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println("result: ".concat(result));
}
序列化结果
{
"name": "My bean",
"attr2": "val2",
"attr1": "val1"
}
禁用
我们还可以使用启用为 false 的可选参数来禁用 @JsonAnyGetter。在这种情况下,Map 将转换为 JSON,并在序列化后显示在 properties 变量下。
@JsonAnyGetter(enabled = false)
public Map<String, String> getProperties() {
return properties;
}
序列化结果
{
"name": "My bean",
"properties": {
"attr2": "val2",
"attr1": "val1"
}
}