Lambda DSL

In Spring you will come across following syntax :

 GET("/hello") { _ ->
            ok().body(just("Hello World!"), String::class.java)
 }

or

 beans {
                bean("webHandler"){
                    RouterFunctions.toWebHandler(router) //<- change our routing intpo spring component
                }
       }

This syntax is built with standard kotlin mechanisms. In this part we are going to better understand how.

FILE : IntroSpring1.kt

Lambda as the last parameter

In Kotlin when lambda is the last parameter you can use special syntax where lambda actually will be placed outside parenthesis. Let me show you :

fun singleRoute(path:String, request:String, handler : (Request) -> Response):String {
    Displayer.section("handling call on path",path)
    return handler(request)
}

We have a definition of a single route handler. It has 3 parameters where the last one has lambda type : (Request) -> Response

You can call this method as usual :

singleRoute("/hello","requestExample1", {request -> "response for $request"})

but now let's use alternative syntax where you can move lambda outside parantheses

val r2=singleRoute("/hello","requestExample1"){request ->"esponse for $request"}

this is still valid code! And we can make it look like "more native" if we format brackets like in for example while constructions

val r2=singleRoute("/hello","requestExample1"){request ->
    "esponse for $request"
}

Implicit receiver

Well, not exactly like while constructions because it is still lambda with parameter and this arrow after it...

As first step we could use implicit function parameter, so arrow will disappear but we have to write it everywhere.

 val buildingResult=buildRouterWitIt {(builder) -> 
        it.route("/hello",{r -> "response for $r"})
        it.route("/info",{r -> "response for $r"})
  }

//can become this

 val buildingResult=buildRouterWitIt {
        it.route("/hello",{r -> "response for $r"})
        it.route("/info",{r -> "response for $r"})
  }

but what if we could write this code like in the following example :

 val dslResult= buildRouter {
        route("/index.html",{r -> "response for $r"})
        route("/register",{"response for $it"})
    }

Of course I've posted this example because you actually can :) There is a special form of an argument declaration where you are actually add extension method to the argument in method scope : YourClass.(A) -> B

fun buildRouter(buildLogic : CustomRoutingDsl.() -> Unit):Routes{
    val dsl = CustomRoutingDsl()
//    buildLogic(dsl)
    dsl.buildLogic() 
    return dsl.toRoutes()
}

Exercises

FILE : IntroSpring1Exercises

You will have to implement following DSL :

val news=news {
            article {
                titled("My first article")
                withContent("First article content")
            }

            article {
                titled("Learning Kotlin DSL")
                withContent("To create Dsl...")
            }
        }

There are actually two DSLs : one for building whole news and the second one for particular article

class NewsBuildingDsl{

fun article(builder: ArticleDsl.() -> Unit){
          TODO("provide your DSL here")
    }

}

results matching ""

    No results matching ""