javakotlinjacksondto

Exclude certain nested props in DTO with Jackson


Assuming I have these three DTO's

data class CountryDTO(
    val name: String,
    val isoAlpha3: String,
    val subContinent: SubContinentDto,
    val continent: ContinentDto
)

data class SubContinentDTO(
    val name: String,
    val continent: ContinentDto
)

data class ContinentDTO(
    val name: String,
)

A response with a single CountryDTO in it would have duplicated values: ContinentDTO would be in CountryDTO and nested in SubContinentDTO. If I return a CountryDTO, I would not want ContinentDTO to be nested in SubContinentDTO, but only "on the first level" of CountryDTO.

But, if I return a SubContinentDTO, I would want a ContinentDTO to be in there, becaue now its not nested anymore.

Now, I could create a CountryNotNestedDTO which would contain a SubContinentNotNestedDTO

data class CountryNotNestedDTO(
    val name: String,
    val isoAlpha3: String,
    val subContinent: SubContinentNotNestedDTO,
    val continent: ContinentDto
)

data class SubContinentNotNestedDTO(
    val name: String,
)

But this feels rather strange... Is there a way to tell Jackson to exclude certain properties from classes, depending on where the class is used? Or is there something else I could do in order not to have these more or less duplicated DTOs?


Solution

  • This is a typical problem when creating an API. I know of 3 ways of doing this:

    1. Move all the common field into a separate SubCountinentFlatDto. And in your SubContinentFullDto include the common SubCountinentFlatDto and mark it as @JsonUnwrapped - this way during serialization all the nested fields are going to be included in the parent object.

    2. Use inheritance, but this will limit you in how flexible you want to be in separating the DTOs because multiple inheritance isn't a thing in Java.

    3. Use @JsonView to mark that this field is applicable only in certain contexts. During (de)serialization you'll need to specify which views you're interested in. However, this is a questionable practice because later you'll be passing this object to your methods which won't know about views and won't know which fields to use or not.

    A typical situation when you want to have different sets of fields is POSTing a resource (the id field should be excluded) and GETing resource (id must be present).