I have the following module structure:
core
persistence
extension
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?
I cannot add them in persistence since that module does not know which Handler implementations exist.
neither Hibernate (to mention a known persisten framework) knows all the posible objects it will persist and yet the serialization/deserialization is implemented by the the framework. Don't draw bold and hard lines between modules. Don't let their names to limit the design.