Search code examples
javajsonjacksonpojo

Jackson: How to edit existing property to the JSON without modifying the POJO?


I need to edit the name of "existing field" in POJO instead of adding "extra_field". Is it possible with the approach referenced link below?

Please note I do not want to use @JsonProperty annotation.

Requirement is, I have a POJO and want to use different field name every time without change in POJO. For example I have a field c_id in POJO and some times it need to write as cust_id and another time it would be my_id.

Also note I cannot change implementation of POJO as it is already used in several modules and have generic implementation.

POJO Example:

class MyPojo {
    String id; 
    // getter and setters
}

Expected output can be the following: (name of field can be changed)

  1. {"cust_id": "123"}
  2. {"my_id": "123"}

Solution

  • Mixins

    The easiest way to modify the output of Jackson without adding annotations to the original POJO is using mixins.

    Just define a mixin-class with the necessary annotations and indicate to Jackson that you want to use the mixin when serializing the original object.

    private static class MyPojoMixin {
        @JsonProperty("cust_id")
        private String id;
    }
    
    public String serializeWithMixin(MyPojo p) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.addMixIn(MyPojo.class, MyPojoMixin.class);
    
        return mapper.writeValueAsString(p);
    }
    

    Custom property naming strategy

    If you need to programmatically change the field-name, you might not be able to use the mixin solution. You could then use a custom PropertyNamingStrategy:

    public class IdRenamingStrategy extends PropertyNamingStrategy {
        private final PropertyNamingStrategy inner;
        private final String newIdPropertyName;
    
        public IdRenamingStrategy(String newIdPropertyName) {
            this(PropertyNamingStrategy.LOWER_CAMEL_CASE, newIdPropertyName);
        }
    
        public IdRenamingStrategy(PropertyNamingStrategy inner, String newIdPropertyName) {
            this.inner = inner;
            this.newIdPropertyName = newIdPropertyName;
        }
    
        private String translate(String propertyName) {
            if ("id".equals(propertyName)) {
                return newIdPropertyName;
            } else {
                return propertyName;
            }
        }
    
        @Override
        public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
            return inner.nameForField(config, field, translate(defaultName));
        }
    
        @Override
        public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
            return inner.nameForGetterMethod(config, method, translate(defaultName));
        }
    
        @Override
        public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
            return inner.nameForSetterMethod(config, method, translate(defaultName));
        }
    
        @Override
        public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName) {
            return inner.nameForConstructorParameter(config, ctorParam, translate(defaultName));
        }
    }
    

    This can be used like this:

    public String serializeWithPropertyNamingStrategy(MyPojo p) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(new IdRenamingStrategy("cust_id"));
    
        return mapper.writeValueAsString(p));
    }