ConstructorSpec
Why
At the moment of writing, KotlinPoet doesn't have a ConstructorSpec. Because KotlinPoetDSL want's to allow building the code in an intuitive way, this means that the primary constructor should be able to define fields. Therefor, KotlinPoetDSL needs to have a ConstructorSpec
Implementation
ConstructorSpec is a combination of a list of PropertySpecs, a FunctionSpec and a boolean indicates if it is a primary or a secondary constructor. Asking for the properties will either return its list with PropertySpecs or an empty list, based on if it's a primary or secondary constructor.
Construction
You can build the constructor in a view ways:
implicit from the clazz-call
using buildConstructor
for interoperability, using a funSpec.
Implicit from the clazz-call
When creating a class, you can create a primary constructor implicitly from the clazz-function:
file("", "Hello"){
//--------------------- doesn't create a primary construcor
clazz("First") // class First
//-------------------- interoperability
val param = ParameterSpec.builder("par", String::class).build()
clazz("Second", param)// class Second(par: String)
val immutable = PropertySpec.builder("immutable", String::class).build()
clazz("Third", immutable) //class Third(val prop: String)
val mutableProp = PropertySpec.varBuilder("mutable", String::class).build()
clazz("Fourth", mutableProp) //class Fourth(var prop: String)
//------------------- KotlinPoetDSLs way
clazz("Fifth", "prop" of String::class) // Fifth(prop : String)
clazz("Sixth", "prop" varOf String::class) // Sixth(var prop : String)
clazz("Sixth", "prop" valOf String::class) // Sixth(val prop : String)
}
Stand-alone using buildConstructor
You can create a standalone ConstructorSpec using createConstructor
.
Inside the function, you can use the real DSL to create a constructor.
Inside the lambda, you need to return a ConstructorSpec, so the curly brackets.
Technically it's not needed, but overhere I wanted to be strict.
fun main(args: Array<String>) {
val constr1 = createConstructor {
private.constructor("prop" valOf String::class) {}
}
constr1 // private constructor(prop : String)
constr1.toPrimary() // private constructor(val prop : String)
val constr2 = createConstructor {
internal.primary.constructor("prop" varOf String::class)
}
constr2 // internal primary constructor(var prop : String)
val constr3 = createConstructor {
constructor("prop" of String::class){}
}
constr3 //constructor(prop : String)
constr3.toPrimary() //primary constructor(prop : String)
createConstructor {
constructor("prop" of String::class).thiz("prop"){}
} //constructor(prop: kotlin.String) : this(prop)
createConstructor {
constructor("prop" of String::class).zuper("prop"){}
} //constructor(prop: kotlin.String) : super(prop)
}
before V0.2, the toPrimary() is not checked for thizz and zuper, meaning it will fail, once it is added to the class.
Adding Stand-alone constructors to the class
you can add those to the class on the following way:
val constr1 = buildConstructor {
primary.constructor()
}
file("", "HelloWorld") {
clazz("One") {
// will always pass the constructor like it is created
// this means private is ignored
private.accept(constr1)
}
clazz("Two") {
// will be dropped in V0.2, due to "strange" working
public.constructor(constr1) // will merge modifiers
}
clazz("Three"){
accept(constr1.buildUpon {
addModifier(KModifier.PUBLIC)
})
}
}
in V0.2, the code of public constructor will be replaced with:
constr1.attach{
addModifiers(KModifier.PUBLIC)
}
Then you can create the function constructor yourself, or give it a different implementation that makes sense to you.
Interoperability
ConstructorSpec is interoperable with KotlinPoet
Creating ConstructorSpec
allowed at the moment
val func = FunSpec.constructorBuilder().addParameter(
ParameterSpec.builder("hi", String::class).build()
).build()
val secondaryConstructor = func.toConstructor()
val primaryConstructor = func.toPrimaryConstructor(
("hi" valOf String::class).toPropertySpec()
)
allowed in V0.2
val option1 = func.toPrimaryConstructor(
"one" of String::class, "two" valOf String::class
)
val option2 = func.toPrimaryConstructor(
"hi" to Variable.Mutability.MUTABLE, //where you import MUTABLE, of course ;-)
"two" to Mutability.NONE
)
Using ConstructorSpec
val const = buildConstructor {
private.primary.constructor(
"arg1" valOf String::class,
"arg2" varOf Int::class
)
}
TypeSpec.classBuilder("Clazz")
.addConstructor(const)
.build()
//class Clazz(val arg1: String, var arg2 : Int)
Getting KotlinPoetTypes
As defined in the intro, the types are already from KotlinPoet:
val const = buildConstructor {
private.constructor(
"arg1" valOf String::class,
"arg2" varOf Int::class
){}
}
const.funSpec // FunSpec: private constructor(arg1: kotlin.String, arg2: kotlin.Int)
const.toPrimary().properties
// Properties: [val arg1: kotlin.String = arg1\n, var arg2: kotlin.Int = arg2\n]
In 0.2, toPrimary
is no longer needed: a field allProperties is added, where all the properties are visible.
Last updated
Was this helpful?