Custom type mapping
Custom PostgreSQL types like citext or int4range can be supported in Exposed’s R2DBC module using custom TypeMapper implementations. This enables accurate value binding and SQL generation without depending on JDBC-only features like PGobject.
To achieve this, you need to do the following:
Implement a custom
TypeMapperthat binds values of those column types.Register your mapper so it takes effect before the built-in
PostgresSpecificTypeMapper.
Defining a custom column type
Custom column types are responsible for generating appropriate SQL types and converting values to and from database representations.
For example, the following CitextR2dbcColumnType emits CITEXT as its SQL type and can be used in column definitions:
Similarly, to support range types like int4range, you can create an abstract base type:
Concrete subclasses like IntRangeColumnType can then implement .toRange() to handle parsing. For more information, see Ranges of data.
Implementing a TypeMapper
A TypeMapper is responsible for binding Kotlin values to R2DBC Statement parameters based on the dialect and column type.
Here's an example CustomTypeMapper that supports both citext and int4range:
This implementation ensures that Exposed can serialize these custom types properly at runtime.
Registering the type mapper
Exposed uses the Java SPI ServiceLoader to discover and load any implementations of this interface. To register your mapper, a new file should be created in the resources folder.
Create the following file in your project:
src/main/resources/META-INF/services/org.jetbrains.exposed.v1.r2dbc.mappers.TypeMapperAdd the fully qualified class name of your type mapper to the file:
com.example.mapper.CustomTypeMapper
When Exposed initializes, your custom mapper will be loaded and added to the R2dbcRegistryTypeMapping.