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.
A query is intended to fetch the value of a non-nullable column.
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.
Product.id->val id: String, column nameidProduct.provider->val provider: String, column nameprovider
abstract suspend fun getProviderById(@Id id: String): String?
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.
./gradlew clean test- Kotest
StringSpectest named"'::getProviderOrFallback' returns supplied fallback value when record not present for 'id'" {}fails - See logs for details (values captured in logger and Kotest matcher output)