From e7eb2f2c9376147da25a72cfc5d0a8a3a58999c8 Mon Sep 17 00:00:00 2001 From: Julia Plewa <34098778+jplewa@users.noreply.github.com> Date: Mon, 27 May 2024 15:42:43 +0200 Subject: [PATCH] Add a workaround for nulls in non-nullable fields (#571) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Task Related to: #402 ## Description This is absolutely not a fix, however no one will have the time to actually fix this any time soon and right now there is no way to use functions such as this one (we immediately get a NPE in `toKotlin`). It's actually a great fear of mine that one of the libraries that I use in my demo presentations will break like this 🙈 The actual fix will presumably be to make all fields lazy and only report errors once they're touched by the user. With this workaround we will at least have a way to make a function/resource work after someone reports such a problem in one of the providers. --------- Signed-off-by: Julia Plewa --- .../step3codegen/types/TypeGenerator.kt | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/types/TypeGenerator.kt b/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/types/TypeGenerator.kt index 9b1e7396..2cb7918d 100644 --- a/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/types/TypeGenerator.kt +++ b/src/main/kotlin/org/virtuslab/pulumikotlin/codegen/step3codegen/types/TypeGenerator.kt @@ -46,6 +46,16 @@ import kotlin.streams.asSequence object TypeGenerator { + /** + * This is a workaround for nullable fields being reported as non-nullable in Pulumi schemas. + * Without this workaround, the affected code causes runtime exceptions when mapping Java objects into Kotlin. + * See: https://github.com/VirtuslabRnD/pulumi-kotlin/issues/402 + */ + private val nullabilityExceptions = setOf( + NullabilityException("com.pulumi.gcp.organizations.kotlin.outputs", "GetProjectResult", "autoCreateNetwork"), + NullabilityException("com.pulumi.gcp.organizations.kotlin.outputs", "GetProjectResult", "skipDelete"), + ) + fun generateTypes( types: List, generationOptions: GenerationOptions = GenerationOptions(), @@ -56,7 +66,7 @@ object TypeGenerator { val isFunction = usageKind.subject == Function val isOutput = usageKind.direction == Output val fields = if (isFunction || isOutput) { - prepareFieldsForTypesUsedForFunctionsOrAsOutput(type) + prepareFieldsForTypesUsedForFunctionsOrAsOutput(typeNameClashResolver, type) } else { prepareFields(type) } @@ -82,16 +92,24 @@ object TypeGenerator { ) } - private fun prepareFieldsForTypesUsedForFunctionsOrAsOutput(type: ComplexType) = - type.fields.map { (name, typeAndOptionality) -> + private fun prepareFieldsForTypesUsedForFunctionsOrAsOutput( + typeNameClashResolver: TypeNameClashResolver, + type: ComplexType, + ): List> { + val className = typeNameClashResolver.kotlinNames(type.metadata) + return type.fields.map { (fieldName, typeAndOptionality) -> + val isNullabilityException = nullabilityExceptions.contains( + NullabilityException(className.packageName, className.className, fieldName), + ) Field( - name, + fieldName, NormalField(typeAndOptionality.type) { it }, - typeAndOptionality.type !is OptionalType, + !(typeAndOptionality.type is OptionalType || isNullabilityException), overloads = emptyList(), typeAndOptionality.kDoc, ) } + } private fun generateFile(context: Context, typeNameClashResolver: TypeNameClashResolver): FileSpec { val typeMetadata = context.typeMetadata @@ -307,4 +325,10 @@ object TypeGenerator { val fields: List>, val options: GenerationOptions, ) + + private data class NullabilityException( + val packageName: String, + val typeName: String, + val fieldName: String, + ) }