javajsonjacksonjackson-databindjackson2

Jackson How to add additional properties during searlization without making changes to default POJO?


I am using Jackson-ObjectMapper to create the JSON data according to my POJO. I would like to add some additional properties to my JSON without modifying the POJO.

Since the POJO has been added as a dependency in my project I cannot modify it but I need some additional fields in JSON. Is there a way to add new key-value pair to JSON without making modifications to Java POJO? I am currently using Jackson 2.13.2 latest version dependencies: jackson-core, jackson-databind, jackson-annotations, jackson-datatype-jdk8

Following is the Java code:

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;

public class Test {
    public static void main(String args[]) throws Exception{
        ObjectMapper objectMapper = new ObjectMapper();

        CustomClass cc = new CustomClass();
        cc.setName("Batman");
        cc.setAge(30);
        System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(cc));
    }

    @Getter
    @Setter
    public static class CustomClass {
        private String name;
        private int age;
    }
}

This is providing me with the JSON:

{
  "name" : "Batman",
  "age" : 30
}

I would like to obtain the JSON that looks something like this, but do not want to add new fields job and company to my CustomClass POJO.

{
  "name" : "Batman",
  "age" : 30,
  "job" : "HR",
  "company": "New"
}

I tried to do something like this: https://www.jdoodle.com/a/z99 but I get the error: Type id handling not implemented for type package.ClassName (by serializer of type package.CustomModule$CustomClassSerializer)


Solution

  • You can try like below in the controller level, (it would be better to manipulate the response by using the Interceptor or Filter)

       @GetMapping
       public ObjectNode test() throws JsonProcessingException {
    
        CustomClass customClass = new CustomClass();
        customClass.setAge(30);
        customClass.setName("Batman");
    
        ObjectMapper mapper = new ObjectMapper();
        String jsonStr = mapper.writeValueAsString(customClass);
        ObjectNode nodes = mapper.readValue(jsonStr, ObjectNode.class);
        nodes.put("job", "HR ");
        nodes.put("company", "New ");
    
        return nodes;
    }
    

    Response:

    {
    name: "Batman",
    age: 30,
    job: "HR ",
    company: "New "
    }
    

    Your new test driver is below,

     public static void main(String[] args) throws JsonProcessingException {
                CustomClass customClass = new CustomClass();
                customClass.setAge(30);
                customClass.setName("Batman");
        
                ObjectMapper mapper = new ObjectMapper();
                String jsonStr = mapper.writeValueAsString(customClass);
                ObjectNode nodes = mapper.readValue(jsonStr, ObjectNode.class);
                nodes.put("job", "HR ");
                nodes.put("company", "New ");
                System.out.println(nodes);
        
            }
    

    Output: {"name":"Batman","age":30,"job":"HR ","company":"New "}


    Updated

    but I get the error: Type id handling not implemented for type package.ClassName (by serializer of type package.CustomModule$CustomClassSerializer)

    Write new object fields "job" and "company" to your custom class serializer.

    public class Test {
        public static void main(String args[]) throws Exception {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.registerModule(new CustomModule());
            CustomClass cc = new CustomClass();
            cc.setAge(30);
            cc.setName("Batman");
            StringWriter sw = new StringWriter();
            objectMapper.writeValue(sw, cc);
            System.out.println(sw.toString());
        }
    
        public static class CustomModule extends SimpleModule {
            public CustomModule() {
                addSerializer(CustomClass.class, new CustomClassSerializer());
            }
    
            private static class CustomClassSerializer extends JsonSerializer {
                @Override
                public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
                    // Validate.isInstanceOf(CustomClass.class, value);
                    jgen.writeStartObject();
                    JavaType javaType = provider.constructType(CustomClass.class);
                    BeanDescription beanDesc = provider.getConfig().introspect(javaType);
                    JsonSerializer<Object> serializer = BeanSerializerFactory.instance.findBeanSerializer(provider,
                            javaType, beanDesc);
                    // this is basically your 'writeAllFields()'-method:
                    serializer.unwrappingSerializer(null).serialize(value, jgen, provider);
                    jgen.writeObjectField("job", "HR ");
                    jgen.writeObjectField("company", "New ");
                    jgen.writeEndObject();
                }
            }
        }
    }
    

    Output: {"name":"Batman","age":30,"job":"HR ","company":"New "}