We sometimes need to tunnel information to a nested serializer and do it from the top level.
Let’s take the following example of some Shape objects which are nested in a Drawing object.
|
public class Drawing { private final List<Shape> shapes; public Drawing(List<Shape> shapes) { this.shapes = shapes; } public List<Shape> getShapes() { return shapes; } } |
|
public class Shape { private final String name; public Shape(String name) { this.name = name; } public String getName() { return name; } } |
We will be serializing the drawing object using Jackson, so let’s define the appropriate serializers.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public class DrawingSerializer extends StdSerializer<Drawing> { public DrawingSerializer() { super(Drawing.class); } @Override public void serialize(Drawing drawing, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeArrayFieldStart("shapes"); for (Shape shape : drawing.getShapes()) { serializerProvider.defaultSerializeValue(shape, jsonGenerator); } jsonGenerator.writeEndArray(); } } |
|
public class ShapeSerializer extends StdSerializer<Shape> { public ShapeSerializer() { super(Shape.class); } @Override public void serialize(Shape shape, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { serializerProvider.defaultSerializeValue(shape.getName(), jsonGenerator); } } |
Now, let’s say that from the Drawing serializer we would like to inject some information into the Shape serializer. But, as you see Jackson never gives us an instance of the Shape serializer so it won’t be possible to change its members.
So how do we do this? Here come the attributes. These ones are set on the SerializerProvider object and can be later retrieved from a more nested serializer.
As example, let’s say we want to inject an attribute, that, when true, will make the Shape serializer output the name as upper case.
We inject the attribute in the Drawing serializer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public class DrawingSerializer extends StdSerializer<Drawing> { public DrawingSerializer() { super(Drawing.class); } @Override public void serialize(Drawing drawing, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeArrayFieldStart("shapes"); serializerProvider.setAttribute("uppercaseFlag", Boolean.TRUE); for (Shape shape : drawing.getShapes()) { serializerProvider.defaultSerializeValue(shape, jsonGenerator); } jsonGenerator.writeEndArray(); } } |
Now from the nested serializer we can retrieve the value of the attribute which was injected at top level.
|
public class ShapeSerializer extends StdSerializer<Shape> { public ShapeSerializer() { super(Shape.class); } @Override public void serialize(Shape shape, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { Boolean allUppercase = (Boolean) serializerProvider.getAttribute("uppercaseFlag"); String name = allUppercase != null && allUppercase ? shape.getName().toUpperCase() : shape.getName(); serializerProvider.defaultSerializeValue(name, jsonGenerator); } } |