Сериализация с Джексоном до определенной глубины во вложенных массивах - PullRequest
2 голосов
/ 10 июля 2020

Я следил за этим, чтобы Джексон не возвращал бесконечную глубину при сериализации в 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

1 Ответ

0 голосов
/ 17 августа 2020

Поскольку никто не ответил с ответом: для этой проблемы, поскольку я выставлял REST API, я в конечном итоге создал несколько нерекурсивных объектов-оберток для хранения полученного значения, чтобы Джексон мог легко его проанализировать. Вероятно, это лучшая практика в данной области. Это был проект Хакатона, поэтому изначально я искал самое быстрое решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...