greyfox
greyfox

Reputation: 6606

Spring NamedParameterJdbcTemplate Cannot Insert NULL using Kotlin

I am using Kotlin with Spring Boot 2. I am just doing a simple insert with a field that may, or may not be null. However in Kotlin this doesn't appear to be possible using MapSqlParameterSource because the .addValue methods do not accept null or nullable types. This is rather unusual because insert NULL can be a valid use case. This was very straight forward and easy with Java and Spring Boot in the past. Is there a way to get around this, I really don't want to jump through hoops to do something that is simple and straight forward.

@Transactional
fun saveSubmittedAnswer(answer: AnswerSubmissionRequest) {

    val query = """INSERT INTO dab.SubmittedAnswer (Id, QuestionId, Answer, SurveyId, ParentQuestionId, TimeTaken
        | VALUES (:id, :questionId, :answer, :surveyId, :parentQuestionId, :timeTaken)
    """.trimMargin()

    answer.answers.forEach { ans ->
        val params: MapSqlParameterSource = MapSqlParameterSource()
                .addValue("id", UUID.randomUUID())
                .addValue("questionId", ans.questionId)
                .addValue("answer", ans.answer)
                .addValue("surveyId", answer.surveyId)
                //.addValue("parentQuestionId", ans.parentId)
                .addValue("timeTaken", ans.timeTaken)

        this.jdbcTemplate.update(query, params)
    }
}

All the methods require a non nullable type.

enter image description here

Upvotes: 4

Views: 2799

Answers (1)

Todd
Todd

Reputation: 31710

The reason MapSqlParameterSource exists is because Java provides no elegant way to create maps of things. Since we can use mapOf() in Kotlin, we probably don't need MapSqlParameterSource at all.

If it were me, I would prefer to just use mapOf() and avoid MapSqlParameterSource entirely:

val params = mapOf(
    "id" to UUID.randomUUID(),
    "questionId" to ans.questionId,
    "answer" to ans.answer,
    "surveyId" to answer.surveyId,
    "parentQuestionId" to ans.parentId,
    "timeTaken" to ans.timeTaken
)
jdbcTemplate.update(query, params)

However, I agree that this seems like an oversight in the API. It was probably introduced when the nullability annotations were put in to make life easier for Kotlin users.

This seemed to compile for me, but I only tried it in the IDE, and didn't run it:

MapSqlParameterSource()
   .addValue("notNullable", myObject.notNulableValue)
   .addValues(mapOf("nullable" to myObject.nullableValue))

This works because the addValues function takes a Map<String, ?> (which, interestingly, is @Nullable).

I'm guessing this is a bug, inadvertently introduced in this commit. But again, we have mapOf(), and probably don't need this.

Upvotes: 3

Related Questions