Open JoseLion opened 2 years ago
Spring Data has an abstraction to detect which types are simple ones (understood natively by the driver). For Spring Data R2DBC, we introduced a Dialect
abstraction to keep database-specifics within a single type. A dialect object can also tell which Java types are simple types via the R2dbcDialect.getSimpleTypes()
method.
Subclassing PostgresDialect
, enriching simple types, and configuring the dialect in your application should allow you to use your application-specific simple types.
@mp911de thanks, that worked! However, it was not that easy to get there đ . Is this just a workaround, or is it documented somewhere?
Also, it'd be great if there could be a simpler way to add custom array types. In a nutshell, these are all the steps I followed to make it work:
Codec<OffsetTimeRange[]>
CodecRegistrar
@WritingConverter
instance:
Converter<OffsetTimeRange, OffsetTimeRange>
, where the convert(source)
method returns the same source
valueR2dbcCustomConversions
beanCustomProstgresDialect
class that extends from PostgresDialect
getSimpleTypes()
methodOffsetTimeRange.class
to the collection without losing the types from super.getSimpleTypes()
CustomDialectProvider
class that implements R2dbcDialectProvider
getDialect(..)
method to return a CustomProstgresDialect
instanceMETA-INF/spring.factories
that should contain the line:
org.springframework.data.r2dbc.dialect.DialectResolver$R2dbcDialectProvider=com.example.CustomDialectProvider
As you can see, there are a lot of steps and new files. Is there any way to improve this process?
As always, I'll be happy to contribute if possible đ
The CodecRegistrar
is part of the ConnectionFactory
configuration and we cannot do much here. The WritingConverter
shouldn't be necessary. Enums use that mechanism only to bypass the built-in enum conversion.
R2dbcDialectProvider
should also not be required as you can override either AbstractR2dbcConfiguration.getDialect()
when using Spring Data R2DBC without Spring Boot. With Spring Boot, you currently cannot provide a custom dialect, but that would be something for Spring Boot to improve. You could alternatively provide your own R2dbcCustomConversions
bean as R2dbcCustomConversions
can be created from a dialect and a collection of converters.
Yep, the CodecRegistrar
it's easy to use (a great feature, IMO!). However, with Spring Boot I still need the WritingConverter
, or else I get the following exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Nested entities are not supported
But... the error goes away if I override
AbstractR2dbcConfiguration.getDialect()
with my custom dialect
On Spring Boot, I was able to create a @Configuration
class that extends from AbstractR2dbcConfiguration
to make some of those overrides. I had to create the ConnectionFactory
manually (using the PostgresqlConnectionFactoryProvider
builder), which is not a bad thing because it also gave me easy access to register custom codecs đ
I tried providing my own R2dbcCustomConversions
bean created with my custom dialect, but it didn't work. It looks like the check for the simple types uses a dialect provided before the one from the R2dbcCustomConversions
bean. That's why I had to switch to the META-INF/spring.factories
solution đ
However, I think the most straightforward solution on Spring Boot was to have a @Configuration
class that extends from AbstractR2dbcConfiguration
, so we can easily add more customizations. Would this be something ok to do on Spring Boot?
Thanks again for your answers, @mp911de! They have been of great help đ
Hi,
I'm using
spring-data-r2dbc
and the extension mechanism fromr2dbc-postgresql
to create a codec for a custom Postgres range type:Since there's no native support for Postgres range types on Java's side, I created my own class
OffsetTimeRange
, and registered a custom codecOffsetTimeRangeCodec
which implements the interfaceCodec<OffsetTimeRange>
.So far, that worked perfectly fine, but I wanted to add the custom codec for its corresponding multirange type. From Postgres range types documentation, we know that:
So I registered another codec
OffsetTimeRangeArrayCodec
which implements the interfaceCodec<OffsetTimeRange[]>
, but this raised the following exception upon reading/writing from the database:The problem
I did some debugging, and I found the exception is thrown in the following check (line #164): https://github.com/spring-projects/spring-data-relational/blob/b691af7b305adfb0a4f8ea7585dc8f7c0abc80e1/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/dialect/PostgresDialect.java#L156-L168
The problem seems to be that the
this.simpleTypeHolder.isSimpleType(typeToUse)
method checks against the local simple types, which are missing any type introduced by a custom codec.As always, I'll be happy to help with a PR if someone can point me in the right direction đ
Cheers!