Search code examples
javajacksonjson-serialization

How can i apply @JsonSerialize annotation to a lib class property?


I'm using an external library in my project. One of it's models has a BigDecimal property, that requires a custom precision. If this model was mine, i would apply a @JsonSerialize annotation that uses custom serializer. But i can't modify sources of ext. lib... Is there any way to apply it somehow?


Solution

  • Exactly for this use-case Jackson offers so-called mixins. To illustrate how to use this let's walk through an example:

    Suppose you have a library class (named Model) containing a property of type BigDecimal.`

    public class Model {
    
        private BigDecimal number;
        
        public BigDecimal getNumber() {
            return number;
        }
        
        public void setNumber(BigDecimal number) {
            this.number = number;
        }
    }
    

    Now, you cannot modify the source of the library class above. But instead, you can write a class (let's call it ModelMixin) which kind of mirrors the library class Model and put any Jackson annotations there. Especially you can specify your own serializer for the BigDecimal number property.

    public abstract class ModelMixin {
    
        @JsonSerialize(using = MyBigDecimalSerializer.class)
        private BigDecimal number;
    }
    

    The serializer might be as simple or sophisticated as you need it. Here is a simple one which chooses to write the BigDecimal as a JSON string.

    public class MyBigDecimalSerializer extends JsonSerializer<BigDecimal> {
    
        @Override
        public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeString(value.toString());
        }
    }
    

    Now you need to tell Jackson's ObjectMapper to take the annotations from the ModelMixin class and apply them to theModel class. This is done by the addMixIn(Class,Class) method.

    ObjectMapper objectMapper = new ObjectMapper()
        .addMixIn(Model.class, ModelMixin.class);
        
    Model model = new Model();
    model.setNumber(BigDecimal.valueOf(123.456));
        
    objectMapper.writeValue(System.out, model);
    

    This writes the following JSON output:

    {"number":"123.456"}