1
votes

existing spring's JdbcTemplate has signature:

public <T> List<T> query(String sql, RowMapper<T> rowMapper)

and i can call it with a lambda that implements the interface:

jdbcTemplate.query("select ...", { rs, _ -> 5 })

but when i declare the same function in kotlin:

fun <T> query(sql: String, rowMapper: RowMapper<T>): List<T> = TODO()

and try to call it the same way:

query("select ...", { rs, _ -> 5 })

i get a compilation error

Type inference failed: fun query ( sql: String, rowMapper: RowMapper ) : List cannot be applied to ( String, (???, ???) → Int )

i have to write

query("select ...", RowMapper{ rs, _ -> 5 })

why? is there any way to just provide lambda?

1

1 Answers

0
votes

Background

In Java, a lambda expression can be passed in a context where a functional interface is expected. Example Java code:

jdbcTemplate.query("select ...", (rs, _) -> 5);

In Kotlin, there is no implicit conversion from lambda expressions to interfaces. Rather than functional interfaces, Kotlin provides native function types with the syntax (Params) -> ReturnType. To make interoperability with Java easier, there is however a conversion from Kotlin lambda expression to Java functional interfaces, by adding the interface name:

query("select ...", RowMapper { rs, _ -> 5 })

Solution

It's not possible to pass a lambda directly -- however you could write an extension function that takes a function type and forwards it to query():

fun JdbcTemplate.query(sql: String, mapper: (A, B) -> Int) =
    query(sql, RowMapper { a, b -> mapper(a, b) })

This can then be called in the way you desire. Note that you don't need the parentheses around all arguments, due to the special syntax Kotlin allows for trailing lambda expressions:

jdbc.query("select ...") { rs, _ -> 5 }

See also here, where I explained this behavior in detail.