mirror of
https://github.com/InsanusMokrassar/SDI.git
synced 2024-11-27 04:28:53 +00:00
custom objects instead of dependencies
This commit is contained in:
parent
41eb2341f7
commit
dc71996546
6
CHANGELOG.md
Normal file
6
CHANGELOG.md
Normal file
@ -0,0 +1,6 @@
|
||||
# SDI changelogs
|
||||
|
||||
## 0.1.1
|
||||
|
||||
* Added opportunity to create objects inside of config:
|
||||
* Now it is possible to construct object without usage of dependency on `@ContextualSerialization` place
|
@ -4,7 +4,7 @@ kotlin_serialisation_runtime_version=0.14.0
|
||||
|
||||
gradle_bintray_plugin_version=1.8.4
|
||||
|
||||
project_public_version=0.1.0
|
||||
project_public_version=0.1.1
|
||||
project_public_group=com.insanusmokrassar
|
||||
project_public_description=Simple DI library
|
||||
|
||||
|
@ -1,31 +1,32 @@
|
||||
package com.insanusmokrassar.sdi.utils
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.internal.StringDescriptor
|
||||
import kotlinx.serialization.modules.SerializerAlreadyRegisteredException
|
||||
import kotlinx.serialization.modules.SerializersModuleBuilder
|
||||
import kotlinx.serialization.json.*
|
||||
import kotlinx.serialization.modules.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@ImplicitReflectionSerializer
|
||||
internal class DependencyResolver<T : Any>(
|
||||
serialModuleBuilder: SerializersModuleBuilder,
|
||||
kClass: KClass<T>,
|
||||
private val formatterGetter: () -> Json,
|
||||
private val dependencyGetter: (String) -> Any
|
||||
) : KSerializer<T> {
|
||||
private val originalSerializer: KSerializer<T>? = try {
|
||||
private val originalSerializer: KSerializer<T> = try {
|
||||
resolveSerializerByKClass(kClass)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
PolymorphicSerializer(kClass)
|
||||
}
|
||||
private val objectsCache = mutableMapOf<String, T>()
|
||||
override val descriptor: SerialDescriptor = originalSerializer ?.descriptor ?: StringDescriptor.withName("DependencyResolver")
|
||||
override val descriptor: SerialDescriptor = originalSerializer.descriptor
|
||||
|
||||
init {
|
||||
serialModuleBuilder.apply {
|
||||
contextual(kClass, this@DependencyResolver)
|
||||
kClass.allSubclasses.forEach { kClass ->
|
||||
polymorphic(kClass, originalSerializer)
|
||||
kClass.allSubclasses.forEach { currentKClass ->
|
||||
try {
|
||||
DependencyResolver(serialModuleBuilder, kClass, dependencyGetter)
|
||||
DependencyResolver(serialModuleBuilder, currentKClass, formatterGetter, dependencyGetter)
|
||||
} catch (e: SerializerAlreadyRegisteredException) {
|
||||
// ok
|
||||
}
|
||||
@ -34,13 +35,18 @@ internal class DependencyResolver<T : Any>(
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): T {
|
||||
return try {
|
||||
val dependencyName = decoder.decodeString()
|
||||
(dependencyGetter(dependencyName) as T).also {
|
||||
objectsCache[dependencyName] = it
|
||||
val decoded = decoder.decodeSerializableValue(JsonElementSerializer)
|
||||
return when {
|
||||
decoded is JsonPrimitive && decoded.contentOrNull != null -> decoded.content.let { dependencyName ->
|
||||
(dependencyGetter(dependencyName) as T).also {
|
||||
objectsCache[dependencyName] = it
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
originalSerializer ?.deserialize(decoder) ?: throw IllegalStateException("Can't resolve dependency", e)
|
||||
decoded is JsonArray -> {
|
||||
val serializer = resolveSerializerByPackageName(decoded.getPrimitive(0).content)
|
||||
formatterGetter().fromJson(serializer, decoded[1]) as T
|
||||
}
|
||||
else -> formatterGetter().fromJson(originalSerializer, decoded)
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +55,6 @@ internal class DependencyResolver<T : Any>(
|
||||
objectsCache[it] === obj
|
||||
} ?.also { dependencyName ->
|
||||
encoder.encodeString(dependencyName)
|
||||
} ?: originalSerializer ?.serialize(encoder, obj) ?: throw IllegalStateException("Can't resolve dependency")
|
||||
} ?: originalSerializer.serialize(encoder, obj)
|
||||
}
|
||||
}
|
||||
|
@ -64,12 +64,17 @@ internal fun createModuleBasedOnConfigRoot(jsonObject: JsonObject): Json {
|
||||
}.toMap()
|
||||
|
||||
return Json(
|
||||
configuration = JsonConfiguration(useArrayPolymorphism = true),
|
||||
context = SerializersModule {
|
||||
keysToPackages.values.forEach {
|
||||
val kclass = resolveKClassByPackageName(it)
|
||||
|
||||
try {
|
||||
DependencyResolver(this, kclass) {
|
||||
DependencyResolver(
|
||||
this,
|
||||
kclass,
|
||||
{ jsonStringFormat }
|
||||
) {
|
||||
caches.getValue(it).invoke()
|
||||
}
|
||||
} catch (e: SerializerAlreadyRegisteredException) {
|
||||
|
@ -0,0 +1,97 @@
|
||||
package com.insanusmokrassar.sdi
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.test.*
|
||||
|
||||
interface SimpleCustomObject_ControllerAPI {
|
||||
fun showUp()
|
||||
}
|
||||
interface SimpleCustomObject_ServiceAPI {
|
||||
val names: List<String>
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class SimpleCustomObject_Controller(@ContextualSerialization val service: SimpleCustomObject_ServiceAPI) : SimpleCustomObject_ControllerAPI {
|
||||
override fun showUp() {
|
||||
println("Inited with name \"${service.names}\"")
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class SimpleCustomObject_CustomController1(@ContextualSerialization val service: SimpleCustomObject_ServiceAPI) : SimpleCustomObject_ControllerAPI {
|
||||
override fun showUp() {
|
||||
println("Inited with name \"${service.names}\"")
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class SimpleCustomObject_CustomController2(@ContextualSerialization val service: SimpleCustomObject_BusinessService) : SimpleCustomObject_ControllerAPI {
|
||||
override fun showUp() {
|
||||
println("Inited with name \"${service.names}\"")
|
||||
}
|
||||
}
|
||||
@Serializable
|
||||
class SimpleCustomObject_BusinessService(override val names: List<String>) : SimpleCustomObject_ServiceAPI
|
||||
|
||||
@ImplicitReflectionSerializer
|
||||
class SimpleCustomObjectTest {
|
||||
@Test
|
||||
fun test_that_simple_config_correctly_work() {
|
||||
val names = arrayOf("nameOne", "nameTwo")
|
||||
val customNames = arrayOf("customNameOne", "customNameTwo")
|
||||
val controllerName = "controller"
|
||||
val customController1Name = "controller1"
|
||||
val customController2Name = "controller2"
|
||||
val input = """
|
||||
{
|
||||
"service": [
|
||||
"${SimpleCustomObject_BusinessService::class.qualifiedName}",
|
||||
{
|
||||
"names": ${names.joinToString(prefix = "[", postfix = "]") { "\"$it\"" }}
|
||||
}
|
||||
],
|
||||
"$controllerName": [
|
||||
"${SimpleCustomObject_Controller::class.qualifiedName}",
|
||||
{
|
||||
"service": "service"
|
||||
}
|
||||
],
|
||||
"$customController1Name": [
|
||||
"${SimpleCustomObject_CustomController1::class.qualifiedName}",
|
||||
{
|
||||
"service": [
|
||||
"${SimpleCustomObject_BusinessService::class.qualifiedName}",
|
||||
{
|
||||
"names": ${customNames.joinToString(prefix = "[", postfix = "]") { "\"$it\"" }}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"$customController2Name": [
|
||||
"${SimpleCustomObject_CustomController2::class.qualifiedName}",
|
||||
{
|
||||
"service": {
|
||||
"names": "${customNames.joinToString(prefix = "[", postfix = "]") { "\"$it\"" }}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
""".trimIndent()
|
||||
val module = Json.plain.parse(Module.serializer(), input)
|
||||
|
||||
(module[controllerName] as SimpleCustomObject_ControllerAPI)
|
||||
val controller = (module["controller"] as SimpleCustomObject_Controller)
|
||||
assertEquals(names.toList(), controller.service.names)
|
||||
|
||||
|
||||
(module[customController1Name] as SimpleCustomObject_ControllerAPI)
|
||||
val customController1 = (module[customController1Name] as SimpleCustomObject_CustomController1)
|
||||
assertEquals(customNames.toList(), customController1.service.names)
|
||||
|
||||
|
||||
(module[customController2Name] as SimpleCustomObject_ControllerAPI)
|
||||
val customController2 = (module[customController2Name] as SimpleCustomObject_CustomController2)
|
||||
assertEquals(customNames.toList(), customController2.service.names)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user