Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Jackson JSON serialization based on parent context

I am trying to conditionally serialize a child bean based on information from the parent.

public class Parent {
  private boolean isSecure;
  private Child child;
}

public class Child {
  String someValue;
}

Basically, if the parent.isSecure() is true, then I want to serialize the someValue differently than if parent.isSecure() is false.

My actual classes are much more complex than this simple example, so I don't really want to create a full custom serializer for Parent that I would need to maintain separately (unless you can show me how to leverage standard serialization for Parent within the custom serializer without having to iterate through all the properties and deal with JSON annotations, views, and such. If you can, that might work, as I could set a context attribute based on isSecure()).

I don't mind writing a custom serializer for a child, but I don't know how to check the value from the parent.

I've considered using a 'secure' view and 'insecure' view that I could specify outside the entire serialization process, but then I would have to go through and annotate lots of properties of the parent class to be in both the 'secure' and 'insecure' view (as I have turned off the DEFAULT_VIEW_INCLUSION option due to a number of properties I never want to be serialized).

I tried to access generator.getCurrentValue() within my custom Child serializer, but it is always null, so I'm not sure how it is supposed to work.

I've considered writing a custom serializer for isSecure, and setting a context attribute within it, but how can I be sure that it will be called prior to the custom serializer for a child? (Though I will admit that I'm not sure context attributes really work the way I am assuming.)

Any ideas?

like image 442
DavidA Avatar asked Jun 24 '15 19:06

DavidA


1 Answers

You could create a serializer specific to your isSecure scenario. Using JsonGenerator#getCurrentValue inside of a child element will return the parent. Something like this should allow you to control serialization of Child without having to modify the serialization of the other properties on Parent.

Create a Child serializer to check the Parent property

SecureChildSerializer and InsecureChildSerializer are meant to be implementations of JsonSerializer<Child>

public class IsSecureChildSerializer extends JsonSerializer<Child> {
    private static final SecureChildSerializer SECURE_CHILD_SERIALIZER = new SecureChildSerializer();
    private static final InsecureChildSerializer INSECURE_CHILD_SERIALIZER = new InsecureChildSerializer();

    @Override
    public void serialize(Child value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (gen.getCurrentValue() instanceof Parent) {
            Parent parent = (Parent) gen.getCurrentValue();
            if (parent.isSecure) {
                SECURE_CHILD_SERIALIZER.serialize(value, gen, serializers);
            } else {
                INSECURE_CHILD_SERIALIZER.serialize(value, gen, serializers);
            }
        }
    }
}

Apply the Child serializer to properties of concern

public class Parent {
    public boolean isSecure;

    @JsonSerialize(using = IsSecureChildSerializer.class)
    public Child child;
}
like image 85
Sam Berry Avatar answered Oct 30 '22 20:10

Sam Berry