diff --git a/compose/src/main/java/br/zup/com/nimbus/compose/TypeDeserializer.kt b/compose/src/main/java/br/zup/com/nimbus/compose/TypeDeserializer.kt new file mode 100644 index 0000000..166e467 --- /dev/null +++ b/compose/src/main/java/br/zup/com/nimbus/compose/TypeDeserializer.kt @@ -0,0 +1,7 @@ +package br.zup.com.nimbus.compose + +import com.zup.nimbus.core.deserialization.ComponentDeserializer + +interface TypeDeserializer { + fun deserialize(properties: ComponentDeserializer, data: ComponentData, name: String): T +} diff --git a/processor/src/main/java/com/zup/nimbus/processor/ClassNames.kt b/processor/src/main/java/com/zup/nimbus/processor/ClassNames.kt index e0027e3..725acd5 100644 --- a/processor/src/main/java/com/zup/nimbus/processor/ClassNames.kt +++ b/processor/src/main/java/com/zup/nimbus/processor/ClassNames.kt @@ -9,6 +9,7 @@ object ClassNames { val ComponentData = ClassName(PackageNames.nimbusCompose, "ComponentData") val NimbusTheme = ClassName(PackageNames.nimbusCompose, "NimbusTheme") val NimbusMode = ClassName(PackageNames.nimbusCompose, "NimbusMode") + val TypeDeserializer = ClassName(PackageNames.nimbusCompose, "TypeDeserializer") val ComponentDeserializer = ClassName( "${PackageNames.nimbusCore}.deserialization", "ComponentDeserializer", diff --git a/processor/src/main/java/com/zup/nimbus/processor/Computed.kt b/processor/src/main/java/com/zup/nimbus/processor/Computed.kt index fcb6ec6..9dbdbea 100644 --- a/processor/src/main/java/com/zup/nimbus/processor/Computed.kt +++ b/processor/src/main/java/com/zup/nimbus/processor/Computed.kt @@ -4,4 +4,5 @@ import kotlin.reflect.KClass @Retention(AnnotationRetention.SOURCE) @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class Computed>(val deserializer: KClass) +// FIXME: typing. should be: annotation class Computed>(val deserializer: KClass) +annotation class Computed(val deserializer: KClass<*>) diff --git a/processor/src/main/java/com/zup/nimbus/processor/ParameterInfo.kt b/processor/src/main/java/com/zup/nimbus/processor/ParameterInfo.kt index af1b9f8..1a4860e 100644 --- a/processor/src/main/java/com/zup/nimbus/processor/ParameterInfo.kt +++ b/processor/src/main/java/com/zup/nimbus/processor/ParameterInfo.kt @@ -29,6 +29,7 @@ class ParameterInfo(parameter: KSValueParameter, fn: KSFunctionDeclaration) { val isParentName: Boolean val deserializer: ClassName? val arity: Int? + val isRoot: Boolean init { name = parameter.name?.asString() ?: throw NamelessParameterException(parameter, fn) @@ -41,6 +42,10 @@ class ParameterInfo(parameter: KSValueParameter, fn: KSFunctionDeclaration) { // todo: don't rely on simple name annotation -> annotation.shortName.asString() == "ParentName" } + isRoot = parameter.annotations.any { + // todo: don't rely on simple name + annotation -> annotation.shortName.asString() == "Root" + } val deserializerType = parameter.annotations.find { // todo: don't rely on simple name annotation -> annotation.shortName.asString() == "Computed" @@ -58,10 +63,6 @@ class ParameterInfo(parameter: KSValueParameter, fn: KSFunctionDeclaration) { } else if (resolved.declaration.modifiers.contains(Modifier.ENUM)) { TypeCategory.Enum } else if (!resolved.isFunctionType && resolved.declaration is KSClassDeclaration) { - val isRoot = parameter.annotations.any { - // todo: don't rely on simple name - annotation -> annotation.shortName.asString() == "Root" - } if (!isRoot && deserializer == null) throw NonRootEntityException(parameter, fn) mustDeserialize.add(resolved.declaration as KSClassDeclaration) TypeCategory.Deserializable diff --git a/processor/src/main/java/com/zup/nimbus/processor/ServerDrivenProcessor.kt b/processor/src/main/java/com/zup/nimbus/processor/ServerDrivenProcessor.kt index 832f857..1658455 100644 --- a/processor/src/main/java/com/zup/nimbus/processor/ServerDrivenProcessor.kt +++ b/processor/src/main/java/com/zup/nimbus/processor/ServerDrivenProcessor.kt @@ -28,6 +28,36 @@ class ServerDrivenProcessor(private val environment: SymbolProcessorEnvironment) getSymbolsWithAnnotation(kClass.qualifiedName.toString()) .filterIsInstance() + private fun handleDeserializer(param: ParameterInfo, fnBuilder: FunSpec.Builder) { + if (param.isRoot) { + fnBuilder.addStatement( + "val %L = %L.deserialize(properties, data, %S)", + param.name, + param.deserializer!!.simpleName, + param.name, + ) + } else if (param.nullable) { + fnBuilder.addCode(""" + |val %L = if (properties.enter(%S, true)) { + | val result = %L.deserialize(properties, data, %S) + | properties.leave() + | result + |} else null + |""".trimMargin(), + param.name, param.name, param.deserializer!!.simpleName, param.name + ) + } else { + fnBuilder.addStatement("properties.enter(%S, false)", param.name) + fnBuilder.addStatement( + "val %L = %L.deserialize(properties, data, %S)", + param.name, + param.deserializer!!.simpleName, + param.name, + ) + fnBuilder.addStatement("properties.leave()", param.name) + } + } + private fun createNimbusComposable( builder: FileSpec.Builder, fn: KSFunctionDeclaration, @@ -49,11 +79,7 @@ class ServerDrivenProcessor(private val environment: SymbolProcessorEnvironment) if (it.deserializer.packageName != fn.packageName.asString()) { builder.addClassImport(it.deserializer) } - fnBuilder.addStatement( - "val %L = %L.deserialize(data)", - it.name, - it.deserializer.simpleName, - ) + handleDeserializer(it, fnBuilder) } else { when (it.category) { @@ -102,7 +128,7 @@ class ServerDrivenProcessor(private val environment: SymbolProcessorEnvironment) mustDeserialize.addAll(it.mustDeserialize) builder.addImport(it.packageName, it.type) fnBuilder.addStatement( - "val %L = NimbusEntityDeserializer.deserialize(properties, %L::class)", + "val %L = NimbusEntityDeserializer.deserialize(properties, data, %L::class)", it.name, it.type, ) @@ -165,6 +191,7 @@ class ServerDrivenProcessor(private val environment: SymbolProcessorEnvironment) .replace(".", "_") val fnBuilder = FunSpec.builder(name) .addParameter("properties", ClassNames.ComponentDeserializer) + .addParameter("data", ClassNames.ComponentData) .addModifiers(KModifier.PRIVATE) .returns(ClassName(clazz.packageName.asString(), clazz.simpleName.asString())) val constructorInfo = FunctionInfo( @@ -175,11 +202,7 @@ class ServerDrivenProcessor(private val environment: SymbolProcessorEnvironment) if (it.deserializer.packageName != clazz.packageName.asString()) { builder.addClassImport(it.deserializer) } - fnBuilder.addStatement( - "val %L = %L.deserialize(data)", - it.name, - it.deserializer.simpleName, - ) + handleDeserializer(it, fnBuilder) } else { when (it.category) { @@ -262,6 +285,10 @@ class ServerDrivenProcessor(private val environment: SymbolProcessorEnvironment) ParameterSpec.builder( "properties", ClassNames.ComponentDeserializer, + ).build(), + ParameterSpec.builder( + "data", + ClassNames.ComponentData, ).build() ), returnType = Any::class.asTypeName(), @@ -274,7 +301,7 @@ class ServerDrivenProcessor(private val environment: SymbolProcessorEnvironment) "mutableMapOf(%L)", mustDeserialize.joinToString(", ") { val name = "${it.packageName.asString()}.${it.simpleName.asString()}" - "\"$name\" to { ${name.replace(".", "_")}(it) }" + "\"$name\" to { properties, data -> ${name.replace(".", "_")}(properties, data) }" }, ) ) @@ -295,11 +322,12 @@ class ServerDrivenProcessor(private val environment: SymbolProcessorEnvironment) ) ) .addParameter("properties", ClassNames.ComponentDeserializer) + .addParameter("data", ClassNames.ComponentData) .addParameter("clazz", TypeVariableName("U")) .returns(TypeVariableName("T")) .addStatement( "return deserializers.get(clazz.qualifiedName ?: \"\")?.let " + - "{ it(properties) as T } ?: throw IllegalArgumentException(%P)", + "{ it(properties, data) as T } ?: throw IllegalArgumentException(%P)", "\${clazz.simpleName} is an invalid Server Driven entity because no " + "deserializer has been found for it." ) diff --git a/processor/src/main/java/com/zup/nimbus/processor/TypeDeserializer.kt b/processor/src/main/java/com/zup/nimbus/processor/TypeDeserializer.kt deleted file mode 100644 index 5c1c720..0000000 --- a/processor/src/main/java/com/zup/nimbus/processor/TypeDeserializer.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.zup.nimbus.processor - -interface TypeDeserializer { - // todo: Any should be ComponentData, but how to import it from nimbus-compose? - fun deserialize(data: Any): T -}