I have various types of events
in my application that are represented by Data classes.
All events
must have an attribute called EventContent
that stores additional data about the event in String format. These events are saved to a database and EventContent
is serialized into a JSON via kotlin.x.serialization.
To enforce this, I have used an interface like this on a sample event called ShutdownEvent
:
interface Event {
var eventContent: String
}
data class ShutdownEvent(
override var eventContent: String
) : Event
Now imagine for the specific event called ShutdownEvent
, I know its EventContent
must have only 2 attributes: trigger
and location
, both of which are Strings. How can I enforce that the EventContent
follows this structure.
I was hoping for something like this:
data class ShutdownEvent(
@Serializable(with = ShutdownContentConverter::class) override var eventContent: ShutdownData,
) : Event
@Serializable
data class ShutdownData(
var trigger: String,
var location: String,
)
But this causes problems with my Event
interface implementation, because it expects the eventContent
attribute to be a String. Is there an easy way to make this work?
Edit:
I would appreciate an answer that allows me to process my events as follows:
fun process(event: Event) {
if (event is ShutdownEvent) {
// do something
}
}
CodePudding user response:
One possible way to deal with this is to make your interface generic in the "event content" type, instead of using String:
interface Event<C> {
var eventContent: C
}
data class ShutdownEvent(
@Serializable(with = ShutdownContentConverter::class)
override var eventContent: ShutdownData,
) : Event<ShutdownData>
@Serializable
data class ShutdownData(
var trigger: String,
var location: String,
)
If all possible types of event content have some common properties, you can define a parent EventContent
interface like this:
/** A parent interface for all types of event content. */
interface EventContent {
val someCommonProp: String
}
interface Event<C : EventContent> {
var eventContent: C
}
data class ShutdownEvent(
@Serializable(with = ShutdownContentConverter::class)
override var eventContent: ShutdownData,
) : Event<ShutdownData>
@Serializable
data class ShutdownData(
override val someCommonProp: String,
var trigger: String,
var location: String,
) : EventContent
Side note: I would strongly advise to use val
instead of var
everywhere here. You probably don't want event data to be mutable. Once the event is created no-one should really modify it.