微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Spring Data R2DBC 自定义转换不适用于 json 数组

如何解决Spring Data R2DBC 自定义转换不适用于 json 数组

我正在尝试使用 Spring Data R2DBC 的自定义转换来处理 json_array 字段。

我有一个由下面的 sql 创建的 MysqL 表。

create table prefecture
(
    id         bigint unsigned auto_increment,region_ids json       not null,created_at datetime   not null default current_timestamp,updated_at datetime   not null default current_timestamp on update current_timestamp,constraint prefecture_pk
        primary key (id)
);

--- initial data
INSERT INTO prefecture
VALUES (null,"1","TEST",json_array(1),Now(),Now());

然后,我定义了一个与该表相对应的实体

data class Prefecture(
    @Id
    val id: Int? = null,val regionIds: RegionIds,)

data class RegionIds(
    val list: List<Int>
)

根据这个doc,我发现需要注册一个对应源类型和目标类型的自定义转换器,所以我实现了一个转换器并如下注册

@Configuration
class R2dbcConfiguration {
    @Bean
    fun customConversions(): R2dbcCustomConversions {
        val converters: MutableList<Converter<*,*>?> = ArrayList()
        converters.add(RegionIdsReadConverter())
        return R2dbcCustomConversions(converters)
    }
}

# guessing Row is not appropriate type to source?
@ReadingConverter
class RegionIdsReadConverter : Converter<Row,RegionIds> {
    override fun convert(source: Row): RegionIds {
        val regionIdsstring = source.get("region_ids",String::class.java)
        val mapper = ObjectMapper()
        return RegionIds(mapper.readValue(regionIdsstring,object : TypeReference<List<Int>>() {}))
    }
}

然后,我尝试通过 ReactiveCrudRepository 获取数据,但出现错误

Could not read property private final jp.foo.bar.models.test.RegionIds jp.foo.bar.models.test.Prefecture.regionIds from column region_ids!
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readFrom(MappingR2dbcConverter.java:177) ~[spring-data-r2dbc-1.2.8.jar:1.2.8]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ Handler jp.foo.bar.controllers.PrefectureController#getAllPrefectures() [dispatcherHandler]

另外,我尝试使用 r2dbc-MysqLCustom Codecs,但不是无法使用,因为 the fix related to this feature 尚未发布。

我正在使用

我是否遗漏或误解了什么?

解决方法

最后,我找到了解决此问题的方法。

首先,我删除了RegionIdsReadConverter(对应于Pureity实体的字段)并添加了一个对应于Prefecture(实体本身)的转换器。

@ReadingConverter
class PrefectureReadConverter : Converter<Row,Prefecture> {
    override fun convert(source: Row): Prefecture {
        val id = source.get("id",Long::class.java)
        val regionIdsString = source.get("region_ids",String::class.java)
        val mapper = ObjectMapper()
        val regionIds = mapper.readValue(regionIdsString,object : TypeReference<List<Int>>() {})
        return Prefecture(id = id?.toInt(),code = code!!,name = name!!,regionIds = regionIds)
    }
}

另外,我稍微修改了 Prefecture 实体的​​定义。

data class Prefecture(
    @Id
    val id: Int? = null,val regionIds: List<Int>,// eliminate wrapper class RegionIds because it's not necessary anymore
)

然后,我将注册转换器的方式改为:

@Configuration
class R2dbcConfiguration(
    private val connectionFactory: ConnectionFactory
) : AbstractR2dbcConfiguration() {
    override fun connectionFactory() = connectionFactory
    override fun getCustomConverters() = mutableListOf<Any>(PrefectureReadConverter())
}

如果您按照我在问题中发布的方式实施,您可能会看到错误:

org.springframework.data.mapping.MappingException: Could not read property private final boolean xxx.yyy from column zzz!
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Byte] to type [boolean]

根据 this 的说法,如果您在注册自定义转换器时不继承 AbstractR2dbcConfiguration 类,则 r2dbc 方言的预定义转换器似乎将不可用。

为了持久化实体,我还必须实现 WritingConverter

@WritingConverter
class PrefectureWriteConverter : Converter<Prefecture,OutboundRow> {
    override fun convert(source: Prefecture): OutboundRow {
        val row = OutboundRow()
        with(row) {
            put("id",Parameter.fromOrEmpty(source.id?.toLong(),Long::class.java))
            put("region_ids",Parameter.from(ObjectMapper().writeValueAsString(source.regionIds)))
        }
        return row
    }
}

并注册它。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。