I have following stack:
Spring boot: 2.3.0.RELEASE java: 11 Postgresql 12 backend Pom dependencies : io.r2dbc:r2dbc-postgresql com.vividsolutions:jts:1.13 org.hibernate:hibernate-spatial:5.4.17.Final
My domain class:
@Table
public class Feature {
@Id
private Long id;
@Column(name = "feature_name")
private String featureName;
@Column(name = "geom")
public com.vividsolutions.jts.geom.Geometry geom;
}
In application.properties, I have:
spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.postgis.PostgisDialect
In postgresql, I insert data as Point, Linestring, Multilinestring, for example:
INSERT INTO feaures (id, feature_name, geom)
VALUES (1, 'feature_1', 'SRID=4326;POINT(8.832002 48.493649 0)');
My repository is defined as:
public interface FeatureRepository extends ReactiveCrudRepository<Feature, Long> {}
With this setup, when I try to read records as:
FeatureRepository featureRepository = applicationContext.getBean(FeatureRepository.class);
featureRepository.findAll().doOnNext(feature -> {
log.info(feature);
}).blockLast(Duration.ofSeconds(10));
I get error as:
Exception in thread "main" org.springframework.data.mapping.MappingException: Could not read property @org.springframework.data.relational.core.mapping.Column("geom")public com.vividsolutions.jts.geom.Geometry com.reactive.relational.reactivedemo.Feature.geom from result set! at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readFrom(MappingR2dbcConverter.java:172)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:133)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:116)
at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:46)
at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:29)
at io.r2dbc.postgresql.PostgresqlResult.lambda$map$1(PostgresqlResult.java:114)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:96)
at reactor.core.publisher.FluxTakeUntil$TakeUntilPredicateSubscriber.onNext(FluxTakeUntil.java:77)
at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drainRegular(FluxWindowPredicate.java:650)
at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drain(FluxWindowPredicate.java:728)
at reactor.core.publisher.FluxWindowPredicate$WindowFlux.onNext(FluxWindowPredicate.java:770)
at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.onNext(FluxWindowPredicate.java:249)
at reactor.core.publisher.FluxCreate$BufferAsyncSink.drain(FluxCreate.java:793)
at reactor.core.publisher.FluxCreate$BufferAsyncSink.next(FluxCreate.java:718)
at reactor.core.publisher.FluxCreate$SerializedSink.next(FluxCreate.java:153)
at io.r2dbc.postgresql.client.ReactorNettyClient$Conversation.emit(ReactorNettyClient.java:679)
at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.emit(ReactorNettyClient.java:867)
at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.onNext(ReactorNettyClient.java:801)
at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.onNext(ReactorNettyClient.java:710)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:112)
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:845)
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:213)
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:213)
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:220)
at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:354)
at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:352)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:96)
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:425)
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:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
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:832)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:139)
at reactor.core.publisher.Flux.blockLast(Flux.java:2521)
at com.reactive.relational.reactivedemo.ReactiveDemoApplication.main(ReactiveDemoApplication.java:42)
Caused by: java.lang.IllegalStateException: Required identifier property not found for class com.vividsolutions.jts.geom.Geometry!
at org.springframework.data.mapping.PersistentEntity.getRequiredIdProperty(PersistentEntity.java:105)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readEntityFrom(MappingR2dbcConverter.java:273)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.readFrom(MappingR2dbcConverter.java:160)
... 49 more
I try to use @Id, @Column annotation from org.springframework.data too, but same error.
Blogs, stackoverflow etc says this is straightforward mapping and should work. But I have just not been able to make it work.
Is there an issue in r2dbc?
Comment From: wilkinsona
Spring Data R2DBC is managed as a separate project. If you believe you have found a bug, please open an issue over there. If you are looking for some help, there are some resources in the project's README.
One thing that I have noticed in what you've shared thus far is that your configuration of Hibernate-related properties won't have any effect as Hibernate will not be involved if you're using Spring Data R2DBC. The dependency on hibernate-spatial is probably redundant as well.