diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java
index b3e6aa1b43..f518103d2e 100644
--- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java
+++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ import org.springframework.lang.Nullable;
* Particularly appropriate for waiting on a slowly starting Oracle database.
*
* @author Juergen Hoeller
+ * @author Marten Deinum
* @since 18.12.2003
*/
public class DatabaseStartupValidator implements InitializingBean {
@@ -59,12 +60,7 @@ public class DatabaseStartupValidator implements InitializingBean {
@Nullable
private DataSource dataSource;
- /**
- * The query used to validate the connection
- * @deprecated in favor of JDBC 4.0 connection validation
- */
@Nullable
- @Deprecated
private String validationQuery;
private int interval = DEFAULT_INTERVAL;
@@ -81,8 +77,7 @@ public class DatabaseStartupValidator implements InitializingBean {
/**
* Set the SQL query string to use for validation.
- *
- * @deprecated in favor of the JDBC 4.0 connection validation
+ * @deprecated as of 5.3, in favor of the JDBC 4.0 connection validation
*/
@Deprecated
public void setValidationQuery(String validationQuery) {
@@ -148,10 +143,9 @@ public class DatabaseStartupValidator implements InitializingBean {
logger.debug("Validation query [" + this.validationQuery + "] threw exception", ex);
}
else {
- logger.debug(" Validation threw exception", ex);
+ logger.debug("Validation check threw exception", ex);
}
}
-
if (logger.isInfoEnabled()) {
float rest = ((float) (deadLine - System.currentTimeMillis())) / 1000;
if (rest > this.interval) {
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionFactoryUtils.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionFactoryUtils.java
index ef1a0e582e..59e1a4e722 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionFactoryUtils.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionFactoryUtils.java
@@ -80,7 +80,6 @@ public abstract class ConnectionFactoryUtils {
* Translates exceptions into the Spring hierarchy of unchecked generic
* data access exceptions, simplifying calling code and making any
* exception that is thrown more meaningful.
- *
*
Is aware of a corresponding Connection bound to the current
* {@link TransactionSynchronizationManager}. Will bind a Connection to the
* {@link TransactionSynchronizationManager} if transaction synchronization is active.
@@ -99,7 +98,6 @@ public abstract class ConnectionFactoryUtils {
/**
* Actually obtain a R2DBC Connection from the given {@link ConnectionFactory}.
* Same as {@link #getConnection}, but preserving the original exceptions.
- *
*
Is aware of a corresponding Connection bound to the current
* {@link TransactionSynchronizationManager}. Will bind a Connection to the
* {@link TransactionSynchronizationManager} if transaction synchronization is active
@@ -193,11 +191,9 @@ public abstract class ConnectionFactoryUtils {
* @param connectionFactory the {@link ConnectionFactory} that the Connection was obtained from
* @see #doGetConnection
*/
- public static Mono doReleaseConnection(Connection connection,
- ConnectionFactory connectionFactory) {
+ public static Mono doReleaseConnection(Connection connection, ConnectionFactory connectionFactory) {
return TransactionSynchronizationManager.forCurrentTransaction()
.flatMap(synchronizationManager -> {
-
ConnectionHolder conHolder = (ConnectionHolder) synchronizationManager.getResource(connectionFactory);
if (conHolder != null && connectionEquals(conHolder, connection)) {
// It's the transactional Connection: Don't close it.
@@ -235,7 +231,6 @@ public abstract class ConnectionFactoryUtils {
* @return the corresponding DataAccessException instance
*/
public static DataAccessException convertR2dbcException(String task, @Nullable String sql, R2dbcException ex) {
-
if (ex instanceof R2dbcTransientException) {
if (ex instanceof R2dbcTransientResourceException) {
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
@@ -247,7 +242,6 @@ public abstract class ConnectionFactoryUtils {
return new QueryTimeoutException(buildMessage(task, sql, ex), ex);
}
}
-
if (ex instanceof R2dbcNonTransientException) {
if (ex instanceof R2dbcNonTransientResourceException) {
return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex);
@@ -262,7 +256,6 @@ public abstract class ConnectionFactoryUtils {
return new BadSqlGrammarException(task, (sql != null ? sql : ""), ex);
}
}
-
return new UncategorizedR2dbcException(buildMessage(task, sql, ex), sql, ex);
}
@@ -326,7 +319,6 @@ public abstract class ConnectionFactoryUtils {
* @see #CONNECTION_SYNCHRONIZATION_ORDER
*/
private static int getConnectionSynchronizationOrder(ConnectionFactory connectionFactory) {
-
int order = CONNECTION_SYNCHRONIZATION_ORDER;
ConnectionFactory current = connectionFactory;
while (current instanceof DelegatingConnectionFactory) {
@@ -336,6 +328,7 @@ public abstract class ConnectionFactoryUtils {
return order;
}
+
/**
* Callback for resource cleanup at the end of a non-native R2DBC transaction.
*/
@@ -355,7 +348,6 @@ public abstract class ConnectionFactoryUtils {
this.order = getConnectionSynchronizationOrder(connectionFactory);
}
-
@Override
public int getOrder() {
return this.order;
@@ -387,7 +379,8 @@ public abstract class ConnectionFactoryUtils {
public Mono resume() {
if (this.holderActive) {
return TransactionSynchronizationManager.forCurrentTransaction()
- .doOnNext(synchronizationManager -> synchronizationManager.bindResource(this.connectionFactory, this.connectionHolder))
+ .doOnNext(synchronizationManager ->
+ synchronizationManager.bindResource(this.connectionFactory, this.connectionHolder))
.then();
}
return Mono.empty();
@@ -401,8 +394,7 @@ public abstract class ConnectionFactoryUtils {
// to avoid issues with strict transaction implementations that expect
// the close call before transaction completion.
if (!this.connectionHolder.isOpen()) {
- return TransactionSynchronizationManager.forCurrentTransaction()
- .flatMap(synchronizationManager -> {
+ return TransactionSynchronizationManager.forCurrentTransaction().flatMap(synchronizationManager -> {
synchronizationManager.unbindResource(this.connectionFactory);
this.holderActive = false;
if (this.connectionHolder.hasConnection()) {
@@ -439,4 +431,5 @@ public abstract class ConnectionFactoryUtils {
return Mono.empty();
}
}
+
}
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionHolder.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionHolder.java
index c4efc83c27..1c713048db 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionHolder.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionHolder.java
@@ -65,7 +65,6 @@ public class ConnectionHolder extends ResourceHolderSupport {
* in an ongoing transaction
*/
public ConnectionHolder(Connection connection, boolean transactionActive) {
-
this.currentConnection = connection;
this.transactionActive = transactionActive;
}
@@ -80,7 +79,6 @@ public class ConnectionHolder extends ResourceHolderSupport {
/**
* Set whether this holder represents an active, R2DBC-managed transaction.
- *
* @see R2dbcTransactionManager
*/
protected void setTransactionActive(boolean transactionActive) {
@@ -111,7 +109,6 @@ public class ConnectionHolder extends ResourceHolderSupport {
* @see #released()
*/
public Connection getConnection() {
-
Assert.notNull(this.currentConnection, "Active Connection is required");
return this.currentConnection;
}
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java
index c3f553021a..d4d8513d4d 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java
@@ -81,22 +81,21 @@ import org.springframework.util.Assert;
@SuppressWarnings("serial")
public class R2dbcTransactionManager extends AbstractReactiveTransactionManager implements InitializingBean {
+ @Nullable
private ConnectionFactory connectionFactory;
private boolean enforceReadOnly = false;
/**
- * Create a new @link ConnectionFactoryTransactionManager} instance. A ConnectionFactory has to be set to be able to
- * use it.
- *
+ * Create a new @link ConnectionFactoryTransactionManager} instance.
+ * A ConnectionFactory has to be set to be able to use it.
* @see #setConnectionFactory
*/
public R2dbcTransactionManager() {}
/**
* Create a new {@link R2dbcTransactionManager} instance.
- *
* @param connectionFactory the R2DBC ConnectionFactory to manage transactions for
*/
public R2dbcTransactionManager(ConnectionFactory connectionFactory) {
@@ -108,19 +107,10 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
/**
* Set the R2DBC {@link ConnectionFactory} that this instance should manage transactions for.
- *
- * This will typically be a locally defined {@link ConnectionFactory}, for example an connection pool.
- *
- * The {@link ConnectionFactory} specified here should be the target {@link ConnectionFactory} to manage transactions
- * for, not a TransactionAwareConnectionFactoryProxy. Only data access code may work with
- * TransactionAwareConnectionFactoryProxy, while the transaction manager needs to work on the underlying target
- * {@link ConnectionFactory}. If there's nevertheless a TransactionAwareConnectionFactoryProxy passed in, it will be
- * unwrapped to extract its target {@link ConnectionFactory}.
- *
- * The {@link ConnectionFactory} passed in here needs to return independent {@link Connection}s. The
- * {@link Connection}s may come from a pool (the typical case), but the {@link ConnectionFactory} must not return
- * scoped {@link Connection} or the like.
- *
+ *
This will typically be a locally defined {@link ConnectionFactory}, for example an connection pool.
+ *
The {@link ConnectionFactory} passed in here needs to return independent {@link Connection}s.
+ * The {@link Connection}s may come from a pool (the typical case), but the {@link ConnectionFactory}
+ * must not return scoped {@link Connection}s or the like.
* @see TransactionAwareConnectionFactoryProxy
*/
public void setConnectionFactory(@Nullable ConnectionFactory connectionFactory) {
@@ -137,7 +127,6 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
/**
* Obtain the {@link ConnectionFactory} for actual use.
- *
* @return the {@link ConnectionFactory} (never {@code null})
* @throws IllegalStateException in case of no ConnectionFactory set
*/
@@ -149,12 +138,11 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
/**
* Specify whether to enforce the read-only nature of a transaction (as indicated by
- * {@link TransactionDefinition#isReadOnly()} through an explicit statement on the transactional connection: "SET
- * TRANSACTION READ ONLY" as understood by Oracle, MySQL and Postgres.
- *
- * The exact treatment, including any SQL statement executed on the connection, can be customized through through
- * {@link #prepareTransactionalConnection}.
- *
+ * {@link TransactionDefinition#isReadOnly()} through an explicit statement on the
+ * transactional connection: "SET TRANSACTION READ ONLY" as understood by Oracle,
+ * MySQL and Postgres.
+ *
The exact treatment, including any SQL statement executed on the connection,
+ * can be customized through through {@link #prepareTransactionalConnection}.
* @see #prepareTransactionalConnection
*/
public void setEnforceReadOnly(boolean enforceReadOnly) {
@@ -162,9 +150,8 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
/**
- * Return whether to enforce the read-only nature of a transaction through an explicit statement on the transactional
- * connection.
- *
+ * Return whether to enforce the read-only nature of a transaction through an
+ * explicit statement on the transactional connection.
* @see #setEnforceReadOnly
*/
public boolean isEnforceReadOnly() {
@@ -179,8 +166,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
@Override
- protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager)
- throws TransactionException {
+ protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager) throws TransactionException {
ConnectionFactoryTransactionObject txObject = new ConnectionFactoryTransactionObject();
ConnectionHolder conHolder = (ConnectionHolder) synchronizationManager.getResource(obtainConnectionFactory());
txObject.setConnectionHolder(conHolder, false);
@@ -196,17 +182,15 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
@Override
protected Mono doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction,
TransactionDefinition definition) throws TransactionException {
+
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
return Mono.defer(() -> {
-
Mono connectionMono;
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Mono newCon = Mono.from(obtainConnectionFactory().create());
-
connectionMono = newCon.doOnNext(connection -> {
-
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for R2DBC transaction");
}
@@ -219,22 +203,18 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
return connectionMono.flatMap(con -> {
-
return prepareTransactionalConnection(con, definition, transaction).then(Mono.from(con.beginTransaction()))
.doOnSuccess(v -> {
txObject.getConnectionHolder().setTransactionActive(true);
-
Duration timeout = determineTimeout(definition);
if (!timeout.isNegative() && !timeout.isZero()) {
txObject.getConnectionHolder().setTimeoutInMillis(timeout.toMillis());
}
-
// Bind the connection holder to the thread.
if (txObject.isNewConnectionHolder()) {
synchronizationManager.bindResource(obtainConnectionFactory(), txObject.getConnectionHolder());
}
}).thenReturn(con).onErrorResume(e -> {
-
if (txObject.isNewConnectionHolder()) {
return ConnectionFactoryUtils.releaseConnection(con, obtainConnectionFactory())
.doOnTerminate(() -> txObject.setConnectionHolder(null, false))
@@ -243,20 +223,17 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
return Mono.error(e);
});
}).onErrorResume(e -> {
-
CannotCreateTransactionException ex = new CannotCreateTransactionException(
- "Could not open R2DBC Connection for transaction",
- e);
-
+ "Could not open R2DBC Connection for transaction", e);
return Mono.error(ex);
});
}).then();
}
/**
- * Determine the actual timeout to use for the given definition. Will fall back to this manager's default timeout if
- * the transaction definition doesn't specify a non-default value.
- *
+ * Determine the actual timeout to use for the given definition.
+ * Will fall back to this manager's default timeout if the
+ * transaction definition doesn't specify a non-default value.
* @param definition the transaction definition
* @return the actual timeout to use
* @see org.springframework.transaction.TransactionDefinition#getTimeout()
@@ -280,14 +257,11 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
@Override
- protected Mono doResume(TransactionSynchronizationManager synchronizationManager, Object transaction,
- Object suspendedResources) throws TransactionException {
+ protected Mono doResume(TransactionSynchronizationManager synchronizationManager,
+ @Nullable Object transaction, Object suspendedResources) throws TransactionException {
return Mono.defer(() -> {
- ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
- txObject.setConnectionHolder(null);
synchronizationManager.bindResource(obtainConnectionFactory(), suspendedResources);
-
return Mono.empty();
});
}
@@ -301,7 +275,6 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
if (status.isDebug()) {
logger.debug("Committing R2DBC transaction on Connection [" + connection + "]");
}
-
return Mono.from(connection.commitTransaction())
.onErrorMap(R2dbcException.class, ex -> translateException("R2DBC commit", ex));
}
@@ -315,7 +288,6 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
if (status.isDebug()) {
logger.debug("Rolling back R2DBC transaction on Connection [" + connection + "]");
}
-
return Mono.from(connection.rollbackTransaction())
.onErrorMap(R2dbcException.class, ex -> translateException("R2DBC rollback", ex));
}
@@ -326,10 +298,9 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
return Mono.fromRunnable(() -> {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
-
if (status.isDebug()) {
- logger
- .debug("Setting R2DBC transaction [" + txObject.getConnectionHolder().getConnection() + "] rollback-only");
+ logger.debug("Setting R2DBC transaction [" + txObject.getConnectionHolder().getConnection() +
+ "] rollback-only");
}
txObject.setRollbackOnly();
});
@@ -380,20 +351,19 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
/**
* Prepare the transactional {@link Connection} right after transaction begin.
- *
- * The default implementation executes a "SET TRANSACTION READ ONLY" statement if the {@link #setEnforceReadOnly
- * "enforceReadOnly"} flag is set to {@code true} and the transaction definition indicates a read-only transaction.
- *
- * The "SET TRANSACTION READ ONLY" is understood by Oracle, MySQL and Postgres and may work with other databases as
- * well. If you'd like to adapt this treatment, override this method accordingly.
- *
+ *
The default implementation executes a "SET TRANSACTION READ ONLY" statement if the
+ * {@link #setEnforceReadOnly "enforceReadOnly"} flag is set to {@code true} and the
+ * transaction definition indicates a read-only transaction.
+ *
The "SET TRANSACTION READ ONLY" is understood by Oracle, MySQL and Postgres
+ * and may work with other databases as well. If you'd like to adapt this treatment,
+ * override this method accordingly.
* @param con the transactional R2DBC Connection
* @param definition the current transaction definition
* @param transaction the transaction object
* @see #setEnforceReadOnly
*/
- protected Mono prepareTransactionalConnection(Connection con, TransactionDefinition definition,
- Object transaction) {
+ protected Mono prepareTransactionalConnection(
+ Connection con, TransactionDefinition definition, Object transaction) {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
@@ -410,8 +380,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
if (isolationLevelToUse != null && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
if (logger.isDebugEnabled()) {
- logger
- .debug("Changing isolation level of R2DBC Connection [" + con + "] to " + isolationLevelToUse.asSql());
+ logger.debug("Changing isolation level of R2DBC Connection [" + con + "] to " + isolationLevelToUse.asSql());
}
IsolationLevel currentIsolation = con.getTransactionIsolationLevel();
if (!currentIsolation.asSql().equalsIgnoreCase(isolationLevelToUse.asSql())) {
@@ -439,10 +408,9 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
* Resolve the {@link TransactionDefinition#getIsolationLevel() isolation level constant} to a R2DBC
* {@link IsolationLevel}. If you'd like to extend isolation level translation for vendor-specific
* {@link IsolationLevel}s, override this method accordingly.
- *
* @param isolationLevel the isolation level to translate.
- * @return the resolved isolation level. Can be {@code null} if not resolvable or the isolation level should remain
- * {@link TransactionDefinition#ISOLATION_DEFAULT default}.
+ * @return the resolved isolation level. Can be {@code null} if not resolvable or the isolation level
+ * should remain {@link TransactionDefinition#ISOLATION_DEFAULT default}.
* @see TransactionDefinition#getIsolationLevel()
*/
@Nullable
@@ -461,9 +429,8 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
/**
- * Translate the given R2DBC commit/rollback exception to a common Spring exception to propagate from the
- * {@link #commit}/{@link #rollback} call.
- *
+ * Translate the given R2DBC commit/rollback exception to a common Spring exception to propagate
+ * from the {@link #commit}/{@link #rollback} call.
* @param task the task description (commit or rollback).
* @param ex the SQLException thrown from commit/rollback.
* @return the translated exception to emit
@@ -474,8 +441,8 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
/**
- * ConnectionFactory transaction object, representing a ConnectionHolder. Used as transaction object by
- * ConnectionFactoryTransactionManager.
+ * ConnectionFactory transaction object, representing a ConnectionHolder.
+ * Used as transaction object by R2dbcTransactionManager.
*/
private static class ConnectionFactoryTransactionObject {
@@ -489,7 +456,6 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
private boolean mustRestoreAutoCommit;
-
void setConnectionHolder(@Nullable ConnectionHolder connectionHolder, boolean newConnectionHolder) {
setConnectionHolder(connectionHolder);
this.newConnectionHolder = newConnectionHolder;
@@ -535,4 +501,3 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
}
-
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/SingleConnectionFactory.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/SingleConnectionFactory.java
index 1970a6c676..bbcd28fcbc 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/SingleConnectionFactory.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/SingleConnectionFactory.java
@@ -91,10 +91,9 @@ public class SingleConnectionFactory extends DelegatingConnectionFactory
/**
* Create a new {@link SingleConnectionFactory} using a R2DBC connection URL.
- *
* @param url the R2DBC URL to use for accessing {@link ConnectionFactory} discovery.
- * @param suppressClose if the returned {@link Connection} should be a close-suppressing proxy or the physical
- * {@link Connection}.
+ * @param suppressClose if the returned {@link Connection} should be a close-suppressing proxy
+ * or the physical {@link Connection}.
* @see ConnectionFactories#get(String)
*/
public SingleConnectionFactory(String url, boolean suppressClose) {
@@ -106,21 +105,18 @@ public class SingleConnectionFactory extends DelegatingConnectionFactory
/**
* Create a new {@link SingleConnectionFactory} with a given {@link Connection} and
* {@link ConnectionFactoryMetadata}.
- *
* @param target underlying target {@link Connection}.
* @param metadata {@link ConnectionFactory} metadata to be associated with this {@link ConnectionFactory}.
* @param suppressClose if the {@link Connection} should be wrapped with a {@link Connection} that suppresses
- * {@code close()} calls (to allow for normal {@code close()} usage in applications that expect a pooled
- * {@link Connection} but do not know our {@link SmartConnectionFactory} interface).
+ * @code close()} calls (to allow for normal {@code close()} usage in applications that expect a pooled
+ * @link Connection}).
*/
- public SingleConnectionFactory(Connection target, ConnectionFactoryMetadata metadata,
- boolean suppressClose) {
+ public SingleConnectionFactory(Connection target, ConnectionFactoryMetadata metadata, boolean suppressClose) {
super(new ConnectionFactory() {
@Override
public Publisher extends Connection> create() {
return Mono.just(target);
}
-
@Override
public ConnectionFactoryMetadata getMetadata() {
return metadata;
@@ -136,15 +132,16 @@ public class SingleConnectionFactory extends DelegatingConnectionFactory
/**
- * Set whether the returned {@link Connection} should be a close-suppressing proxy or the physical {@link Connection}.
+ * Set whether the returned {@link Connection} should be a close-suppressing proxy
+ * or the physical {@link Connection}.
*/
public void setSuppressClose(boolean suppressClose) {
this.suppressClose = suppressClose;
}
/**
- * Return whether the returned {@link Connection} will be a close-suppressing proxy or the physical
- * {@link Connection}.
+ * Return whether the returned {@link Connection} will be a close-suppressing proxy
+ * or the physical {@link Connection}.
*/
protected boolean isSuppressClose() {
return this.suppressClose;
@@ -159,7 +156,6 @@ public class SingleConnectionFactory extends DelegatingConnectionFactory
/**
* Return whether the returned {@link Connection}'s "autoCommit" setting should be overridden.
- *
* @return the "autoCommit" value, or {@code null} if none to be applied
*/
@Nullable
@@ -167,28 +163,25 @@ public class SingleConnectionFactory extends DelegatingConnectionFactory
return this.autoCommit;
}
+
@Override
public Mono extends Connection> create() {
-
Connection connection = this.target.get();
-
return this.connectionEmitter.map(connectionToUse -> {
-
if (connection == null) {
- this.target.compareAndSet(connection, connectionToUse);
- this.connection = (isSuppressClose() ? getCloseSuppressingConnectionProxy(connectionToUse) : connectionToUse);
+ this.target.compareAndSet(null, connectionToUse);
+ this.connection =
+ (isSuppressClose() ? getCloseSuppressingConnectionProxy(connectionToUse) : connectionToUse);
}
-
return this.connection;
}).flatMap(this::prepareConnection);
}
/**
- * Close the underlying {@link Connection}. The provider of this {@link ConnectionFactory} needs to care for proper
- * shutdown.
- *
- * As this bean implements {@link DisposableBean}, a bean factory will automatically invoke this on destruction of its
- * cached singletons.
+ * Close the underlying {@link Connection}.
+ * The provider of this {@link ConnectionFactory} needs to care for proper shutdown.
+ *
As this bean implements {@link DisposableBean}, a bean factory will automatically
+ * invoke this on destruction of its cached singletons.
*/
@Override
public void destroy() {
@@ -199,46 +192,36 @@ public class SingleConnectionFactory extends DelegatingConnectionFactory
* Reset the underlying shared Connection, to be reinitialized on next access.
*/
public Mono resetConnection() {
-
Connection connection = this.target.get();
-
if (connection == null) {
return Mono.empty();
}
-
return Mono.defer(() -> {
-
if (this.target.compareAndSet(connection, null)) {
-
this.connection = null;
-
return Mono.from(connection.close());
}
-
return Mono.empty();
});
}
/**
- * Prepare the {@link Connection} before using it. Applies {@link #getAutoCommitValue() auto-commit} settings if
- * configured.
- *
+ * Prepare the {@link Connection} before using it.
+ * Applies {@link #getAutoCommitValue() auto-commit} settings if configured.
* @param connection the requested {@link Connection}.
* @return the prepared {@link Connection}.
*/
protected Mono prepareConnection(Connection connection) {
-
Boolean autoCommit = getAutoCommitValue();
if (autoCommit != null) {
return Mono.from(connection.setAutoCommit(autoCommit)).thenReturn(connection);
}
-
return Mono.just(connection);
}
/**
- * Wrap the given {@link Connection} with a proxy that delegates every method call to it but suppresses close calls.
- *
+ * Wrap the given {@link Connection} with a proxy that delegates every method call to it
+ * but suppresses close calls.
* @param target the original {@link Connection} to wrap.
* @return the wrapped Connection.
*/
@@ -264,22 +247,18 @@ public class SingleConnectionFactory extends DelegatingConnectionFactory
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // Invocation on ConnectionProxy interface coming in...
-
- if (method.getName().equals("equals")) {
- // Only consider equal when proxies are identical.
- return proxy == args[0];
- }
- else if (method.getName().equals("hashCode")) {
- // Use hashCode of PersistenceManager proxy.
- return System.identityHashCode(proxy);
- }
- else if (method.getName().equals("unwrap")) {
- return this.target;
- }
- else if (method.getName().equals("close")) {
- // Handle close method: suppress, not valid.
- return Mono.empty();
+ switch (method.getName()) {
+ case "equals":
+ // Only consider equal when proxies are identical.
+ return proxy == args[0];
+ case "hashCode":
+ // Use hashCode of PersistenceManager proxy.
+ return System.identityHashCode(proxy);
+ case "unwrap":
+ return this.target;
+ case "close":
+ // Handle close method: suppress, not valid.
+ return Mono.empty();
}
// Invoke method on target Connection.
@@ -290,7 +269,6 @@ public class SingleConnectionFactory extends DelegatingConnectionFactory
throw ex.getTargetException();
}
}
-
}
}
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/TransactionAwareConnectionFactoryProxy.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/TransactionAwareConnectionFactoryProxy.java
index 9cbd9083b7..406b2662cf 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/TransactionAwareConnectionFactoryProxy.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/TransactionAwareConnectionFactoryProxy.java
@@ -141,23 +141,18 @@ public class TransactionAwareConnectionFactoryProxy extends DelegatingConnection
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (ReflectionUtils.isObjectMethod(method)) {
-
if (ReflectionUtils.isToStringMethod(method)) {
return proxyToString(proxy);
}
-
if (ReflectionUtils.isEqualsMethod(method)) {
return (proxy == args[0]);
}
-
if (ReflectionUtils.isHashCodeMethod(method)) {
return System.identityHashCode(proxy);
}
}
- // Invocation on ConnectionProxy interface coming in...
switch (method.getName()) {
-
case "unwrap":
return this.connection;
case "close":
@@ -183,14 +178,7 @@ public class TransactionAwareConnectionFactoryProxy extends DelegatingConnection
private String proxyToString(@Nullable Object proxy) {
// Allow for differentiating between the proxy and the raw Connection.
- StringBuilder sb = new StringBuilder("Transaction-aware proxy for target Connection ");
- if (this.connection != null) {
- sb.append("[").append(this.connection.toString()).append("]");
- }
- else {
- sb.append(" from ConnectionFactory [").append(this.targetConnectionFactory).append("]");
- }
- return sb.toString();
+ return "Transaction-aware proxy for target Connection [" + this.connection.toString() + "]";
}
}
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DatabaseClient.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DatabaseClient.java
index 02f7ed352d..b2a66ea65a 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DatabaseClient.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DatabaseClient.java
@@ -40,7 +40,7 @@ import org.springframework.util.Assert;
* or obtain a {@link DatabaseClient#builder()} to create an instance.
*
* Usage example:
- *
+ *
* ConnectionFactory factory = …
*
* DatabaseClient client = DatabaseClient.create(factory);
@@ -60,7 +60,6 @@ public interface DatabaseClient extends ConnectionAccessor {
* SQL call along with options leading to the execution. The SQL string can
* contain either native parameter bind markers or named parameters (e.g.
* {@literal :foo, :bar}) when {@link NamedParameterExpander} is enabled.
- *
* @param sql must not be {@code null} or empty
* @return a new {@link GenericExecuteSpec}
* @see NamedParameterExpander
@@ -74,7 +73,6 @@ public interface DatabaseClient extends ConnectionAccessor {
* the execution. The SQL string can contain either native parameter
* bind markers or named parameters (e.g. {@literal :foo, :bar}) when
* {@link NamedParameterExpander} is enabled.
- *
* Accepts {@link PreparedOperation} as SQL and binding {@link Supplier}
* @param sqlSupplier must not be {@code null}
* @return a new {@link GenericExecuteSpec}
@@ -85,7 +83,7 @@ public interface DatabaseClient extends ConnectionAccessor {
GenericExecuteSpec sql(Supplier sqlSupplier);
- // Static, factory methods
+ // Static factory methods
/**
* Create a {@code DatabaseClient} that will use the provided {@link ConnectionFactory}.
@@ -146,7 +144,6 @@ public interface DatabaseClient extends ConnectionAccessor {
* Builder the {@link DatabaseClient} instance.
*/
DatabaseClient build();
-
}
@@ -187,10 +184,8 @@ public interface DatabaseClient extends ConnectionAccessor {
/**
* Add the given filter to the end of the filter chain.
* Filter functions are typically used to invoke methods on the Statement
- * before it is executed.
- *
- * For example:
- *
+ * before it is executed. For example:
+ *
* DatabaseClient client = …;
* client.sql("SELECT book_id FROM book").filter(statement -> statement.fetchSize(100))
*
@@ -204,10 +199,8 @@ public interface DatabaseClient extends ConnectionAccessor {
/**
* Add the given filter to the end of the filter chain.
* Filter functions are typically used to invoke methods on the Statement
- * before it is executed.
- *
- * For example:
- *
+ * before it is executed. For example:
+ *
* DatabaseClient client = …;
* client.sql("SELECT book_id FROM book").filter((statement, next) -> next.execute(statement.fetchSize(100)))
*
@@ -244,7 +237,6 @@ public interface DatabaseClient extends ConnectionAccessor {
* @return a {@link Mono} ignoring its payload (actively dropping).
*/
Mono then();
-
}
}
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DefaultDatabaseClient.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DefaultDatabaseClient.java
index 78f79d7277..0f8c319772 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DefaultDatabaseClient.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DefaultDatabaseClient.java
@@ -53,7 +53,6 @@ import org.springframework.r2dbc.core.binding.BindTarget;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
-
/**
* Default implementation of {@link DatabaseClient}.
*
@@ -72,22 +71,17 @@ class DefaultDatabaseClient implements DatabaseClient {
private final ExecuteFunction executeFunction;
- private final boolean namedParameters;
-
@Nullable
private final NamedParameterExpander namedParameterExpander;
- DefaultDatabaseClient(BindMarkersFactory bindMarkersFactory,
- ConnectionFactory connectionFactory, ExecuteFunction executeFunction,
- boolean namedParameters) {
+ DefaultDatabaseClient(BindMarkersFactory bindMarkersFactory, ConnectionFactory connectionFactory,
+ ExecuteFunction executeFunction, boolean namedParameters) {
this.bindMarkersFactory = bindMarkersFactory;
this.connectionFactory = connectionFactory;
this.executeFunction = executeFunction;
- this.namedParameters = namedParameters;
- this.namedParameterExpander = namedParameters ? new NamedParameterExpander()
- : null;
+ this.namedParameterExpander = (namedParameters ? new NamedParameterExpander() : null);
}
@@ -233,9 +227,7 @@ class DefaultDatabaseClient implements DatabaseClient {
final StatementFilterFunction filterFunction;
-
DefaultGenericExecuteSpec(Supplier sqlSupplier) {
-
this.byIndex = Collections.emptyMap();
this.byName = Collections.emptyMap();
this.sqlSupplier = sqlSupplier;
@@ -255,8 +247,7 @@ class DefaultDatabaseClient implements DatabaseClient {
public DefaultGenericExecuteSpec bind(int index, Object value) {
assertNotPreparedOperation();
Assert.notNull(value, () -> String.format(
- "Value at index %d must not be null. Use bindNull(…) instead.",
- index));
+ "Value at index %d must not be null. Use bindNull(…) instead.", index));
Map byIndex = new LinkedHashMap<>(this.byIndex);
@@ -286,8 +277,7 @@ class DefaultDatabaseClient implements DatabaseClient {
Assert.hasText(name, "Parameter name must not be null or empty!");
Assert.notNull(value, () -> String.format(
- "Value for parameter %s must not be null. Use bindNull(…) instead.",
- name));
+ "Value for parameter %s must not be null. Use bindNull(…) instead.", name));
Map byName = new LinkedHashMap<>(this.byName);
@@ -314,9 +304,7 @@ class DefaultDatabaseClient implements DatabaseClient {
@Override
public DefaultGenericExecuteSpec filter(StatementFilterFunction filter) {
-
Assert.notNull(filter, "Statement FilterFunction must not be null");
-
return new DefaultGenericExecuteSpec(this.byIndex, this.byName, this.sqlSupplier, this.filterFunction.andThen(filter));
}
@@ -336,38 +324,29 @@ class DefaultDatabaseClient implements DatabaseClient {
return fetch().rowsUpdated().then();
}
- private FetchSpec execute(Supplier sqlSupplier,
- BiFunction mappingFunction) {
-
+ private FetchSpec execute(Supplier sqlSupplier, BiFunction mappingFunction) {
String sql = getRequiredSql(sqlSupplier);
-
Function statementFunction = connection -> {
-
if (logger.isDebugEnabled()) {
logger.debug("Executing SQL statement [" + sql + "]");
}
-
if (sqlSupplier instanceof PreparedOperation>) {
-
Statement statement = connection.createStatement(sql);
BindTarget bindTarget = new StatementWrapper(statement);
((PreparedOperation>) sqlSupplier).bindTo(bindTarget);
-
return statement;
}
- if (DefaultDatabaseClient.this.namedParameters) {
+ if (DefaultDatabaseClient.this.namedParameterExpander != null) {
+ Map remainderByName = new LinkedHashMap<>(this.byName);
+ Map remainderByIndex = new LinkedHashMap<>(this.byIndex);
- Map remainderByName = new LinkedHashMap<>(
- this.byName);
- Map remainderByIndex = new LinkedHashMap<>(
- this.byIndex);
+ List parameterNames = DefaultDatabaseClient.this.namedParameterExpander.getParameterNames(sql);
+ MapBindParameterSource namedBindings = retrieveParameters(
+ sql, parameterNames, remainderByName, remainderByIndex);
- MapBindParameterSource namedBindings = retrieveParameters(sql,
- remainderByName, remainderByIndex);
-
- PreparedOperation operation = DefaultDatabaseClient.this.namedParameterExpander.expand(sql,
- DefaultDatabaseClient.this.bindMarkersFactory, namedBindings);
+ PreparedOperation operation = DefaultDatabaseClient.this.namedParameterExpander.expand(
+ sql, DefaultDatabaseClient.this.bindMarkersFactory, namedBindings);
String expanded = getRequiredSql(operation);
if (logger.isTraceEnabled()) {
@@ -406,23 +385,16 @@ class DefaultDatabaseClient implements DatabaseClient {
mappingFunction);
}
- private MapBindParameterSource retrieveParameters(String sql,
- Map remainderByName,
- Map remainderByIndex) {
- List parameterNames = DefaultDatabaseClient.this.namedParameterExpander.getParameterNames(sql);
- Map namedBindings = new LinkedHashMap<>(
- parameterNames.size());
+ private MapBindParameterSource retrieveParameters(String sql, List parameterNames,
+ Map remainderByName, Map remainderByIndex) {
+
+ Map namedBindings = new LinkedHashMap<>(parameterNames.size());
for (String parameterName : parameterNames) {
-
- Parameter parameter = getParameter(remainderByName, remainderByIndex,
- parameterNames, parameterName);
-
+ Parameter parameter = getParameter(remainderByName, remainderByIndex, parameterNames, parameterName);
if (parameter == null) {
throw new InvalidDataAccessApiUsageException(
- String.format("No parameter specified for [%s] in query [%s]",
- parameterName, sql));
+ String.format("No parameter specified for [%s] in query [%s]", parameterName, sql));
}
-
namedBindings.put(parameterName, parameter);
}
return new MapBindParameterSource(namedBindings);
@@ -430,8 +402,7 @@ class DefaultDatabaseClient implements DatabaseClient {
@Nullable
private Parameter getParameter(Map remainderByName,
- Map remainderByIndex, List parameterNames,
- String parameterName) {
+ Map remainderByIndex, List parameterNames, String parameterName) {
if (this.byName.containsKey(parameterName)) {
remainderByName.remove(parameterName);
@@ -456,8 +427,9 @@ class DefaultDatabaseClient implements DatabaseClient {
private void bindByName(Statement statement, Map byName) {
byName.forEach((name, parameter) -> {
- if (parameter.hasValue()) {
- statement.bind(name, parameter.getValue());
+ Object value = parameter.getValue();
+ if (value != null) {
+ statement.bind(name, value);
}
else {
statement.bindNull(name, parameter.getType());
@@ -467,8 +439,9 @@ class DefaultDatabaseClient implements DatabaseClient {
private void bindByIndex(Statement statement, Map byIndex) {
byIndex.forEach((i, parameter) -> {
- if (parameter.hasValue()) {
- statement.bind(i, parameter.getValue());
+ Object value = parameter.getValue();
+ if (value != null) {
+ statement.bind(i, value);
}
else {
statement.bindNull(i, parameter.getType());
@@ -477,10 +450,8 @@ class DefaultDatabaseClient implements DatabaseClient {
}
private String getRequiredSql(Supplier sqlSupplier) {
-
String sql = sqlSupplier.get();
- Assert.state(StringUtils.hasText(sql),
- "SQL returned by SQL supplier must not be empty!");
+ Assert.state(StringUtils.hasText(sql), "SQL returned by SQL supplier must not be empty!");
return sql;
}
@@ -497,32 +468,26 @@ class DefaultDatabaseClient implements DatabaseClient {
private final Connection target;
-
CloseSuppressingInvocationHandler(Connection target) {
this.target = target;
}
@Override
@Nullable
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- // Invocation on ConnectionProxy interface coming in...
-
- if (method.getName().equals("equals")) {
- // Only consider equal when proxies are identical.
- return proxy == args[0];
- }
- else if (method.getName().equals("hashCode")) {
- // Use hashCode of PersistenceManager proxy.
- return System.identityHashCode(proxy);
- }
- else if (method.getName().equals("unwrap")) {
- return this.target;
- }
- else if (method.getName().equals("close")) {
- // Handle close method: suppress, not valid.
- return Mono.error(
- new UnsupportedOperationException("Close is not supported!"));
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ switch (method.getName()) {
+ case "equals":
+ // Only consider equal when proxies are identical.
+ return proxy == args[0];
+ case "hashCode":
+ // Use hashCode of PersistenceManager proxy.
+ return System.identityHashCode(proxy);
+ case "unwrap":
+ return this.target;
+ case "close":
+ // Handle close method: suppress, not valid.
+ return Mono.error(
+ new UnsupportedOperationException("Close is not supported!"));
}
// Invoke method on target Connection.
@@ -533,12 +498,11 @@ class DefaultDatabaseClient implements DatabaseClient {
throw ex.getTargetException();
}
}
-
}
+
/**
- * Holder for a connection that makes sure the close action is invoked atomically only
- * once.
+ * Holder for a connection that makes sure the close action is invoked atomically only once.
*/
static class ConnectionCloseHolder extends AtomicBoolean {
@@ -548,7 +512,6 @@ class DefaultDatabaseClient implements DatabaseClient {
final Function> closeFunction;
-
ConnectionCloseHolder(Connection connection,
Function> closeFunction) {
this.connection = connection;
@@ -556,24 +519,20 @@ class DefaultDatabaseClient implements DatabaseClient {
}
Mono close() {
-
return Mono.defer(() -> {
-
if (compareAndSet(false, true)) {
return Mono.from(this.closeFunction.apply(this.connection));
}
-
return Mono.empty();
});
}
-
}
+
static class StatementWrapper implements BindTarget {
final Statement statement;
-
StatementWrapper(Statement statement) {
this.statement = statement;
}
@@ -597,7 +556,6 @@ class DefaultDatabaseClient implements DatabaseClient {
public void bindNull(int index, Class> type) {
this.statement.bindNull(index, type);
}
-
}
}
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/Parameter.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/Parameter.java
index f74d9b349c..714bfe5504 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/Parameter.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/Parameter.java
@@ -74,8 +74,7 @@ public final class Parameter {
/**
- * Returns the column value. Can be {@code null}.
- * @return the column value. Can be {@code null}
+ * Return the column value. Can be {@code null}.
* @see #hasValue()
*/
@Nullable
@@ -85,7 +84,6 @@ public final class Parameter {
/**
* Returns the column value type. Must be also present if the {@code value} is {@code null}.
- * @return the column value type
*/
public Class> getType() {
return this.type;
@@ -93,29 +91,30 @@ public final class Parameter {
/**
* Returns whether this {@link Parameter} has a value.
- * @return whether this {@link Parameter} has a value. {@code false} if {@link #getValue()} is {@code null}
+ * @return {@code false} if {@link #getValue()} is {@code null}
*/
public boolean hasValue() {
- return this.value != null;
+ return (this.value != null);
}
/**
* Returns whether this {@link Parameter} has a empty.
- * @return whether this {@link Parameter} is empty. {@code true} if {@link #getValue()} is {@code null}
+ * @return {@code true} if {@link #getValue()} is {@code null}
*/
public boolean isEmpty() {
- return this.value == null;
+ return (this.value == null);
}
+
@Override
- public boolean equals(Object o) {
- if (this == o) {
+ public boolean equals(Object obj) {
+ if (this == obj) {
return true;
}
- if (!(o instanceof Parameter)) {
+ if (!(obj instanceof Parameter)) {
return false;
}
- Parameter other = (Parameter) o;
+ Parameter other = (Parameter) obj;
return ObjectUtils.nullSafeEquals(this.value, other.value) && ObjectUtils.nullSafeEquals(this.type, other.type);
}
@@ -126,12 +125,7 @@ public final class Parameter {
@Override
public String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append("Parameter");
- sb.append("[value=").append(this.value);
- sb.append(", type=").append(this.type);
- sb.append(']');
- return sb.toString();
+ return "Parameter[value=" + this.value + ", type=" + this.type + ']';
}
}
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarker.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarker.java
index 71687186a8..7e90397e2b 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarker.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarker.java
@@ -32,13 +32,12 @@ import io.r2dbc.spi.Statement;
public interface BindMarker {
/**
- * Returns the database-specific placeholder for a given substitution.
+ * Return the database-specific placeholder for a given substitution.
*/
String getPlaceholder();
/**
* Bind the given {@code value} to the {@link Statement} using the underlying binding strategy.
- *
* @param bindTarget the target to bind the value to
* @param value the actual value. Must not be {@code null}
* Use {@link #bindNull(BindTarget, Class)} for {@code null} values
diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/Bindings.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/Bindings.java
index b430d96c0f..7e851d2020 100644
--- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/Bindings.java
+++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/Bindings.java
@@ -28,6 +28,7 @@ import java.util.function.Consumer;
import io.r2dbc.spi.Statement;
+import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -69,37 +70,10 @@ public class Bindings implements Iterable {
}
- /**
- * Create a new, empty {@link Bindings} object.
- *
- * @return a new, empty {@link Bindings} object.
- */
- public static Bindings empty() {
- return EMPTY;
- }
-
-
protected Map getBindings() {
return this.bindings;
}
- /**
- * Merge this bindings with an other {@link Bindings} object and create a new merged
- * {@link Bindings} object.
- * @param left the left object to merge with
- * @param right the right object to merge with
- * @return a new, merged {@link Bindings} object
- */
- public static Bindings merge(Bindings left, Bindings right) {
- Assert.notNull(left, "Left side Bindings must not be null");
- Assert.notNull(right, "Right side Bindings must not be null");
- List result = new ArrayList<>(
- left.getBindings().size() + right.getBindings().size());
- result.addAll(left.getBindings().values());
- result.addAll(right.getBindings().values());
- return new Bindings(result);
- }
-
/**
* Merge this bindings with an other {@link Bindings} object and create a new merged
* {@link Bindings} object.
@@ -141,6 +115,32 @@ public class Bindings implements Iterable {
}
+ /**
+ * Create a new, empty {@link Bindings} object.
+ * @return a new, empty {@link Bindings} object.
+ */
+ public static Bindings empty() {
+ return EMPTY;
+ }
+
+ /**
+ * Merge this bindings with an other {@link Bindings} object and create a new merged
+ * {@link Bindings} object.
+ * @param left the left object to merge with
+ * @param right the right object to merge with
+ * @return a new, merged {@link Bindings} object
+ */
+ public static Bindings merge(Bindings left, Bindings right) {
+ Assert.notNull(left, "Left side Bindings must not be null");
+ Assert.notNull(right, "Right side Bindings must not be null");
+ List result = new ArrayList<>(
+ left.getBindings().size() + right.getBindings().size());
+ result.addAll(left.getBindings().values());
+ result.addAll(right.getBindings().values());
+ return new Bindings(result);
+ }
+
+
/**
* Base class for value objects representing a value or a {@code NULL} binding.
*/
@@ -188,7 +188,6 @@ public class Bindings implements Iterable {
* @param bindTarget the target to apply bindings to
*/
public abstract void apply(BindTarget bindTarget);
-
}
@@ -199,19 +198,18 @@ public class Bindings implements Iterable {
private final Object value;
-
ValueBinding(BindMarker marker, Object value) {
super(marker);
this.value = value;
}
-
@Override
public boolean hasValue() {
return true;
}
@Override
+ @NonNull
public Object getValue() {
return this.value;
}
@@ -220,9 +218,9 @@ public class Bindings implements Iterable {
public void apply(BindTarget bindTarget) {
getBindMarker().bind(bindTarget, getValue());
}
-
}
+
/**
* {@code NULL} binding.
*/
@@ -230,13 +228,11 @@ public class Bindings implements Iterable {
private final Class> valueType;
-
NullBinding(BindMarker marker, Class> valueType) {
super(marker);
this.valueType = valueType;
}
-
@Override
public boolean hasValue() {
return false;
@@ -256,7 +252,6 @@ public class Bindings implements Iterable {
public void apply(BindTarget bindTarget) {
getBindMarker().bindNull(bindTarget, getValueType());
}
-
}
}
diff --git a/spring-web/src/main/java/org/springframework/http/RequestEntity.java b/spring-web/src/main/java/org/springframework/http/RequestEntity.java
index 6b62e7222b..4c77123332 100644
--- a/spring-web/src/main/java/org/springframework/http/RequestEntity.java
+++ b/spring-web/src/main/java/org/springframework/http/RequestEntity.java
@@ -69,6 +69,7 @@ public class RequestEntity extends HttpEntity {
@Nullable
private final HttpMethod method;
+ @Nullable
private final URI url;
@Nullable
@@ -138,7 +139,7 @@ public class RequestEntity extends HttpEntity {
* @since 4.3
*/
public RequestEntity(@Nullable T body, @Nullable MultiValueMap headers,
- @Nullable HttpMethod method, URI url, @Nullable Type type) {
+ @Nullable HttpMethod method, @Nullable URI url, @Nullable Type type) {
super(body, headers);
this.method = method;
@@ -160,6 +161,9 @@ public class RequestEntity extends HttpEntity {
* Return the URL of the request.
*/
public URI getUrl() {
+ if (this.url == null) {
+ throw new UnsupportedOperationException();
+ }
return this.url;
}
@@ -679,14 +683,13 @@ public class RequestEntity extends HttpEntity {
*/
public static class UriTemplateRequestEntity extends RequestEntity {
- String uriTemplate;
+ private final String uriTemplate;
@Nullable
- private Object[] uriVarsArray;
+ private final Object[] uriVarsArray;
@Nullable
- Map uriVarsMap;
-
+ private final Map uriVarsMap;
UriTemplateRequestEntity(
@Nullable T body, @Nullable MultiValueMap headers,
@@ -699,7 +702,6 @@ public class RequestEntity extends HttpEntity {
this.uriVarsMap = uriVarsMap;
}
-
public String getUriTemplate() {
return this.uriTemplate;
}
@@ -714,11 +716,6 @@ public class RequestEntity extends HttpEntity {
return this.uriVarsMap;
}
- @Override
- public URI getUrl() {
- throw new UnsupportedOperationException();
- }
-
@Override
public String toString() {
return format(getMethod(), getUriTemplate(), getBody(), getHeaders());
diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
index 84870ca1a2..0071fabd38 100644
--- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
+++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
@@ -667,9 +667,15 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
private URI resolveUrl(RequestEntity> entity) {
if (entity instanceof RequestEntity.UriTemplateRequestEntity) {
RequestEntity.UriTemplateRequestEntity> ext = (RequestEntity.UriTemplateRequestEntity>) entity;
- return (ext.getVars() != null ?
- this.uriTemplateHandler.expand(ext.getUriTemplate(), ext.getVars()) :
- this.uriTemplateHandler.expand(ext.getUriTemplate(), ext.getVarsMap()));
+ if (ext.getVars() != null) {
+ return this.uriTemplateHandler.expand(ext.getUriTemplate(), ext.getVars());
+ }
+ else if (ext.getVarsMap() != null) {
+ return this.uriTemplateHandler.expand(ext.getUriTemplate(), ext.getVarsMap());
+ }
+ else {
+ throw new IllegalStateException("No variables specified for URI template: " + ext.getUriTemplate());
+ }
}
else {
return entity.getUrl();
diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java b/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java
index a34cef914e..531d734135 100644
--- a/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java
+++ b/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java
@@ -137,19 +137,19 @@ public class ForwardedHeaderTransformer implements Function 1 && rawPrefix.charAt(endIndex - 1) == '/') {
- endIndex--;
- }
- prefix.append((endIndex != rawPrefix.length() ? rawPrefix.substring(0, endIndex) : rawPrefix));
- }
- return prefix.toString();
+ if (header == null) {
+ return null;
}
- return header;
+ StringBuilder prefix = new StringBuilder(header.length());
+ String[] rawPrefixes = StringUtils.tokenizeToStringArray(header, ",");
+ for (String rawPrefix : rawPrefixes) {
+ int endIndex = rawPrefix.length();
+ while (endIndex > 1 && rawPrefix.charAt(endIndex - 1) == '/') {
+ endIndex--;
+ }
+ prefix.append((endIndex != rawPrefix.length() ? rawPrefix.substring(0, endIndex) : rawPrefix));
+ }
+ return prefix.toString();
}
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java
index 8f8c84a9b6..1ae8d0c6c8 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java
@@ -411,10 +411,10 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
@Override
public RequestMatchResult match(HttpServletRequest request, String pattern) {
- Assert.isNull(getPatternParser(), "This HandlerMapping requires a PathPattern.");
+ Assert.isNull(getPatternParser(), "This HandlerMapping requires a PathPattern");
RequestMappingInfo info = RequestMappingInfo.paths(pattern).options(this.config).build();
RequestMappingInfo match = info.getMatchingCondition(request);
- return (match != null ?
+ return (match != null && match.getPatternsCondition() != null ?
new RequestMatchResult(
match.getPatternsCondition().getPatterns().iterator().next(),
UrlPathHelper.getResolvedLookupPath(request),