Я следил за этим, чтобы Джексон не возвращал бесконечную глубину при сериализации в JSON определенных вложенных объектов: Сериализовать рекурсивные объекты с помощью Джексона до определенной глубины
Это влечет создание нового BeanSerializer и переопределение метода serializeFields. Это отлично работает, если вы не сериализуете объекты, содержащиеся в массивах. Когда вызывается мой метод serializeFields, я понятия не имею, нахожусь я в массиве или нет, поэтому для каждого вызова мой счетчик глубины фактически подсчитывает каждый объект во вложенном массиве. Так что в основном я просто выполняю поиск в глубину, и по достижении своего предела я просто прекращаю обработку всех элементов в массиве, вместо того, чтобы продолжать работу со следующим элементом.
Думаю, мне нужно перезаписать ObjectArraySerializer. serializeContents, поэтому я могу передать информацию о массиве моему методу serializeFields, но я не уверен, как go об этом.
Есть ли у кого-нибудь рекомендации?
- Изменить -
У меня воспроизводимая ошибка.
Ввод:
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. Не уверен, что это лучший способ go решить эту проблему. </p>
Я также знаю, что пример не имеет смысла и, вероятно, является плохим дизайном - это воспроизведение части массивной структуры bean-компонента веб-приложения, которую у меня нет времени или навыков для изменения дизайна: D
- Edit -
См. Рабочий пример здесь: https://repl.it/@csxdog / Serialize-with-Jackson-up-to-Certain-Depth-in-Nested-Arrays