Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 560
Kohei Nozaki Avatar asked Apr 06 '16 03:04

Kohei Nozaki


1 Answers

I created an interface which has getValue() which annotated as @JsonValue:

public interface LongValue {
    @JsonValue
    long getValue();
}

Then implemented it in every @Data classes. note that actual implementation of getValue() will be automatically generated by Lombok:

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

With that I've got the test SomeDTOTest passed - SomeDTO is serialized to {"id":123} as I expected.

like image 155
Kohei Nozaki Avatar answered Sep 28 '22 20:09

Kohei Nozaki