kotlinspring-jdbcspring-kotlin

Why queryForObject Kotlin extension func returns nullable T? if it actually will throw EmptyResultDataAccessException?


Using Kotlin and Spring 5 for some simple project. I would like to get single record from database by id using queryForObject. My query is a 'simple select by id':

jdbc.queryForObject("select id, name from example where id = ?", id)
{ rs: ResultSet, _: Int -> NamedEnt(rs.getLong("id"), rs.getString("name") }

In JdbcOperationsExtensions.kt it is declared to return nullable type T?:

fun <T : Any> JdbcOperations.queryForObject(sql: String, vararg args: Any, function: (ResultSet, Int) -> T): T? =
    queryForObject(sql, RowMapper { resultSet, i -> function(resultSet, i) }, *args)

In practice when I pass not existing identifier, I face with:

org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0

Then I do not understand what is the point of returning nullable type? You either receive a single record or exception. Or I miss something?


Solution

  • JdbcOperationsExtensions.kt adds some extension functions to the org.springframework.jdbc.core.JdbcOperations interface (written in Java). If you look at the JavaDocs for queryForObject in that, it says:

    @return the single mapped object (may be {@code null} if the given
    {@link RowMapper} returned {@code} null)
    

    See here for full source code of the JdbcOperations Java class.

    So the Kotlin-written extension functions need to adhere to this and allow nulls to be returned, hence the nullable type.

    Except... as pointed out by @AlexeyRomanov, this particular overload of queryForObject takes in a lambda which returns T, so can't ever return null, so arguably this overload could return T, not T?. Maybe it's a bit inconsistent that this lambda in Kotlin can't return null, but the JavaDocs on the very similar overload in the Java class explicitly state that it (RowMapper) should be allowed to return null.

    Regardless of that point, some other overloads of queryForObject simply call to down to the Java-written overload, and because it's written in Java, it's possible that it could return a null. So for them it does seem to make sense for it to be a nullable return value. In which case arguably it's a nice bit of consistency that all the overloads do in fact return the nullable T.