Skip to content

Commit

Permalink
Add a workaround for nulls in non-nullable fields (#571)
Browse files Browse the repository at this point in the history
## 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 <jplewa@virtuslab.com>
  • Loading branch information
jplewa authored May 27, 2024
1 parent c6735b8 commit e7eb2f2
Showing 1 changed file with 29 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<RootType>,
generationOptions: GenerationOptions = GenerationOptions(),
Expand All @@ -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)
}
Expand All @@ -82,16 +92,24 @@ object TypeGenerator {
)
}

private fun prepareFieldsForTypesUsedForFunctionsOrAsOutput(type: ComplexType) =
type.fields.map { (name, typeAndOptionality) ->
private fun prepareFieldsForTypesUsedForFunctionsOrAsOutput(
typeNameClashResolver: TypeNameClashResolver,
type: ComplexType,
): List<Field<ReferencedType>> {
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
Expand Down Expand Up @@ -307,4 +325,10 @@ object TypeGenerator {
val fields: List<Field<ReferencedType>>,
val options: GenerationOptions,
)

private data class NullabilityException(
val packageName: String,
val typeName: String,
val fieldName: String,
)
}

0 comments on commit e7eb2f2

Please sign in to comment.