如何解决Spring Data R2DBC 自定义转换不适用于 json 数组
我正在尝试使用 Spring Data R2DBC 的自定义转换来处理 json_array 字段。
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-MysqL 的 Custom Codecs,但不是无法使用,因为 the fix related to this feature 尚未发布。
我正在使用
- MysqL 5.7
- spring-boot-starter-data-r2dbc
- r2dbc-MysqL 0.8.2.RELEASE
我是否遗漏或误解了什么?
解决方法
最后,我找到了解决此问题的方法。
首先,我删除了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 举报,一经查实,本站将立刻删除。