Tuesday, December 26, 2017

Kotlin - Try type for functional exception handling

Scala has a Try type to functionally handle exceptions. I could get my head around using this type using the excellent Neophyte's guide to Scala by Daniel Westheide. This post will replicate this type using Kotlin.


Background


Consider a simple function which takes two String, converts them to integer and then divides them(sample based on scaladoc of Try) :

fun divide(dividend: String, divisor: String): Int {
     val num = dividend.toInt()
     val denom = divisor.toInt()
     return num / denom
 }

It is the callers responsibility to ensure that any exception that is propagated from this implementation is handled appropriately using the exception handling mechanism of Java/Kotlin:

try {
    divide("5t", "4")
} catch (e: ArithmeticException) {
    println("Got an exception $e")
} catch (e: NumberFormatException) {
    println("Got an exception $e")
}

My objective with the "Try" code will be to transform the "divide" to something which looks like this:

fun divideFn(dividend: String, divisor: String): Try<Int> {
    val num = Try { dividend.toInt() }
    val denom = Try { divisor.toInt() }
    return num.flatMap { n -> denom.map { d -> n / d } }
}

A caller of this variant of "divide" function will not have an exception to handle through a try/catch block, instead, it will get back the exception as a value which it can introspect and act on as needed.

val result = divideFn("5t", "4")
when(result) {
    is Success -> println("Got ${result.value}")
    is Failure -> println("An error : ${result.e}") 
}

Kotlin implementation

The "Try" type has two implementations corresponding to the "Success" path or a "Failure" path and implemented as a sealed class the following way:

sealed class Try<out T> {}

data class Success<out T>(val value: T) : Try<T>() {}

data class Failure<out T>(val e: Throwable) : Try<T>() {}

The "Success" type wraps around the successful result of an execution and "Failure" type wraps any exception thrown from the execution.

So now, to add some meat to these, my first test is to return one of these types based on a clean and exceptional implementation, along these lines:

val trySuccessResult: Try<Int> = Try {
    4 / 2
}
assertThat(trySuccessResult.isSuccess()).isTrue()


val tryFailureResult: Try<Int> = Try {
    1 / 0
}
assertThat(tryFailureResult.isFailure()).isTrue()

This can be achieved through a "companion object" in Kotlin, similar to static methods in Java, it returns either a Success type or a Failure type based on the execution of the lambda expression:

sealed class Try<out T> {
    ...    
    companion object {
        operator fun <T> invoke(body: () -> T): Try<T> {
            return try {
                Success(body())
            } catch (e: Exception) {
                Failure(e)
            }
        }
    }
    ...
}

Now that a caller has a "Try" type, they can check whether it is a "Success" type or a "Failure" type using the "when" expression like before, or using "isSuccess" and "isFailure" methods which are delegated to the sub-types like this:

sealed class Try<out T> {
    abstract fun isSuccess(): Boolean
    abstract fun isFailure(): Boolean
}

data class Success<out T>(val value: T) : Try<T>() {
    override fun isSuccess(): Boolean = true
    override fun isFailure(): Boolean = false
}

data class Failure<out T>(val e: Throwable) : Try<T>() {
    override fun isSuccess(): Boolean = false
    override fun isFailure(): Boolean = true
}

in case of Failure a default can be returned to the caller, something like this in a test:

val t1 = Try { 1 }

assertThat(t1.getOrElse(100)).isEqualTo(1)

val t2 = Try { "something" }
        .map { it.toInt() }
        .getOrElse(100)

assertThat(t2).isEqualTo(100)

again implemented by delegating to the subtypes:
sealed class Try<out T> {
  abstract fun get(): T
  abstract fun getOrElse(default: @UnsafeVariance T): T
  abstract fun orElse(default: Try<@UnsafeVariance T>): Try<T>
}

data class Success<out T>(val value: T) : Try<T>() {
    override fun getOrElse(default: @UnsafeVariance T): T = value
    override fun get() = value
    override fun orElse(default: Try<@UnsafeVariance T>): Try<T> = this
}

data class Failure<out T>(val e: Throwable) : Try<T>() {
    override fun getOrElse(default: @UnsafeVariance T): T = default
    override fun get(): T = throw e
    override fun orElse(default: Try<@UnsafeVariance T>): Try<T> = default
}


The biggest advantage of returning a "Try" type, however, is in chaining further operations on the type.

Chaining with map and flatMap

"map" operation is passed a lambda expression to transform the value in some form - possibly even to a different type:

val t1 = Try { 2 }

val t2 = t1.map({ it * 2 }).map { it.toString()}

assertThat(t2).isEqualTo(Success("4"))

Here a number is being doubled and then converted to a string. If the initial Try were a "Failure" then the final value will simply return the "Failure" along the lines of this test:

val t1 = Try {
    2 / 0
}

val t2 = t1.map({ it * 2 }).map { it * it }

assertThat(t2).isEqualTo(Failure<Int>((t2 as Failure).e))


Implementing "map" is fairly straightforward:

sealed class Try<out T> {
    fun <U> map(f: (T) -> U): Try<U> {
        return when (this) {
            is Success -> Try {
                f(this.value)
            }
            is Failure -> this as Failure<U>
        }
    }
}


flatmap, on the other hand, takes in a lambda expression which returns another "Try" type and flattens the result back into a "Try" type, along the lines of this test:

val t1 = Try { 2 }

val t2 = t1
        .flatMap { i -> Try { i * 2 } }
        .flatMap { i -> Try { i.toString() } }

assertThat(t2).isEqualTo(Success("4"))

Implementing this is simple too, along the following lines:

sealed class Try<out T> {
    fun <U> flatMap(f: (T) -> Try<U>): Try<U> {
        return when (this) {
            is Success -> f(this.value)
            is Failure -> this as Failure<U>
        }
    }
}

The "map" and "flatMap" methods are the power tools of this type, allowing chaining of complex operations together focusing on the happy path.


Conclusion

Try is a powerful type allowing a functional handling of exceptions in the code. I have a strawman implementation using Kotlin available in my github repo here - https://github.com/bijukunjummen/kfun

Monday, December 18, 2017

Kotlin - tail recursion optimization

Kotlin compiler optimizes tail recursive calls with a few catches. Consider a rank function to search for the index of an element in a sorted array, implemented the following way using tail recursion and a test for it:

fun rank(k: Int, arr: Array<Int>): Int {
    tailrec fun rank(low: Int, high: Int): Int {
        if (low > high) {
            return -1
        }
        val mid = (low + high) / 2

        return when {
            (k < arr[mid]) -> rank(low, mid)
            (k > arr[mid]) -> rank(mid + 1, high)
            else -> mid
        }
    }

    return rank(0, arr.size - 1)
}

@Test
fun rankTest() {
    val array = arrayOf(2, 4, 6, 9, 10, 11, 16, 17, 19, 20, 25)
    assertEquals(-1, rank(100, array))
    assertEquals(0, rank(2, array))
    assertEquals(2, rank(6, array))
    assertEquals(5, rank(11, array))
    assertEquals(10, rank(25, array))
}

IntelliJ provides an awesome feature to show the bytecode of any Kotlin code, along the lines of the following screenshot:



A Kotlin equivalent of the type of bytecode that the Kotlin compiler generates is the following:

fun rankIter(k: Int, arr: Array<Int>): Int {
    fun rankIter(low: Int, high: Int): Int {
        var lo = low
        var hi = high
        while (lo <= hi) {
            val mid = (lo + hi)/2

            if (k < arr[mid]) {
                hi = mid
            } else if (k > arr[mid]){
                lo = mid + 1
            } else {
                return mid
            }

        }
        return -1
    }

    return rankIter(0, arr.size - 1)
}

the tail calls have been translated to a simple loop.


There are a few catches that I could see though:
1. The compiler has to be explicitly told which calls are tail-recursive using the "tailrec" modifier
2. Adding tailrec modifier to a non-tail-recursive function does not generate compiler errors, though a warning does appear during compilation step

Sunday, December 10, 2017

Spring Webflux - Writing Filters

Spring Webflux is the new reactive web framework available as part of Spring 5+.  The way filters were written in a traditional Spring MVC based application(Servlet Filter, HandlerInterceptor) is very different from the way a filter is written in a Spring Webflux based application and this post will briefly go over the WebFlux approach to Filters.

Approach 1 - WebFilter

The first approach using WebFilter affects all endpoints broadly and covers Webflux endpoints written in a functional style as well the endpoints that are written using an annotation style. A WebFilter in Kotlin look like this:

    @Bean
    fun sampleWebFilter(): WebFilter {
        return WebFilter { e: ServerWebExchange, c: WebFilterChain ->
            val l: MutableList<String> = e.getAttributeOrDefault(KEY, mutableListOf())
            l.add("From WebFilter")
            e.attributes.put(KEY, l)
            c.filter(e)
        }
    }

The WebFilter adds a request attribute with the value being a collection where the filter is just putting in a message that it has intercepted the request.

Approach 2 - HandlerFilterFunction


The second approach is more focused and covers only endpoints written using functional style. Here specific RouterFunctions can be hooked up with a filter, along these lines:

Consider a Spring Webflux endpoint defined the following way:

@Bean
fun route(): RouterFunction<*> = router {
    GET("/react/hello", { r ->
        ok().body(fromObject(
                Greeting("${r.attribute(KEY).orElse("[Fallback]: ")}: Hello")
        ))
    POST("/another/endpoint", TODO())
        
    PUT("/another/endpoint", TODO())
})
        
}

A HandlerFilterFunction which intercepts these API's alone can be added in a highly focused way along these lines:

fun route(): RouterFunction<*> = router {
    GET("/react/hello", { r ->
        ok().body(fromObject(
                Greeting("${r.attribute(KEY).orElse("[Fallback]: ")}: Hello")
        ))
    })
    
    POST("/another/endpoint", TODO())
    
    PUT("/another/endpoint", TODO())
    
}.filter({ r: ServerRequest, n: HandlerFunction<ServerResponse> ->
    val greetings: MutableList<String> = r.attribute(KEY)
            .map { v ->
                v as MutableList<String>
            }.orElse(mutableListOf())

    greetings.add("From HandlerFilterFunction")

    r.attributes().put(KEY, greetings)
    n.handle(r)
})

Note that there is no need to be explicit about the types in Kotlin, I have added it just to be clear about the types in some of the lambda expressions


Conclusion

The WebFilter approach and the HandlerFilterFunction are very different from the Spring WebMVC based approach of writing filters using Servlet Specs or using HandlerInterceptors and this post summarizes the new approaches - I have samples available in my git repo which goes over these in more detail.

Friday, December 1, 2017

Annotated controllers - Spring Web/Webflux and Testing

Spring Webflux and Spring Web are two entirely different web stacks. Spring Webflux, however, continues to support an annotation-based programming model

An endpoint defined using these two stacks may look similar but the way to test such an endpoint is fairly different and a user writing such an endpoint has to be aware of which stack is active and formulate the test accordingly.

Sample Endpoint

Consider a sample annotation based endpoint:


import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


data class Greeting(val message: String)

@RestController
@RequestMapping("/web")
class GreetingController {
    
    @PostMapping("/greet")
    fun handleGreeting(@RequestBody greeting: Greeting): Greeting {
        return Greeting("Thanks: ${greeting.message}")
    }
    
}


Testing with Spring Web

If Spring Boot 2 starters were used to create this application with Spring Web as the starter, specified using a Gradle build file the following way:

compile('org.springframework.boot:spring-boot-starter-web')

then the test of such an endpoint would be using a Mock web runtime, referred to as Mock MVC:

import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.test.context.junit4.SpringRunner
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content


@RunWith(SpringRunner::class)
@WebMvcTest(GreetingController::class)
class GreetingControllerMockMvcTest {

    @Autowired
    lateinit var mockMvc: MockMvc

    @Test
    fun testHandleGreetings() {
        mockMvc
                .perform(
                        post("/web/greet")
                                .content(""" 
                                |{
                                |"message": "Hello Web"
                                |}
                            """.trimMargin())
                ).andExpect(content().json("""
                    |{
                    |"message": "Thanks: Hello Web"
                    |}
                """.trimMargin()))
    }
}


Testing with Spring Web-Flux

If on the other hand Spring-Webflux starters were pulled in, say with the following Gradle dependency:

compile('org.springframework.boot:spring-boot-starter-webflux')

then the test of this endpoint would be using the excellent WebTestClient class, along these lines:

import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest
import org.springframework.http.HttpHeaders
import org.springframework.test.context.junit4.SpringRunner
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.web.reactive.function.BodyInserters


@RunWith(SpringRunner::class)
@WebFluxTest(GreetingController::class)
class GreetingControllerTest {

    @Autowired
    lateinit var webTestClient: WebTestClient

    @Test
    fun testHandleGreetings() {
        webTestClient.post()
                .uri("/web/greet")
                .header(HttpHeaders.CONTENT_TYPE, "application/json")
                .body(BodyInserters
                        .fromObject(""" 
                                |{
                                |   "message": "Hello Web"
                                |}
                            """.trimMargin()))
                .exchange()
                .expectStatus().isOk
                .expectBody()
                .json("""
                    |{
                    |   "message": "Thanks: Hello Web"
                    |}
                """.trimMargin())
    }
}


Conclusion

It is easy to assume that since the programming model looks very similar using Spring Web and Spring Webflux stacks, that the tests for such a legacy test using Spring Web would continue over to Spring Webflux, this is however not true, as a developer we have to be mindful of the underlying stack that comes into play and formulate the test accordingly. I hope this post clarifies how such a test should be crafted.