mirror of
https://github.com/InsanusMokrassar/SDI.git
synced 2024-11-27 12:38:55 +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
|
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_group=com.insanusmokrassar
|
||||||
project_public_description=Simple DI library
|
project_public_description=Simple DI library
|
||||||
|
|
||||||
|
@ -1,31 +1,32 @@
|
|||||||
package com.insanusmokrassar.sdi.utils
|
package com.insanusmokrassar.sdi.utils
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.internal.StringDescriptor
|
import kotlinx.serialization.json.*
|
||||||
import kotlinx.serialization.modules.SerializerAlreadyRegisteredException
|
import kotlinx.serialization.modules.*
|
||||||
import kotlinx.serialization.modules.SerializersModuleBuilder
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@ImplicitReflectionSerializer
|
@ImplicitReflectionSerializer
|
||||||
internal class DependencyResolver<T : Any>(
|
internal class DependencyResolver<T : Any>(
|
||||||
serialModuleBuilder: SerializersModuleBuilder,
|
serialModuleBuilder: SerializersModuleBuilder,
|
||||||
kClass: KClass<T>,
|
kClass: KClass<T>,
|
||||||
|
private val formatterGetter: () -> Json,
|
||||||
private val dependencyGetter: (String) -> Any
|
private val dependencyGetter: (String) -> Any
|
||||||
) : KSerializer<T> {
|
) : KSerializer<T> {
|
||||||
private val originalSerializer: KSerializer<T>? = try {
|
private val originalSerializer: KSerializer<T> = try {
|
||||||
resolveSerializerByKClass(kClass)
|
resolveSerializerByKClass(kClass)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
PolymorphicSerializer(kClass)
|
||||||
}
|
}
|
||||||
private val objectsCache = mutableMapOf<String, T>()
|
private val objectsCache = mutableMapOf<String, T>()
|
||||||
override val descriptor: SerialDescriptor = originalSerializer ?.descriptor ?: StringDescriptor.withName("DependencyResolver")
|
override val descriptor: SerialDescriptor = originalSerializer.descriptor
|
||||||
|
|
||||||
init {
|
init {
|
||||||
serialModuleBuilder.apply {
|
serialModuleBuilder.apply {
|
||||||
contextual(kClass, this@DependencyResolver)
|
contextual(kClass, this@DependencyResolver)
|
||||||
kClass.allSubclasses.forEach { kClass ->
|
polymorphic(kClass, originalSerializer)
|
||||||
|
kClass.allSubclasses.forEach { currentKClass ->
|
||||||
try {
|
try {
|
||||||
DependencyResolver(serialModuleBuilder, kClass, dependencyGetter)
|
DependencyResolver(serialModuleBuilder, currentKClass, formatterGetter, dependencyGetter)
|
||||||
} catch (e: SerializerAlreadyRegisteredException) {
|
} catch (e: SerializerAlreadyRegisteredException) {
|
||||||
// ok
|
// ok
|
||||||
}
|
}
|
||||||
@ -34,13 +35,18 @@ internal class DependencyResolver<T : Any>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): T {
|
override fun deserialize(decoder: Decoder): T {
|
||||||
return try {
|
val decoded = decoder.decodeSerializableValue(JsonElementSerializer)
|
||||||
val dependencyName = decoder.decodeString()
|
return when {
|
||||||
(dependencyGetter(dependencyName) as T).also {
|
decoded is JsonPrimitive && decoded.contentOrNull != null -> decoded.content.let { dependencyName ->
|
||||||
objectsCache[dependencyName] = it
|
(dependencyGetter(dependencyName) as T).also {
|
||||||
|
objectsCache[dependencyName] = it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
decoded is JsonArray -> {
|
||||||
originalSerializer ?.deserialize(decoder) ?: throw IllegalStateException("Can't resolve dependency", e)
|
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
|
objectsCache[it] === obj
|
||||||
} ?.also { dependencyName ->
|
} ?.also { dependencyName ->
|
||||||
encoder.encodeString(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()
|
}.toMap()
|
||||||
|
|
||||||
return Json(
|
return Json(
|
||||||
|
configuration = JsonConfiguration(useArrayPolymorphism = true),
|
||||||
context = SerializersModule {
|
context = SerializersModule {
|
||||||
keysToPackages.values.forEach {
|
keysToPackages.values.forEach {
|
||||||
val kclass = resolveKClassByPackageName(it)
|
val kclass = resolveKClassByPackageName(it)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DependencyResolver(this, kclass) {
|
DependencyResolver(
|
||||||
|
this,
|
||||||
|
kclass,
|
||||||
|
{ jsonStringFormat }
|
||||||
|
) {
|
||||||
caches.getValue(it).invoke()
|
caches.getValue(it).invoke()
|
||||||
}
|
}
|
||||||
} catch (e: SerializerAlreadyRegisteredException) {
|
} 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