Kotlin, Callable and ExecutorService

I’ve recently written about using Callable in Groovy, but how does it look like in kotlin?Callable instance as separete class First, let’s create class which implements Callable interface:class MyJob : Callable<Int> { override fun call() = 42}…

I’ve recently written about using Callable in Groovy, but how does it look like in kotlin?

Callable instance as separete class

First, let’s create class which implements Callable interface:

class MyJob : Callable {
    override fun call() = 42
}

Now we could pass instance of this class to executorService:

fun callableAsClassInstance() = executorService.submit(MyJob()).get()

When we run it, as we expect, it returns 42. (Tests are written in groovy, not in kotlin).

def 'should submit callable as class instance from kotlin'() {
    expect:
        callableExample.callableAsClassInstance() == 42
}

Casting to Callable

If we create map with string “call” to closure or just closure and try to cast to Callable, we always obtain CastClassException:

fun callableAsMap() = executorService.submit(mapOf("call" to { 42 }) as Callable).get()

fun callableAsClosure() = executorService.submit({ 42 } as Callable).get()
def 'should submit callable as closure from kotlin'() {
    when:
        callableExample.callableAsClosure() == 42
    then:
        thrown(ClassCastException)
}

def 'should submit callable as map from kotlin'() {
    when:
        callableExample.callableAsMap() == 42
    then:
        thrown(ClassCastException)
}

It does not work as in groovy…

Pass instance method

So maybe passing an instance method which produces value will work?

private fun callMe() = 42

fun callableAsPassedFunction(): Int? {
    return executorService.submit(::callMe).get()
}

It does not even compile. Why? It moans that there is no submit method which could be called with such argument…

But, what interesting, if we create a value to which we assign closure and pass it to submit method then everything is ok and get returns 42.

private val callMe = { 42 }

fun callableAsPassedLocalFunction(): Int? {
    return executorService.submit(callMe).get()
}

Inline implementation

Of course, there is also an option to create Callable inline:

fun callableAsInlineImplementation() = executorService.submit(Callable { 42 }).get()

And this is IHMO the best and the most comfortable way to create Callable in kotlin, because its syntax is much nicer than in java or groovy.

Source code is available here.

You May Also Like

New HTTP Logger Grails plugin

I've wrote a new Grails plugin - httplogger. It logs:

  • request information (url, headers, cookies, method, body),
  • grails dispatch information (controller, action, parameters),
  • response information (elapsed time and body).

It is mostly useful for logging your REST traffic. Full HTTP web pages can be huge to log and generally waste your space. I suggest to map all of your REST controllers with the same path in UrlMappings, e.g. /rest/ and configure this plugin with this path.

Here is some simple output just to give you a taste of it.

17:16:00,331 INFO  filters.LogRawRequestInfoFilter  - 17:16:00,340 INFO  filters.LogRawRequestInfoFilter  - 17:16:00,342 INFO  filters.LogGrailsUrlsInfoFilter  - 17:16:00,731 INFO  filters.LogOutputResponseFilter  - >> #1 returned 200, took 405 ms.
17:16:00,745 INFO filters.LogOutputResponseFilter - >> #1 responded with '{count:0}'
17:18:55,799 INFO  filters.LogRawRequestInfoFilter  - 17:18:55,799 INFO  filters.LogRawRequestInfoFilter  - 17:18:55,800 INFO  filters.LogRawRequestInfoFilter  - 17:18:55,801 INFO  filters.LogOutputResponseFilter  - >> #2 returned 404, took 3 ms.
17:18:55,802 INFO filters.LogOutputResponseFilter - >> #2 responded with ''

Official plugin information can be found on Grails plugins website here: http://grails.org/plugins/httplogger or you can browse code on github: TouK/grails-httplogger.

Grails with Spock unit test + IntelliJ IDEA = No thread-bound request found

During my work with Grails project using Spock test in IntelliJ IDEA I've encountered this error:

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.codehaus.groovy.grails.plugins.web.api.CommonWebApi.currentRequestAttributes(CommonWebApi.java:205)
at org.codehaus.groovy.grails.plugins.web.api.CommonWebApi.getParams(CommonWebApi.java:65)
... // and few more lines of stacktrace ;)

It occurred when I tried to debug one of test from IDEA level. What is interesting, this error does not happen when I'm running all test using grails test-app for instance.

So what was the issue? With little of reading and tip from Tomek Kalkosiński (http://refaktor.blogspot.com/) it turned out that our test was missing @TestFor annotation and adding it solved all problems.

This annotation, according to Grails docs (link), indicates Spock what class is being tested and implicitly creates field with given type in test class. It is somehow strange as problematic test had explicitly and "manually" created field with proper controller type. Maybe there is a problem with mocking servlet requests?