Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreThis release is a major milestone in Spring's R2DBC support. Spring support for R2DBC started as an experimental project two years ago to evaluate how a reactive SQL integration might look. With this release, Spring Data R2DBC underwent a major refactoring by moving several components into a dedicated spring-r2dbc
module and deprecating components that are provided by the Spring Framework. Besides that change, Spring Data R2DBC ships with the following most notable changes:
EntityCallback
APIenum
values and Postgres Geo typesSpring Data R2DBC is now based on spring-r2dbc
, a new module in Spring Framework that ships with core R2DBC support, such as DatabaseClient
, ConnectionFactoryInitializer
, and R2dbcTransactionManager
. Those components were deprecated in favor of Spring R2DBC components and marked for removal with the next major Spring Data R2DBC release. See the migration guide to learn about deprecations and what replacement API to use.
Spring Data Moore introduced the EntityCallback
API to pre-process and post-process entities upon load, save, and delete operations. Entity callbacks are invoked during persistence operations and allow in-place modifications to entities and returning new object instances if an entity class is immutable.
EntityCallback
interfaces are reactive-enabled by returning Publisher<T>
where T
represents the entity type. Returning a publisher allows consuming the subscriber context (as is done for reactive auditing) or integrating with other reactive components that perform I/O before saving an entity or after loading one.
You can use EntityCallback
for all sorts of callback hooks. The following example defines a BeforeConvertCallback
to generate a primary key value from a H2 sequence for the Customer
type if its identifier is null
:
@Bean
BeforeConvertCallback<Customer> idGeneratingCallback(DatabaseClient databaseClient) {
return (customer, sqlIdentifier) -> {
if (customer.getId() == null) {
return databaseClient.sql("SELECT primary_key.nextval") //
.map(row -> row.get(0, Long.class)) //
.first() //
.map(customer::withId);
}
return Mono.just(customer);
};
}
You can read more about R2DBC EntityCallbacks in the R2DBC reference documentation.
enum
Values and Postgres Geo TypesPostgres supports various data types, of which enumerations and Geometric types can be used directly from Spring Data R2DBC. By default, Spring Data converts enum
values to String
by using the enum's name()
method to represent the enumeration value. R2DBC Postgres supports (since version 0.8.4) a specific codec that accepts Java enum
types and maps these onto the corresponding Postgres enum type.
Consider the following Java enum
:
enum Color {
Blue, Green, White
}
Enumeration types in Postgres need to be created before using enum types:
CREATE TYPE color_enum as enum ('Blue', 'Green', `White`);
CREATE TABLE product (id SERIAL PRIMARY KEY, color color_enum);
Once the enum type is in place, you need to configure the driver to associate the Java enum with the corresponding Postgres enum type. This is done by using the R2DBC Postgres EnumCodec
builder . The resulting CodecRegistrar
must be registered with the connection configuration before creating a ConnectionFactory
:
CodecRegistrar codecRegistrar = EnumCodec.builder().withEnum("color_enum", Color.class).build();
PostgresqlConnectionConfiguration configuration = PostgresqlConnectionConfiguration.builder()
.codecRegistrar(codecRegistrar)
// additional configuration
.build();
See also the driver documentation on Postgres Enum Types for further reference.
Once the ConnectionFactory
is configured, you can configure specific enum
types in Spring Data to be passed-thru to the driver with their actual value instead of converting the enum value to String
. R2dbcCustomConversions
is the entry point to use when configuring simple types and their converters:
R2dbcCustomConversions conversions = R2dbcCustomConversions.of(PostgresDialect.INSTANCE, new ColorConverter());
Now you can use the enumeration type in your domain class:
class Product {
@Id Integer id;
Color color;
// getter, setter, constructors omitted for brevity
}
See the reference documentation on Overriding Enum Mapping with Explicit Converters.
In contrast to enums, using Postgres Geometric types requires no special setup since Geo types have fixed type identifiers and map to individual Geo types. Spring Data R2DBC supports the use of the following driver-specific types in your entities:
io.r2dbc.postgresql.codec.Box
io.r2dbc.postgresql.codec.Circle
io.r2dbc.postgresql.codec.Line
io.r2dbc.postgresql.codec.Lseg
io.r2dbc.postgresql.codec.Point
io.r2dbc.postgresql.codec.Path
io.r2dbc.postgresql.codec.Polygon
Alternatively, you can use Spring Data's Geo Types in your domain model:
org.springframework.data.geo.Box
org.springframework.data.geo.Circle
org.springframework.data.geo.Point
org.springframework.data.geo.Polygon
To use Geometric types, create a table and a corresponding entity type:
CREATE TABLE venue (id SERIAL PRIMARY KEY, name VARCHAR(255), location POINT);
class Venue {
@Id Long id;
String name;
Point location;
// getter, setter, constructors omitted for brevity
}
Finally, you can use the entity in your application:
R2dbcEntityTemplate template = …;
template.insert(new Venue(null, "Seattle Space Needle", Point.of(47.6204,-122.3491));