How do I generate a constructor parameter of the Kotlin "Unit" type with a single type parameter with kotlinpoet?

1.5k Views Asked by At

This might be a bit too specific for posting here, but I'm trying to generate a class like this with kotlinpoet:

class Query<out E: Model>(val onSuccess: (E) -> Unit, val onError: (Int, String) -> Unit = { i, m -> })

How would I create that type/constructor parameter with kotlinpoet? The docs do have the "Unit" type listed along with primitive types, so it seems to be a special case.

2

There are 2 best solutions below

2
On BEST ANSWER

Easily enough, it's done by using the LambdaTypeName class. It was a bit confusing after getting used to kotlin's functional type style as opposed to java strictly functional interfaces. Here's what I used:

val typeVariable = TypeVariableName.invoke("E")
    .withBounds(QueryData::class)
ParameterSpec.builder("onSuccess", 
    LambdaTypeName.get(null, listOf(typeVariable), UNIT)).build()

Which generates (with the class builders, of course):

class Query<E : QueryData> {
  constructor(onSuccess: (E) -> Unit) {
  }
}
0
On

Here's a program producing the output you need:

class Model

fun main(args: Array<String>) {
  val onSuccessType = LambdaTypeName.get(
      parameters = TypeVariableName(name = "E"),
      returnType = Unit::class.asTypeName())
  val onErrorType = LambdaTypeName.get(
      parameters = listOf(Int::class.asTypeName(), String::class.asTypeName()),
      returnType = Unit::class.asTypeName())
  val primaryConstructor = FunSpec.constructorBuilder()
      .addParameter(ParameterSpec.builder(name = "onSuccess", type = onSuccessType)
          .build())
      .addParameter(ParameterSpec.builder(name = "onError", type = onErrorType)
          .defaultValue("{ i, m -> }")
          .build())
      .build()

  val querySpec = TypeSpec.classBuilder("Query")
      .addTypeVariable(TypeVariableName(name = "out E", bounds = Model::class))
      .addProperty(PropertySpec.builder(name = "onSuccess", type = onSuccessType)
          .initializer("onSuccess")
          .build())
      .addProperty(PropertySpec.builder(name = "onError", type = onErrorType)
          .initializer("onError")
          .build())
      .primaryConstructor(primaryConstructor)
      .build()

  val file = KotlinFile.builder(packageName = "", fileName = "test")
      .addType(querySpec)
      .build()
  file.writeTo(System.out)
}

This prints (excluding generated imports) the following:

class Query<out E : Model>(val onSuccess: (E) -> Unit,
    val onError: (Int, String) -> Unit = { i, m -> })

I'm hacking TypeVariableName here as out E, since there seems to be no better solution at the time. I'm also using the 0.4.0-SNAPSHOT version.