[英]Mapping to JSON Fields with Spring Data R2DBC and Reactive MySQL Driver
我正在嘗試使用 JSON 數據類型將 json 數據存儲在 MySQL 數據庫的特定列中。
我按照本指南進行了存儲和讀取 JSON 工作正常但現在我在嘗試保存另一個具有boolean
列/字段的實體時收到此錯誤:
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Byte] to type [boolean]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.getPotentiallyConvertedSimpleRead(MappingR2dbcConverter.java:277)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readValue(MappingR2dbcConverter.java:201)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readFrom(MappingR2dbcConverter.java:182)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:136)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:119)
at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:46)
at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:29)
at dev.miku.r2dbc.mysql.MySqlResult.processRow(MySqlResult.java:176)
at dev.miku.r2dbc.mysql.MySqlResult.handleResult(MySqlResult.java:149)
at dev.miku.r2dbc.mysql.MySqlResult.lambda$map$1(MySqlResult.java:93)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:102)
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)
at dev.miku.r2dbc.mysql.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:70)
at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drainRegular(FluxWindowPredicate.java:667)
at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drain(FluxWindowPredicate.java:745)
at reactor.core.publisher.FluxWindowPredicate$WindowFlux.onNext(FluxWindowPredicate.java:787)
at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.onNext(FluxWindowPredicate.java:265)
at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:184)
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)
at dev.miku.r2dbc.mysql.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:70)
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:199)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:118)
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854)
at reactor.core.publisher.EmitterProcessor.drain(EmitterProcessor.java:491)
at reactor.core.publisher.EmitterProcessor.tryEmitNext(EmitterProcessor.java:299)
at reactor.core.publisher.InternalManySink.emitNext(InternalManySink.java:27)
at reactor.core.publisher.EmitterProcessor.onNext(EmitterProcessor.java:265)
at dev.miku.r2dbc.mysql.client.ReactorNettyClient$ResponseSink.next(ReactorNettyClient.java:340)
at dev.miku.r2dbc.mysql.client.ReactorNettyClient.lambda$new$0(ReactorNettyClient.java:103)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:184)
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:280)
at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:389)
at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:405)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:94)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at dev.miku.r2dbc.mysql.client.MessageDuplexCodec.handleDecoded(MessageDuplexCodec.java:187)
at dev.miku.r2dbc.mysql.client.MessageDuplexCodec.channelRead(MessageDuplexCodec.java:95)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:311)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:432)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1368)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1234)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1280)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:507)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:446)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
如果我不創建R2dbcCustomConversions
bean(如指南中所述),那么我不會收到此錯誤,但 JSON 不起作用...
在我的場景中還有另一種使用 JSON 的方法嗎?
回答我自己的問題 - 看起來像 spring-data-r2dbc 中的某種錯誤:
在R2dbcDataAutoConfiguration
中有這個 bean 定義:
@Bean
@ConditionalOnMissingBean
public R2dbcCustomConversions r2dbcCustomConversions() {
List<Object> converters = new ArrayList<>(this.dialect.getConverters());
converters.addAll(R2dbcCustomConversions.STORE_CONVERTERS);
return new R2dbcCustomConversions(
CustomConversions.StoreConversions.of(this.dialect.getSimpleTypeHolder(), converters),
Collections.emptyList());
}
這是我們在注冊轉換器時覆蓋的 bean(這是我的代碼):
@Bean
public R2dbcCustomConversions r2dbcCustomConversions(JsonEventsReadingConverter readingConverter,
JsonEventsWritingConverter writingConverter) {
val converters = new ArrayList<>();
converters.add(readingConverter);
converters.add(writingConverter);
return new R2dbcCustomConversions(converters);
}
CTOR new R2dbcCustomConversions(converters)
負責添加一些基本轉換器( STORE_CONVERSIONS
和R2dbcConverters
)但它不添加MySqlDialect.BooleanToByteConverter
和MySqlDialect.ByteToBooleanConverter
負責將 MySQL 值轉換為 8837439595.3288 轉換
我找到了一個棘手的解決方案(在我的 bean 中手動添加這些轉換器)但我看不到另一種方法(接受建議):
@Configuration
@RequiredArgsConstructor
public class R2dbcConvertorsConfig {
private final DatabaseClient databaseClient;
@Bean
public R2dbcCustomConversions r2dbcCustomConversions(JsonEventsReadingConverter readingConverter,
JsonEventsWritingConverter writingConverter) {
val dialect = DialectResolver.getDialect(this.databaseClient.getConnectionFactory());
val converters = new ArrayList<>();
converters.add(readingConverter);
converters.add(writingConverter);
converters.addAll(dialect.getConverters());
return new R2dbcCustomConversions(converters);
}
}
按照要求:
package com.mycompany.platform.webhookdelivery.core.dal.converters;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mycompany.platform.webhookdelivery.core.dal.entities.webhookfilters.JsonEvents;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.SerializationFailedException;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Slf4j
@ReadingConverter
@AllArgsConstructor
@Component
public class JsonEventsReadingConverter implements Converter<String, JsonEvents> {
private final ObjectMapper objectMapper;
@Override
public JsonEvents convert(@NonNull String target) {
try {
String json = " {\"events\":" + target + "}";
return objectMapper.readValue(json, JsonEvents.class);
} catch (IOException e) {
log.debug("Failed to deserialise JSON: " + target, e);
throw new SerializationFailedException("Failed to deserialize JSON: " + target, e);
}
}
}
package com.mycompany.platform.webhookdelivery.core.dal.converters;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mycompany.platform.webhookdelivery.core.dal.entities.webhookfilters.JsonEvents;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.SerializationFailedException;
import org.springframework.data.convert.WritingConverter;
import org.springframework.stereotype.Component;
@Log4j2
@WritingConverter
@AllArgsConstructor
@Component
public class JsonEventsWritingConverter implements Converter<JsonEvents, String> {
private final ObjectMapper objectMapper;
@Override
public String convert(JsonEvents source) {
try {
return objectMapper.writeValueAsString(source.getEvents());
} catch (JsonProcessingException e) {
log.debug("Failed to serialise JSON: " + source, e);
throw new SerializationFailedException("Failed to serialize JSON: " + source, e);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.