How to serialize single-valued @Data object using Jackson without nesting (e.g. {“id”:123}, not {“id”:{“value”:123}})? Code Answer

Hello Developer, Hope you guys are doing great. Today at Tutorial Guruji Official website, we are sharing the answer of How to serialize single-valued @Data object using Jackson without nesting (e.g. {“id”:123}, not {“id”:{“value”:123}})? without wasting too much if your time.

The question is published on by Tutorial Guruji team.

I’m planning to use Lombok for creating hundreds of classes that are based on “value object” pattern as follows:

@Data
public final class SomeId implements Serializable {
    private final long value;
}

And I want to use these classes for JSON serialization powered by Jackson. for example, consider a DTO class as follows:

public class SomeDTO {
    SomeId id;
    public SomeId getId() {
        return id;
    }
}

I want that DTO class to be serialized as something like {"id":123}, but Jackson produces something like {"id":{"value":123}}, which comes with unnecessary nested object with a field named value. i.e. a testcase expresses my requirement:

public class SomeDTOTest {
    @Test
    public void serializationTest() throws Exception {
        SomeDTO dto = new SomeDTO();
        dto.id = new SomeId(123);

        String serialized = new ObjectMapper().writeValueAsString(dto);

        System.out.println(serialized);             // {"id":{"value":123}}
        assertThat(serialized, is("{"id":123}")); // I want {"id":123} instead!
    }
}

I know putting @JsonValue annotation to every getValue() method in SomeId classes would be a solution, but I can’t do it because there is no actual definition of @Data classes because Lombok automatically creates it.

Creating actual getValue() method annotated as @JsonValue for every classes by hand might be another solution but it means creating tons of boilarplate code.

How do I achieve this requirement without boilerplate code?

Answer

You can write custom Serializer for this class.

E.g.:

class CustomSerializer extends StdSerializer<SomeId>{

    protected CustomSerializer(Class<SomeId> t) {
        super(t);
    }

    @Override
    public void serialize(SomeId someId, JsonGenerator gen, SerializerProvider serializers)
            throws IOException, JsonProcessingException {
        gen.writeNumber(someId.getValue()); 
    }   
}

Now use this serializer to serialize SomeId class:

 ObjectMapper mapper = new ObjectMapper();

 SimpleModule module = new SimpleModule();
 module.addSerializer(new CustomSerializer(SomeId.class));       
 mapper.registerModule(module);

 SomeDTO dto = new SomeDTO();
 dto.id = new SomeId(123);     
 String serialized = mapper.writeValueAsString(dto);
 System.out.println(serialized);             // output : {"id":123}
We are here to answer your question about How to serialize single-valued @Data object using Jackson without nesting (e.g. {“id”:123}, not {“id”:{“value”:123}})? - If you find the proper solution, please don't forgot to share this with your team members.

Related Posts

Tutorial Guruji