How to define Workflow method arguments and return values as Java interface or abstract class?

I want to define Workflow method arguments and return values as Java interface so the API is generic (without using Java generic since I don’t know all implementations of the interface). Is this supported OOTB?

I understand the default JSON data converter doesn’t know how to de/serialize interface/abstract classes. Is the only way is to provide my own data converter? If yes, then it’s not “elegant” since I can only provide data converter once per Temporal workflow client which my app has only one, therefore, I have to “inspect” the payload type, i.e., having conditional which I don’t want to do and I don’t want one workflow client per workflow type.

1 Like

By default Temporal uses Jackson for serialization and deserialization of arguments. It looks like Jackson supports polymorphic deserialization. It needs to be configured, but DataConverter APIs allow such configuration.

I personally would not recommend going this route as RPC that passes around non value classes is too brittle for my taste.

I’ve successfully used Jackson’s polymorphic deserialisation without having to define a custom data converter. Just using the @JsonTypeInfo and JsonSubTypes annotations on my value objects. I can then define both Workflow methods and Activity methods to accept and return Interface types rather than concrete classes. Here is an example in Kotlin. I think there are other ways to define the subtypes with Jackson annotations but this is the way that I knew how to do with Jackson.

@JsonTypeInfo(
  use = Id.NAME,
  include = As.Property,
  property = "@type"
)
@JsonSubTypes(
  JsonSubTypes.Type(value = First::class, name = "first"),
  JsonSubTypes.Type(value = Second::class, name = "second")
)
interface CustomInterface

data class First(
  @JsonProperty val first: String
) : CustomInterface

data class Second(
  @JsonProperty val second: Long
) : CustomInterface

The JSON payloads you’ll get for these will look like

{
  "@type": "first",
  "first": "this is a value"
}

{
  "@type": "second",
  "second": 123456789
}
1 Like

Thanks Tucker. Let me explore this approach.