Skip to content

micronaut-data-r2dbc|Kotlin Coroutines: Non-null string "NullValue[]" returned rather than null #3619

@stevenlmcgraw

Description

@stevenlmcgraw

Expected Behavior

APP SETUP

A Kotlin application uses micronaut-data-r2dbc with a Postgresql database.

The application uses Netty/Reactor and Kotlin coroutines (suspend functions).

An entity is defined using @MappedEntity/@MappedProperty/etcetera io.micronaut.data.annotation.* annotations.

A @R2dbcRepository abstract class is defined for the entity that extends io.micronaut.data.repository.kotlin.CoroutineCrudRepository.

EXPECTATION

A query is intended to fetch the value of an individual entity field representing a non-nullable column if the record exists.

If a record exists for the given identifier then the value of the column is returned as expected from the repository method.

If a record does not exist for the given identifier then null is returned from the repository method.

Actual Behaviour

OBSERVED BEHAVIOR

Rather than returning null when a record does not exist for the given identifier, the non-null string "NullValue[]" is returned by the repository method.

This subverts any null checks like the Kotlin elvis operator (?:), leading to unexpected behavior in the application.

The NullValue record class was introduced in this commit.

Older versions of micronaut-data-r2dbc return null as expected in this scenario.

Steps To Reproduce

Example project can be found here. Our production applications that are prevented from upgrading to the most current micronaut-platform use r2dbc-pool and also use the R2DBC workaround for avoiding thread colocation - I have included this configuration in the example to get as close to our actual apps as possible while still keeping the reproducer small.

Example failed build.

^^^logs in this build demonstrate the behavior; search for "ARGS" to see log message from application code. The io.kotest.assertions.AssertionFailedError can also be searched to see the non-null "NullValue[]" string as well.

Otherwise, to run locally:

  • JDK 17
  • Needs Docker environment for Testcontainers Postgresql container to run
  • ./gradlew clean test

Environment Information

Operating system:

  • MacOS (local runs)
  • Ubuntu (GitHub runner)

JDK 17

Kotlin -> 2.1.21
KotlinX -> 1.10.2

Micronaut Platform -> 4.10.2

Looks to have come about when NullValue record class was introduced in this commit

Example Application

https://github.com/stevenlmcgraw/coroutine-r2dbc-null-value

Version

micronaut-platform:4.10.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions