
Compile-time plug-in rewriting builder calls into concise lambda-style DSL with no runtime dependency, enforcing required-argument order, supporting singular collection additions and set/opt naming.
Java builders, the way Kotliners like them
The builder pattern is very common in the Java world. However, using them in Kotlin usually leads to non-idiomatic code.
Config.builder().hostname("localhost").port(8080).build()Using this compiler plug-in, you get a much nicer syntax,
import com.serranofp.builder.lambda.build
build<Config, *> { // alas, the * is needed
hostname = "localhost"
port = 8080
}Apply the plug-in.
Regardless of your choice of build tool,
import com.serranofp.builder.lambda.build whenever you need to use a builder.
The plug-in injects a supporting library for that function,
but note this is a compile-only dependency. The plug-in rewrites the entire call
to a sequence of calls on the builder, with no additional runtime dependency.
Gradle. Add the corresponding Gradle plug-in to your plugins block in your Gradle file,
id("com.serranofp.builder.lambda") version "<current.release>"Kotlin Toolchain. Add the following blocks to your module.yaml,
dependencies:
- com.serranofp:builder-lambda-support-lib:<current.release>: compile-only
settings:
kotlin:
compilerPlugins:
- id: com.serranofp.builder.lambda
dependency: com.serranofp:builder-lambda-compiler-plugin:<current.release>[!WARNING] Unfortunately, compiler plug-ins do not see declarations generated by other plug-ins in the same module. In particular, if you use the Lombok plug-in to generate builders for Kotlin classes, you cannot use this plug-in to build those classes within the same module.
IDE support. You can get autocompletion and diagnostics right in IntelliJ if you allow compiler plug-ins from outside the Kotlin Team to run. To do so, go to Help > Edit Custom Properties..., and add the following line to the file that opens:
kotlin.k2.only.bundled.compiler.plugins.enabled=falseRestart your IDE, and enjoy.
Required arguments.
Arguments required for the initial call to build are turned into required
arguments. Those required arguments must be present, and must be given at
the very beginning of the block, before anything else is set.
The plug-in reports errors otherwise, ensuring that builder calls are correct.
Singular for collections. When the type of a property is a collection type, builders sometimes provide singular methods for more quickly adding a value. The plug-in is aware of this pattern, and exposes those as functions, instead of as setters.
// 'authors' is a List<String>
Book.builder().title("Wow!").author("me").author("you").build()build<Book, *> {
title = "Wow!"
author("me")
author("you")
}set/opt naming convention.
Some projects (like DJL) follow a slighly different
convention for their builders, with setXXX marking required arguments,
and optXXX marking optional ones.
The plug-in also supports that convention.
Java builders, the way Kotliners like them
The builder pattern is very common in the Java world. However, using them in Kotlin usually leads to non-idiomatic code.
Config.builder().hostname("localhost").port(8080).build()Using this compiler plug-in, you get a much nicer syntax,
import com.serranofp.builder.lambda.build
build<Config, *> { // alas, the * is needed
hostname = "localhost"
port = 8080
}Apply the plug-in.
Regardless of your choice of build tool,
import com.serranofp.builder.lambda.build whenever you need to use a builder.
The plug-in injects a supporting library for that function,
but note this is a compile-only dependency. The plug-in rewrites the entire call
to a sequence of calls on the builder, with no additional runtime dependency.
Gradle. Add the corresponding Gradle plug-in to your plugins block in your Gradle file,
id("com.serranofp.builder.lambda") version "<current.release>"Kotlin Toolchain. Add the following blocks to your module.yaml,
dependencies:
- com.serranofp:builder-lambda-support-lib:<current.release>: compile-only
settings:
kotlin:
compilerPlugins:
- id: com.serranofp.builder.lambda
dependency: com.serranofp:builder-lambda-compiler-plugin:<current.release>[!WARNING] Unfortunately, compiler plug-ins do not see declarations generated by other plug-ins in the same module. In particular, if you use the Lombok plug-in to generate builders for Kotlin classes, you cannot use this plug-in to build those classes within the same module.
IDE support. You can get autocompletion and diagnostics right in IntelliJ if you allow compiler plug-ins from outside the Kotlin Team to run. To do so, go to Help > Edit Custom Properties..., and add the following line to the file that opens:
kotlin.k2.only.bundled.compiler.plugins.enabled=falseRestart your IDE, and enjoy.
Required arguments.
Arguments required for the initial call to build are turned into required
arguments. Those required arguments must be present, and must be given at
the very beginning of the block, before anything else is set.
The plug-in reports errors otherwise, ensuring that builder calls are correct.
Singular for collections. When the type of a property is a collection type, builders sometimes provide singular methods for more quickly adding a value. The plug-in is aware of this pattern, and exposes those as functions, instead of as setters.
// 'authors' is a List<String>
Book.builder().title("Wow!").author("me").author("you").build()build<Book, *> {
title = "Wow!"
author("me")
author("you")
}set/opt naming convention.
Some projects (like DJL) follow a slighly different
convention for their builders, with setXXX marking required arguments,
and optXXX marking optional ones.
The plug-in also supports that convention.