Writing a DSL

A Kotlin DSL is really just a type-safe builder for a data structure. To extend the Spring DSL framework by adding your own DSL, first define your main data class. This class must implement the SpringDsl interface. It should be annotated with @SpringDslMarker.

@SpringDslMarker
class CustomDsl : SpringDsl 

The simplest way to add a property to the DSL is by exposing a mutable property.

@SpringDslMarker
class CustomDsl : SpringDsl {
    @SpringDslMarker
    var aProperty: String? = null
}

More complex behavior can be driven by functions. These functions should be annotated with @SpringDslMarker. Properties not meant to be accessed by the DSL should not be annotated and should have internal visibility.

@SpringDslMarker
class CustomDsl : SpringDsl {
    internal var implementation: MyInterface? = null

    @SpringDslMarker
    fun impl1() {
        implementation = Impl1()
    }

    @SpringDslMarker
    fun impl2() {
        implementation = Impl2()
    }
}

Nested DSLs

You can also nest DSL objects. Nested DSLs do not need to implement SpringDsl but should be annotated with @SpringDslMarker.

@SpringDslMarker
class CustomDsl : SpringDsl {
    internal val nestedDsl: NestedDsl = NestedDsl()

    @SpringDslMarker
    fun nested(builder: NestedDsl.() -> Unit) { 
        nestedDsl.apply(builder)
    }
}

Entry point

In order to make your DSL accessible from the root-level Spring DSL, add an extension method as an entry point which calls the register method on SpringDslContainer.

fun SpringDslContainer.customDsl(builder: CustomDsl.() -> Unit) {
    register(CustomDsl().apply(builder))
}

Next, you will use this DSL to drive behavior in your initializer.