Spring R2DBC:如何替换已弃用的 DatabaseClient.as(…) 并处理 jsonb 字段的自定义 types/converters

Spring R2DBC: How to replace deprecated DatabaseClient.as(…) and handle custom types/converters for jsonb field

我在迁移到 Spring Boot 2.4 后遇到对象映射问题。到目前为止,我使用的是 Spring Boot 2.3(带有 Kotlin)。

对于示例数据库查询

    override fun findMyEntities(searchParams: SearchParams): Flux<MyEntity> =
        databaseClient
            .sql("SELECT *  FROM my_entities ........................... OFFSET :offset LIMIT :limit")
            .bind("searchPhrase", searchParams.searchPhrase)
            .bind("limit", searchParams.pageSize)
            .bind("offset", searchParams.offset)
            .map(::mapRow)
            .all()

    private fun mapRow(row: Row) = MyEntity(
        id = row.get("id", UUID::class.java)!!,
        name = row.get("name", String::class.java)!!,
        description = row.get("description", String::class.java)!!,
        creation = row.get("creation", UserActionMetadata::class.java)!!,
    )

我遇到错误:

Suppressed: java.lang.IllegalArgumentException: Cannot decode value of type com.mypackage.model.UserActionMetadata
        at io.r2dbc.postgresql.codec.DefaultCodecs.decode(DefaultCodecs.java:153)
        at io.r2dbc.postgresql.PostgresqlRow.decode(PostgresqlRow.java:90)
        at io.r2dbc.postgresql.PostgresqlRow.get(PostgresqlRow.java:77)
        at com.mypackage.repository.MyRepotistory.mapRow(MyRepotistory.kt:59)

以上版本升级前的功能是这样的:

.execute("SELECT * FROM ...")
.`as`(MyEntity::class.java)
.fetch()
.all()

发生错误的地方,数据库中的创建字段是JSONB类型。为此,我有自定义读写转换器(在我的配置 class 中扩展了 AbstractR2dbcConfiguration)。

import org.springframework.data.convert.ReadingConverter
import org.springframework.data.convert.WritingConverter

@Configuration
class DatabaseConfig(private val r2dbcProperties: R2dbcProperties, private val objectMapper: ObjectMapper) :
    AbstractR2dbcConfiguration() {

    @WritingConverter
    inner class UserActionMetadataToJsonConverter : Converter<UserActionMetadata, Json> {
        override fun convert(source: UserActionMetadata): Json {
            return Json.of(objectMapper.writeValueAsString(source))
        }
    }

    @ReadingConverter
    inner class JsonToUserActionMetadataConverter : Converter<Json, UserActionMetadata> {
        override fun convert(source: Json): UserActionMetadata {
            return objectMapper.readValue(source.asString())
        }
    }

知道如何成功迁移到 Spring Boot 2.4 吗?

我看到了建议 to use R2dbcEntityTemplate, but my queries are too complex, and code will be too bloated. There is also an issue https://github.com/spring-projects/spring-framework/issues/26021。我希望有一些解决方法。

以下代码将数据转换为实体:

import org.springframework.r2dbc.core.DatabaseClient
import org.springframework.data.r2dbc.convert.MappingR2dbcConverter

class MyRepository(
    private val databaseClient: DatabaseClient,
    private val converter: MappingR2dbcConverter
) {
   fun fetchMyEntity() = databaseClient
       .sql("...")
       .map { row, metadata -> converter.read(MyEntity::class.java, row, metadata) }
       .all()
}