Zum Hauptinhalt springen

Kotlin DSL for webforJ

Preview

Write it in Kotlin. Keep your Java.

The Kotlin DSL builds webforJ UIs with concise, type-safe syntax. Instead of imperative calls, you write declarative code that reads like a description of the screen, and it compiles in the same project as your Java.

The class you know, as a builder

  • Buttonbecomesbutton()
  • TextFieldbecomestextField()
  • FlexLayoutbecomesflexLayout()
  • Breakbecomes`break`()

Buttons, fields, layouts, dialogs, drawers, lists and HTML elements each have one, named after the class in camelCase.

Same screen, two languages

Read the Java. Then read the Kotlin.

Both sides build the same components with the same webforJ classes. The Kotlin side drops the setters and add() calls: components nest inside each other and configuration happens in blocks.

JavaHelloView.java

@Route("/hello")
public class HelloView extends Composite<FlexLayout> {
private final FlexLayout self = getBoundComponent();
private TextField name = new TextField("What is your name?");
private Button greet = new Button("Say hello");

public HelloView() {
greet.setTheme(ButtonTheme.PRIMARY)
.addClickListener(e ->
Toast.show("Welcome, " + name.getValue() + "!",
Theme.SUCCESS));
self.add(name, greet);
}
}

KotlinHelloView.kt

@Route("hello")
class HelloView : Composite<FlexLayout>() {
private val self = boundComponent

init {
self.apply {
val name = textField("What is your name?")
button("Say hello") {
theme = ButtonTheme.PRIMARY
onClick {
Toast.show("Welcome, ${name.text}!", Theme.SUCCESS)
}
}
}
}
}

What the DSL gives you

Builders, blocks and lambdas

Each builder function creates a component, adds it to its parent container and runs a configuration block. The rest of the DSL follows from that.

Configuration blocks

The block receives the component as this, so you set its properties and call its methods directly.

textField("Email") {
placeholder = "you@example.com" // this.placeholder
required = true // this.required
onModify { validate() } // this.onModify(...)
}
  • Builders named after components

    Each component has a function named after its class in camelCase. Most take the options you set most often, such as a label or a placeholder, before the block.

  • Nested blocks

    Components that hold children accept nested DSL calls inside their block, so the code has the shape of the screen.

  • Events as lambdas

    Listeners use on prefixed methods that take a lambda, such as onClick and onModify.

  • Scope safety

    Children only go into components that support them. Adding to an outer scope by accident does not compile.

  • Styles and class names

    The styles property gives bracket access to CSS properties, the same as setStyle() in Java. Class names are added with +=.

  • Next to your Java code

    Kotlin compiles to JVM bytecode. Use Kotlin composites from Java classes and nest Java components in DSL blocks with add().

Extending the DSL

Your own components, as builders too

Custom components and third-party libraries join the DSL through an extension function on HasComponents. The init helper adds the component to its parent, runs the block and returns it. Composites you build with the DSL get a function the same way.

StarRating.kt
fun @WebforjDsl HasComponents.starRating(
block: @WebforjDsl StarRating.() -> Unit = {}
): StarRating {
return init(StarRating(), block)
}
Extending the DSL in the docs

How to start

Add Kotlin to a Maven project

The Kotlin DSL is available from webforJ 25.12. A project that already builds with Maven needs a dependency and a plugin.

  1. 1

    Add the dependencies

    Add the webforJ Kotlin DSL module and the Kotlin standard library to your pom.xml.

  2. 2

    Add the Kotlin Maven plugin

    It compiles your Kotlin and Java sources in one build. No separate Kotlin installation is needed.

  3. 3

    Put Kotlin next to your Java

    Kotlin files can go in their own source folder or in the same folder as your Java files.

  4. 4

    Write a view and compile

    Write a view with the builders. Maven then compiles your Kotlin alongside your Java.