1

Although I checked all tests in the kotlinpoet code, but I didn't find a proper way to implement below target codes, or I am not sure whether I used the best approach to do that. If anyone can provide some comments about this, that would be highly appreciate.

These properties are defined in the function of a class

Target Code 1

val outputState = StateType1(iouValue, ourIdentity, otherParty)

I used below codes to generate above code

.addCode(CodeBlock.of("%L",
    PropertySpec.builder("outputState", ClassName("","StateType1"))
        .initializer(CodeBlock.of("%T(%L, %L, %L)", ClassName("","StateType1"), "iouValue", "ourIdentity", "otherParty"))
        .build()))

But question would be this outputState might be from different types, for example, StateType1 has 3 parameters, but StateTyp2 might only has 1 parameter, how should I dynamically define my kotlinpoet code to generate correct target code.

Target Code 2

val txBuilder = TransactionBuilder(notary = notary)
    .addOutputState(outputState, TEMPLATE_CONTRACT_ID)

I didn't find a reference test case which has this scenario, after property's initializer then invoke it's function directly.

Jiachuan Li
  • 195
  • 9

1 Answers1

2

Use CodeBlock.Builder for the first example, it gives you more flexibility in constructing CodeBlocks:

fun createConstructorCall(type: TypeName, vararg args: String): CodeBlock {
  val argsCode = args
      .map { CodeBlock.of("%L", it) }
      .joinToCode(separator = ", ", prefix = "(", suffix = ")")
  return CodeBlock.Builder()
      .add("%T", type)
      .add(argsCode)
      .build()
}

val className = ClassName("", "StateType1")
val codeBlock = CodeBlock.of("%L", PropertySpec.builder("outputState", className)
    .initializer(createConstructorCall(className, "iouValue", "ourIdentity", "otherParty"))
    .build())
assertThat(codeBlock.toString()).isEqualTo("""
  |val outputState: StateType1 = StateType1(iouValue, ourIdentity, otherParty)
  |""".trimMargin())

In the second example, we don't really provide anything special, pass your code as a String and feel free to use placeholders to parameterize if needed:

val className1 = ClassName("", "TransactionBuilder")
val codeBlock1 = CodeBlock.of("%L", PropertySpec.builder("txBuilder", className)
    .initializer(
        "%T(notary = notary)\n.addOutputState(outputState, TEMPLATE_CONTRACT_ID)",
        className1)
    .build())
assertThat(codeBlock1.toString()).isEqualTo("""
  |val txBuilder: StateType1 = TransactionBuilder(notary = notary)
  |        .addOutputState(outputState, TEMPLATE_CONTRACT_ID)
  |""".trimMargin())
Egor
  • 39,695
  • 10
  • 113
  • 130