Skip to content

Refactor Spring Data R2DBC on top of Spring R2DBC #412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-r2dbc</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.2.0-gh-368-SNAPSHOT</version>

<name>Spring Data R2DBC</name>
<description>Spring Data module for R2DBC</description>
Expand Down Expand Up @@ -107,6 +109,11 @@
<version>${springdata.relational}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-r2dbc</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
Expand Down
1 change: 1 addition & 0 deletions src/main/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ include::reference/kotlin.adoc[leveloffset=+1]
:numbered!:
include::{spring-data-commons-docs}/repository-query-keywords-reference.adoc[leveloffset=+1]
include::{spring-data-commons-docs}/repository-query-return-types-reference.adoc[leveloffset=+1]
include::reference/r2dbc-upgrading.adoc[leveloffset=+1]
1 change: 1 addition & 0 deletions src/main/asciidoc/new-features.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[[new-features.1-2-0]]
== What's New in Spring Data R2DBC 1.2.0

* Deprecate Spring Data R2DBC `DatabaseClient` and move off deprecated API in favor of Spring R2DBC. Consult the <<upgrading.1.1-1.2,Migration Guide>> for further details.
* Support for <<entity-callbacks>>.
* <<r2dbc.auditing,Auditing>> through `@EnableR2dbcAuditing`.

Expand Down
58 changes: 58 additions & 0 deletions src/main/asciidoc/reference/r2dbc-upgrading.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
[appendix]
[[migration-guide]]
= Migration Guide

The following sections explain how to migrate to a newer version of Spring Data R2DBC.

[[upgrading.1.1-1.2]]
== Upgrading from 1.1.x to 1.2.x

Spring Data R2DBC was developed with the intent to evaluate how well R2DBC can integrate with Spring applications.
One of the main aspects was to move core support into Spring Framework once R2DBC support has proven useful.
Spring Framework 5.3 ships with a new module: Spring R2DBC (`spring-r2dbc`).

`spring-r2dbc` ships core R2DBC functionality (a slim variant of `DatabaseClient`, Transaction Manager, Connection Factory initialization, Exception translation) that was initially provided by Spring Data R2DBC. The 1.2.0 release aligns with what's provided in Spring R2DBC by making several changes outlined in the following sections.

Spring R2DBC's `DatabaseClient` is a more lightweight implementation that encapsulates a pure SQL-oriented interface.
You will notice that the method to run SQL statements changed from `DatabaseClient.execute(…)` to `DatabaseClient.sql(…)`.
The fluent API for CRUD operations has moved into `R2dbcEntityTemplate`.

[[upgrading.1.1-1.2.deprecation]]
=== Deprecations

* Deprecation of `o.s.d.r2dbc.core.DatabaseClient` and its support classes `ConnectionAccessor`, `FetchSpec`, `SqlProvider` and a few more.
Named parameter support classes such as `NamedParameterExpander` are encapsulated by Spring R2DBC's `DatabaseClient` implementation hence we're not providing replacements as this was internal API in the first place.
Use `o.s.r2dbc.core.DatabaseClient` and their Spring R2DBC replacements available from `org.springframework.r2dbc.core`.
Entity-based methods (`select`/`insert`/`update`/`delete`) methods are available through `R2dbcEntityTemplate` which was introduced with version 1.1.
* Deprecation of `o.s.d.r2dbc.connectionfactory`, `o.s.d.r2dbc.connectionfactory.init`, and `o.s.d.r2dbc.connectionfactory.lookup` packages.
Use Spring R2DBC's variant which you can find at `o.s.r2dbc.connection`.
* Deprecation of `o.s.d.r2dbc.convert.ColumnMapRowMapper`.
Use `o.s.r2dbc.core.ColumnMapRowMapper` instead.
* Deprecation of binding support classes `o.s.d.r2dbc.dialect.Bindings`, `BindMarker`, `BindMarkers`, `BindMarkersFactory` and related types.
Use replacements from `org.springframework.r2dbc.core.binding`.
* Deprecation of `BadSqlGrammarException`, `UncategorizedR2dbcException` and exception translation at `o.s.d.r2dbc.support`.
Spring R2DBC provides a slim exception translation variant without an SPI for now available through `o.s.r2dbc.connection.ConnectionFactoryUtils#convertR2dbcException`.

[[upgrading.1.1-1.2.replacements]]
=== Usage of replacements provided by Spring R2DBC

To ease migration, several deprecated types are now subtypes of their replacements provided by Spring R2DBC. Spring Data R2DBC has changes several methods or introduced new methods accepting Spring R2DBC types.
Specifically the following classes are changed:

* `R2dbcEntityTemplate`
* `R2dbcDialect`
* Types in `org.springframework.data.r2dbc.query`

We recommend that you review and update your imports if you work with these types directly.

=== Breaking Changes

* `OutboundRow` and statement mappers switched from using `SettableValue` to `Parameter`
* Repository factory support requires `o.s.r2dbc.core.DatabaseClient` instead of `o.s.data.r2dbc.core.DatabaseClient`.

[[upgrading.1.1-1.2.dependencies]]
=== Dependency Changes

To make use of Spring R2DBC, make sure to include the following dependency:

* `org.springframework:spring-r2dbc`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should be done by the build tool for 99.9% of the users, shouldn't it?

I there for just mention it in the starting paragraph, that spring-data-r2dbc now depends on spring-r2dbc.

Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@

import io.r2dbc.spi.R2dbcException;

import org.springframework.dao.InvalidDataAccessResourceUsageException;

/**
* Exception thrown when SQL specified is invalid. Such exceptions always have a {@link io.r2dbc.spi.R2dbcException}
* root cause.
Expand All @@ -28,13 +26,13 @@
* without affecting code using this class.
*
* @author Mark Paluch
* @deprecated since 1.2, use directly Spring R2DBC's {@link org.springframework.r2dbc.BadSqlGrammarException} instead.
*/
public class BadSqlGrammarException extends InvalidDataAccessResourceUsageException {
@Deprecated
public class BadSqlGrammarException extends org.springframework.r2dbc.BadSqlGrammarException {

private static final long serialVersionUID = 3814579246913482054L;

private final String sql;

/**
* Creates a new {@link BadSqlGrammarException}.
*
Expand All @@ -43,10 +41,7 @@ public class BadSqlGrammarException extends InvalidDataAccessResourceUsageExcept
* @param ex the root cause.
*/
public BadSqlGrammarException(String task, String sql, R2dbcException ex) {

super(task + "; bad SQL grammar [" + sql + "]", ex);

this.sql = sql;
super(task, sql, ex);
}

/**
Expand All @@ -60,6 +55,6 @@ public R2dbcException getR2dbcException() {
* Return the SQL that caused the problem.
*/
public String getSql() {
return this.sql;
return super.getSql();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
* Exception thrown when a {@link io.r2dbc.spi.Result} has been accessed in an invalid fashion. Such exceptions always
* have a {@link io.r2dbc.spi.R2dbcException} root cause.
* <p>
* This typically happens when an invalid {@link org.springframework.data.r2dbc.core.FetchSpec} column index or name
* has been specified.
* This typically happens when an invalid {@link org.springframework.data.r2dbc.core.FetchSpec} column index or name has
* been specified.
*
* @author Mark Paluch
* @see BadSqlGrammarException
* @deprecated since 1.2, not in use anymore.
*/
@SuppressWarnings("serial")
@Deprecated
public class InvalidResultAccessException extends InvalidDataAccessResourceUsageException {

private final @Nullable String sql;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,19 @@

import io.r2dbc.spi.R2dbcException;

import org.springframework.dao.UncategorizedDataAccessException;
import org.springframework.lang.Nullable;

/**
* Exception thrown when we can't classify a {@link R2dbcException} into one of our generic data access exceptions.
*
* @author Mark Paluch
* @deprecated since 1.2, use Spring R2DBC's {@link org.springframework.r2dbc.UncategorizedR2dbcException} instead.
*/
public class UncategorizedR2dbcException extends UncategorizedDataAccessException {
@Deprecated
public class UncategorizedR2dbcException extends org.springframework.r2dbc.UncategorizedR2dbcException {

private static final long serialVersionUID = 361587356435210266L;

/**
* SQL that led to the problem
*/
private final @Nullable String sql;

/**
* Creates a new {@link UncategorizedR2dbcException}.
*
Expand All @@ -42,10 +38,7 @@ public class UncategorizedR2dbcException extends UncategorizedDataAccessExceptio
* @param ex the root cause
*/
public UncategorizedR2dbcException(String task, @Nullable String sql, R2dbcException ex) {

super(String.format("%s; uncategorized R2dbcException%s; %s", task, sql != null ? " for SQL [" + sql + "]" : "",
ex.getMessage()), ex);
this.sql = sql;
super(task, sql, ex);
}

/**
Expand All @@ -62,6 +55,6 @@ public R2dbcException getR2dbcException() {
*/
@Nullable
public String getSql() {
return this.sql;
return super.getSql();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,18 @@
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.CustomConversions.StoreConversions;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.r2dbc.convert.MappingR2dbcConverter;
import org.springframework.data.r2dbc.convert.R2dbcCustomConversions;
import org.springframework.data.r2dbc.core.DatabaseClient;
import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.dialect.DialectResolver;
import org.springframework.data.r2dbc.dialect.R2dbcDialect;
import org.springframework.data.r2dbc.mapping.R2dbcMappingContext;
import org.springframework.data.r2dbc.support.R2dbcExceptionSubclassTranslator;
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
import org.springframework.data.r2dbc.support.SqlStateR2dbcExceptionTranslator;
import org.springframework.data.relational.core.conversion.BasicRelationalConverter;
import org.springframework.data.relational.core.mapping.NamingStrategy;
import org.springframework.lang.Nullable;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.util.Assert;

/**
Expand Down Expand Up @@ -100,26 +97,34 @@ public R2dbcDialect getDialect(ConnectionFactory connectionFactory) {
* @throws IllegalArgumentException if any of the required args is {@literal null}.
*/
@Bean({ "r2dbcDatabaseClient", "databaseClient" })
public DatabaseClient databaseClient(ReactiveDataAccessStrategy dataAccessStrategy,
R2dbcExceptionTranslator exceptionTranslator) {
public DatabaseClient databaseClient() {

Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null!");
Assert.notNull(exceptionTranslator, "ExceptionTranslator must not be null!");

SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
if (context != null) {
projectionFactory.setBeanFactory(context);
projectionFactory.setBeanClassLoader(context.getClassLoader());
}
ConnectionFactory connectionFactory = lookupConnectionFactory();

return DatabaseClient.builder() //
.connectionFactory(lookupConnectionFactory()) //
.dataAccessStrategy(dataAccessStrategy) //
.exceptionTranslator(exceptionTranslator) //
.projectionFactory(projectionFactory) //
.connectionFactory(connectionFactory) //
.bindMarkers(getDialect(connectionFactory).getBindMarkersFactory()) //
.build();
}

/**
* Register {@link R2dbcEntityTemplate} using {@link #databaseClient()} and {@link #connectionFactory()}.
*
* @param databaseClient must not be {@literal null}.
* @param dataAccessStrategy must not be {@literal null}.
* @return
* @since 1.2
*/
@Bean
public R2dbcEntityTemplate r2dbcEntityTemplate(DatabaseClient databaseClient,
ReactiveDataAccessStrategy dataAccessStrategy) {

Assert.notNull(databaseClient, "DatabaseClient must not be null!");
Assert.notNull(dataAccessStrategy, "ReactiveDataAccessStrategy must not be null!");

return new R2dbcEntityTemplate(databaseClient, dataAccessStrategy);
}

/**
* Register a {@link R2dbcMappingContext} and apply an optional {@link NamingStrategy}.
*
Expand Down Expand Up @@ -200,19 +205,6 @@ protected StoreConversions getStoreConversions() {
return StoreConversions.of(dialect.getSimpleTypeHolder(), converters);
}

/**
* Creates a {@link R2dbcExceptionTranslator} using the configured {@link #connectionFactory() ConnectionFactory}.
*
* @return must not be {@literal null}.
* @see #connectionFactory()
* @see R2dbcExceptionSubclassTranslator
* @see SqlStateR2dbcExceptionTranslator
*/
@Bean
public R2dbcExceptionTranslator exceptionTranslator() {
return new R2dbcExceptionSubclassTranslator();
}

ConnectionFactory lookupConnectionFactory() {

ApplicationContext context = this.context;
Expand Down
Loading