用杰克逊序列化递归对象到一定深度
Serialize recursive objects with jackson up to a certain depth
我有一个需要序列化的树对象结构,我希望每次都能够基于使用 jackson(或任何其他库 - 我是开放的)的参数来控制序列化的深度。
我的class是这样的:
class Node {
...
private String id;
private Node child;
...
}
这里有 2 个序列化示例 json,我想根据深度级别
获取它们
深度级别设置为 3
{
"id": "A",
"child": {
"id": "B",
"child": {
"id": "C",
"child": {}
}
}
}
深度级别设置为 2
{
"id": "A",
"child": {
"id": "B",
"child": {}
}
}
有什么方法可以控制递归对象的序列化深度吗?
谢谢
您需要实现自定义序列化程序,您需要在其中计算已处理的 Node
对象的数量。对于每个序列化过程,我们需要提供 max depth
值并在每次发现 Node
class 时递减它。示例实现:
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 JsonApp {
public static void main(String[] args) throws IOException {
Node nodeD = new Node("D", null);
Node nodeC = new Node("C", nodeD);
Node nodeB = new Node("B", nodeC);
Node nodeA = new Node("A", nodeB);
for (int i = 0; i < 4; i++) {
System.out.println("Depth: " + i);
System.out.println(serialiseWithDepth(nodeA, i));
}
}
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);
}
}
}
以上代码打印:
Depth: 0
Node{id='A', child=Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}}} => 0
{ }
Depth: 1
Node{id='A', child=Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}}} => 1
Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}} => 0
{
"id" : "A",
"child" : { }
}
Depth: 2
Node{id='A', child=Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}}} => 2
Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}} => 1
Node{id='C', child=Node{id='D', child=null}} => 0
{
"id" : "A",
"child" : {
"id" : "B",
"child" : { }
}
}
Depth: 3
Node{id='A', child=Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}}} => 3
Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}} => 2
Node{id='C', child=Node{id='D', child=null}} => 1
Node{id='D', child=null} => 0
{
"id" : "A",
"child" : {
"id" : "B",
"child" : {
"id" : "C",
"child" : { }
}
}
}
我有一个需要序列化的树对象结构,我希望每次都能够基于使用 jackson(或任何其他库 - 我是开放的)的参数来控制序列化的深度。
我的class是这样的:
class Node {
...
private String id;
private Node child;
...
}
这里有 2 个序列化示例 json,我想根据深度级别
获取它们深度级别设置为 3
{
"id": "A",
"child": {
"id": "B",
"child": {
"id": "C",
"child": {}
}
}
}
深度级别设置为 2
{
"id": "A",
"child": {
"id": "B",
"child": {}
}
}
有什么方法可以控制递归对象的序列化深度吗?
谢谢
您需要实现自定义序列化程序,您需要在其中计算已处理的 Node
对象的数量。对于每个序列化过程,我们需要提供 max depth
值并在每次发现 Node
class 时递减它。示例实现:
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 JsonApp {
public static void main(String[] args) throws IOException {
Node nodeD = new Node("D", null);
Node nodeC = new Node("C", nodeD);
Node nodeB = new Node("B", nodeC);
Node nodeA = new Node("A", nodeB);
for (int i = 0; i < 4; i++) {
System.out.println("Depth: " + i);
System.out.println(serialiseWithDepth(nodeA, i));
}
}
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);
}
}
}
以上代码打印:
Depth: 0
Node{id='A', child=Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}}} => 0
{ }
Depth: 1
Node{id='A', child=Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}}} => 1
Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}} => 0
{
"id" : "A",
"child" : { }
}
Depth: 2
Node{id='A', child=Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}}} => 2
Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}} => 1
Node{id='C', child=Node{id='D', child=null}} => 0
{
"id" : "A",
"child" : {
"id" : "B",
"child" : { }
}
}
Depth: 3
Node{id='A', child=Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}}} => 3
Node{id='B', child=Node{id='C', child=Node{id='D', child=null}}} => 2
Node{id='C', child=Node{id='D', child=null}} => 1
Node{id='D', child=null} => 0
{
"id" : "A",
"child" : {
"id" : "B",
"child" : {
"id" : "C",
"child" : { }
}
}
}