Skip to content
Advertisement

How to conditionally serialize a field

I want to conditionally serialize a field. I figured out how to conditionally ignore a field with

public class NologIntrospector extends JacksonAnnotationIntrospector {
    @Override
    public boolean hasIgnoreMarker(AnnotatedMember m) {
        boolean noLogOnClass = m.getDeclaringClass().getAnnotation(NoLog.class) != null;
        return m.hasAnnotation(NoLog.class) || super.hasIgnoreMarker(m) || noLogOnClass;
    }
}

But what I really want to do is to redact the field. So if I have

@Getter
@Setter
@NoArgsConstructor
public class MyObject1 {
    public String field1 = "field1";
    @NoLog
    public String field2 = "field2";

    public static void main(String[] args) throws JsonProcessingException {
        final ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setAnnotationIntrospector(new NologIntrospector());
        final MyObject1 myObject1 = new MyObject1();
        System.out.println(objectMapper.writeValueAsString(myObject1));
    }
}

I get

{"field1":"field1"}

Field2 is correctly ignored. But what I really want is

{"field1":"field1", "field2": "<***redacted***>"}

I have another annotation, @MaskSensitiveData

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = MaskSensitiveDataSerializer.class)
public @interface MaskSensitiveData {
}

public class MaskSensitiveDataSerializer extends StdSerializer<Object> {

    protected MaskSensitiveDataSerializer() {
        this(null);
    }

    public MaskSensitiveDataSerializer(Class<Object> t) {
        super(t);
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (!(value instanceof  String)) {
            throw new RuntimeException("MaskSensitiveData annotation is only valid for string");
        }
        gen.writeString("<*** redacted ***>");
    }
}

So what I want to do is combine them. So if a field has the special annotation and I am using my introspector, only then, do I want to redact the field. Otherwise, the field should be serialized normally.

Advertisement

Answer

Instead of overriding method hasIgnoreMarker in NologIntrospector. You need to override findSerializer. This way when your introspector is enabled the custom serializer will be used else it will use the original serializer.

public class NologIntrospector extends JacksonAnnotationIntrospector {
    @Override
    public Object findSerializer(Annotated ann){
        if (ann.hasAnnotation(NoLog.class)) {
            return MaskSensitiveDataSerializer.class;
        }
        return super.findSerializer(ann);
    }
}
Advertisement