I have the following module structure:
corepersistenceextension
In my core module, I have an interface: Handler. This interface has multiple implementations in the core module as well as extension module. Some implementations depend on other complex types.
I would like to persist instances of Handler in a database. My persistence module has a HandlerRepository which needs to somehow save any Handler to the database and later read them back. Since these are very dynamic, I would like to save them as JSON documents. I do not want to add any serialization/deserialization logic to my core module.
Here is the repository signature:
interface HandlerRepository {
fun findById(id: String): Handler
fun save(id: String, handler: Handler)
}
One idea I had was to introduce HandlerSerializer<Handler> which could serialize/deserialize a specific type of a Handler. I could do something like the following:
interface HandlerSerializer<T: Handler> {
fun serialize(handler: T): String
fun deserialize(json: String): T
}
object HandlerSerializerRegistry {
private val serializers = mutableMapOf<KClass<>, HandlerSerializer<>>()
fun <T : Handler> registerSerializer(type: KClass<T>, serializer: HandlerSerializer<T>) {
serializers[type] = serializer
}
fun <T : Handler> getSerializer(type: KClass<T>): HandlerSerializer<T>? {
return serializers[type] as? HandlerSerializer<T>
}
}
Then, to save a Handler, I would get the HandlerSerializer for that specific Handler from the HandlerSerializerRegistry and serialize it.
This seems like an acceptable solution and separation of concerns to me. However, I am having issues figuring out where to put HandlerSerializer implementations and tests for them? Putting these in core and extension does not seem correct to me and I cannot add them in persistence since that module does not know which Handler implementations exist.
Any advice? Is my design wrong? Am I missing something obvious?