gpt4 book ai didi

java - 使用 ObjectMapper 时如何设置 jackson 序列化深度级别?

转载 作者:搜寻专家 更新时间:2023-11-01 00:58:37 33 4
gpt4 key购买 nike

假设我有以下类(class):

public class Employee {
private Department department;

// other fields, getters and setters omited for brevtity
}

public class Department {
private Address address;

// other fields, getters and setters omited for brevtity
}

public class Address {
private Location location;

// other fields, getters and setters omited for brevtity
}

public class Location {
private String streetName;

// other fields, getters and setters omited for brevtity
}

现在,我想加载 Employee 对象并用 ObjectMapper 序列化它:

public void serializeEmployee() {
Employee employee = entityManager.load(Employee.class, 1);
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(student));
}

当我运行上面的代码时,我看到这样的 json 字符串:

{
"department" : {
"address" : {
"location" : {
"streetName" : {}
}
}
}
}

但我想将序列化深度设置为一个级别,我的意思是当代码运行时,我想看到这样的结果:

{
"department" : {
}
}

注意

我不想使用 jackson 注释,我想在使用 mapper 对象时设置配置。例如调用 mapper.setConfigmapper.disable

最佳答案

您可以使用 PropertyFilter能够限制序列化的深度。这是我想出的解决方案。使用此过滤器时需要注意一些事项,示例中也对此进行了演示:

  • 数组提供了额外的深度级别,因此数组条目是父级的深度+2(这不是错误,这是一个功能 :D - 如果为数组开始解析上下文,则可以更改此行为)
  • map 属性在 map 声明的级别上完全序列化
  • 深度是按类定义的;如果您需要可变长度,您可以使用 DN 后缀扩展基类以进行序列化,或者创建一个常量过滤器名称并为每个深度创建一个专用的 ObjectMapper

这是代码。 DeepFieldFilter 进行深度计算。它必须在 ObjectMapper 中注册为过滤器,并且数据类必须使用 @JsonFilter 注释进行标记。

public class JsonSerializationDeepFun {

@Data
@JsonFilter("depth_3")
static class DynamicJsonObject {
Long id;
String name;
BigDecimal price;

List<DynamicJsonObject> children = new ArrayList<>();

@JsonIgnore
Map<String, Object> properties = new HashMap<>();

@JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}

@JsonAnyGetter
public Map<String, Object> getMap() {
return properties;
}
}


/**
* There're a couple of things to note when using this filter. <a href="https://stackoverflow.com/a/51279460/1961634">Visit stackoverflow for an example</a>
* <ul>
* <li>arrays provide an additional depth level, so array entry is depth+2
* from parent; it's not a bug, it's a feature - this behavior could be
* changed if JsonStreamContext is parsed for array start</li>
* <li>map properties are serialized fully at the level the map is declared</li>
* <li>depth is defined per-class; you could extend base class with DN suffix
* to serialize if you need variable length, or make a constant filter name
* and create a dedicated `ObjectMapper` for each depth</li>
* </ul>
* @author Dariusz Wawer <dwawer@pretius.com>
*
*/
static class DeepFieldFilter extends SimpleBeanPropertyFilter {
private final int maxDepth;

public DeepFieldFilter(int maxDepth) {
super();
this.maxDepth = maxDepth;
}

private int calcDepth(PropertyWriter writer, JsonGenerator jgen) {
JsonStreamContext sc = jgen.getOutputContext();
int depth = -1;
while (sc != null) {
sc = sc.getParent();
depth++;
}
return depth;
}

@Override
public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider provider, PropertyWriter writer)
throws Exception {
int depth = calcDepth(writer, gen);
if (depth <= maxDepth) {
writer.serializeAsField(pojo, gen, provider);
}
// comment this if you don't want {} placeholders
else {
writer.serializeAsOmittedField(pojo, gen, provider);
}
}

}

public static void main(String[] args) throws IOException {
ObjectMapper om = new ObjectMapper();

SimpleFilterProvider depthFilters = new SimpleFilterProvider().addFilter("depth_1", new DeepFieldFilter(1))
.addFilter("depth_2", new DeepFieldFilter(2))
.addFilter("depth_3", new DeepFieldFilter(3))
.addFilter("depth_4", new DeepFieldFilter(4))
.addFilter("depth_5", new DeepFieldFilter(5))
// ...
;
om.setFilterProvider(depthFilters);

om.enable(SerializationFeature.INDENT_OUTPUT);
DynamicJsonObject obj = new DynamicJsonObject();
obj.setId(321L);
obj.setName("name");
obj.setPrice(BigDecimal.valueOf(10.0));

Map<String, Object> mapD3 = new HashMap<>();
mapD3.put("depth", "3");
mapD3.put("info", "gets serialzied at depth 1");

Map<String, Object> mapD2 = new HashMap<>();
mapD2.put("depth", "2");
mapD2.put("map", mapD3);

Map<String, Object> mapD1 = new HashMap<>();
mapD1.put("depth", "1");
mapD1.put("map", mapD2);

obj.setProperties(mapD1);

DynamicJsonObject child = new DynamicJsonObject();
child.setId(514L);
child.setName("actually depth 3, because array");
child.setPrice(BigDecimal.valueOf(5.1));
obj.getChildren().add(child);

String jsonStr = om.writeValueAsString(obj);
System.out.println(jsonStr);
}

}

关于java - 使用 ObjectMapper 时如何设置 jackson 序列化深度级别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47908805/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com