I have a tree object structure that I need to Serialize and I want to be able to control the depth of the serialization every time based on a parameter using jackson (or any other library - I am open).
My class is like this:
class Node {
...
private String id;
private Node child;
...
}
And here are 2 examples of serialized json that I would like to get based on depth level
depth level set to 3
{
"id": "A",
"child": {
"id": "B",
"child": {
"id": "C",
"child": {}
}
}
}
depth level set to 2
{
"id": "A",
"child": {
"id": "B",
"child": {}
}
}
Is there any way to control the depth of serialization in recursive objects?
Thanks
You need to implement custom serializer in which you need to count number of already handled Node objects. For each serialization process we need to provide max depth value and decrement it every time Node class is spotted. Example implementation:
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);
}
}
}
Above code prints:
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" : { }
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With