gpt4 book ai didi

java - 在嵌套数组中使用 Jackson 序列化到一定深度

转载 作者:行者123 更新时间:2023-12-05 07:04:56 24 4
gpt4 key购买 nike

为了防止 Jackson 在序列化为 JSON 某些嵌套对象时返回无限深度,我遵循了这个:Serialize recursive objects with jackson up to a certain depth

这需要创建一个新的 BeanSerializer 并覆盖 serializeFields 方法。除非您正在序列化数组中包含的对象,否则这很好用。当我的 serializeFields 方法被调用时,我不知道我是否在数组中,所以对于每次调用,我的深度计数器实际上是在计算嵌套数组中的每个对象。所以基本上我只是在进行深度优先搜索,当达到我的极限时,我只是停止处理数组中的所有元素,而不是继续处理下一个元素。

我想我需要覆盖 ObjectArraySerializer.serializeContents 方法,这样我就可以将有关数组的信息传递到我的 serializeFields 方法,但我不确定如何去做。

有人指导吗?

--编辑--

我有一个可重现的错误。

输入:

    stdin:3

代码:

    import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializer;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

public class TestJackson {

public static void main(String[] args) throws IOException {
Node aNode = new Node("A");
Node bNode = new Node("B");
Node[] NodeArr = new Node[] {aNode,bNode};
aNode.setChild(NodeArr);
bNode.setChild(NodeArr);

//System.out.print(defMapper.writeValueAsString(aNode)); //Bombs, as expected

for (int i = 0; i < Integer.parseInt(args[0]); i++) {
System.out.println("Depth: " + i);
System.out.println(serialiseWithDepth(aNode, i));
}
}

private static ObjectMapper defMapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.build();

private static ObjectMapper mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(createNodeModule())
.build();

private static String serialiseWithDepth(Node node, int maxDepth) throws JsonProcessingException {
ObjectWriter writer = mapper.writerFor(Node.class)
.withAttribute(NodeDepthBeanSerializer.DEPTH_KEY, new AtomicInteger(maxDepth));

return writer.writeValueAsString(node);
}

private static SimpleModule createNodeModule() {
SimpleModule nodeModule = new SimpleModule("NodeModule");
nodeModule.setSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (beanDesc.getBeanClass() == Node.class) {
return new NodeDepthBeanSerializer((BeanSerializerBase) serializer);
}
return super.modifySerializer(config, beanDesc, serializer);
}
});
return nodeModule;
}
}

class NodeDepthBeanSerializer extends BeanSerializer {

public static final String DEPTH_KEY = "maxDepthSize";

public NodeDepthBeanSerializer(BeanSerializerBase src) {
super(src);
}

@Override
protected void serializeFields(Object bean, JsonGenerator gen, SerializerProvider provider) throws IOException {
AtomicInteger depth = (AtomicInteger) provider.getAttribute(DEPTH_KEY);
if (depth.decrementAndGet() >= 0) {
super.serializeFields(bean, gen, provider);
}
}
}

class Node {

public Node() {
this("",null, (new NodeHolder(new Node[]{})));
}
public Node(String id){
this(id,null, (new NodeHolder(new Node[]{})));
}
public Node(String theId,Node[] theChild,NodeHolder holder){
setId(theId);
setChild(theChild);
setHolder(holder);
}

private String id;

private Node[] child;

private NodeHolder holder;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public Node[] getChildren() {
return child;
}

public void setChild(Node[] child) {
this.child = child;
}

public NodeHolder getHolder() {
return holder;
}

public void setHolder(NodeHolder holder) {
this.holder = holder;
}
}
class NodeHolder {
public NodeHolder(Node[] theNodes) {
this.nodes = theNodes;
}

public Node[] getNodes() {
return nodes;
}

public void setNodes(Node[] nodes) {
this.nodes = nodes;
}

private Node[] nodes;
}

输出:

Depth: 0
{ }
Depth: 1
{
"id" : "A",
"holder" : {
"nodes" : [ ]
},
"children" : [ { }, { } ]
}
Depth: 2
{
"id" : "A",
"holder" : {
"nodes" : [ ]
},
"children" : [ {
"id" : "A",
"holder" : {
"nodes" : [ ]
},
"children" : [ { }, { } ]
}, { } ]
}

请注意子数组是如何全部为空,但它们的字段数恰好正确?它进行深度优先搜索,当计数器 < 0 时,它们返回而不移动到下一个数组元素。不确定解决它的最佳方法。

我也知道该示例没有意义,并且可能是糟糕的设计 - 它是一个大型 Web 应用程序 bean 结构的一部分的复制品,我目前没有时间或技能来重新设计:

--编辑--

请在此处查看工作示例: https://repl.it/@csxdog/Serialize-with-Jackson-up-to-Certain-Depth-in-Nested-Arrays

最佳答案

由于没有人回答:对于这个问题,因为我公开了一个 REST API,所以我最终创建了一些非递归包装器对象来保存结果值,以便 Jackson 可以轻松地解析它。这可能是该领域的最佳实践。这是一个 Hackathon 项目,所以我最初是在寻找最快的修复方法。

关于java - 在嵌套数组中使用 Jackson 序列化到一定深度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62834731/

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