Skip to content

More granular control of class discriminator at use site #3187

Description

@geoffliu

What is your use-case and why do you need this feature?

Suppose we have sealed interface with subclasses to model two special kinds of products:

interface Product
data class FooProduct(...): Product
data class BarProduct(...): Product

And requests that get one of the base types:

data class GetFooProductResponse(
  ... other fields
  product: FooProduct
)

Once this response is serialized to the front end, the FooProduct objects do not have class discriminator. I understand this is documented behavior, but the workarounds are all a bit uncomfortable:

  • Front end attaches class discriminator when it receives the response, but this is error prone
  • Change FooProduct to just Product in the response, but we lose type safety and intentionality
  • ClassDiscriminatorMode is a non-starter. I'm in a Spring project, response serialization settings are global, turning it on would affect everything else in the project

I think my realistic options are the following, unless I missed something:

  • Add a @Serializable(with = FooProductSerializer) on the products field, and it forwards all calls to a serializer<Product>()
  • Hook into Spring response serialization and add special case

Describe the solution you'd like

Ideally, more granular control of class discriminator, so something like

@ClassDiscriminatorMode(ALWAYS) data class FooProduct(...)

Or

@ClassDiscriminatorMode(ALL_SEALED_SUBCLASSES) interface Product

Or 

data class GetFooProductResponse(
  ... other fields
  @ClassDiscriminatorMode(ALWAYS)
  product: FooProduct
)

Short of that, if the @Serializable annotation can accept another class

data class GetFooProductResponse(
  ... other fields
  @Serializable(as = Product::class)
  product: FooProduct
)

I realize there could be some ambiguity with ClassDiscriminatorMode as a field annotation approach, as whether it's recursive or not, what happens with List<FooProduct>, etc, but annotation on class would be pretty clean? In any case, curious what people think, also curious if I'm just missing something obvious.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions