diff --git a/pom.xml b/pom.xml
index f0b2a42b23..429fd43bc3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-relational-parent
- 3.4.0-SNAPSHOT
+ 3.4.0-1872-refactor-SBJQ-SNAPSHOT
pom
Spring Data Relational Parent
diff --git a/spring-data-jdbc-distribution/pom.xml b/spring-data-jdbc-distribution/pom.xml
index 84eeb178e0..2c032f6242 100644
--- a/spring-data-jdbc-distribution/pom.xml
+++ b/spring-data-jdbc-distribution/pom.xml
@@ -14,7 +14,7 @@
org.springframework.data
spring-data-relational-parent
- 3.4.0-SNAPSHOT
+ 3.4.0-1872-refactor-SBJQ-SNAPSHOT
../pom.xml
diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml
index 266af71b96..84e71e08b1 100644
--- a/spring-data-jdbc/pom.xml
+++ b/spring-data-jdbc/pom.xml
@@ -6,7 +6,7 @@
4.0.0
spring-data-jdbc
- 3.4.0-SNAPSHOT
+ 3.4.0-1872-refactor-SBJQ-SNAPSHOT
Spring Data JDBC
Spring Data module for JDBC repositories.
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-relational-parent
- 3.4.0-SNAPSHOT
+ 3.4.0-1872-refactor-SBJQ-SNAPSHOT
diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/AbstractJdbcQuery.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/AbstractJdbcQuery.java
index 8e9db74cd6..e66aed271a 100644
--- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/AbstractJdbcQuery.java
+++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/AbstractJdbcQuery.java
@@ -76,7 +76,7 @@ public JdbcQueryMethod getQueryMethod() {
* Creates a {@link JdbcQueryExecution} given a {@link ResultSetExtractor} or a {@link RowMapper}. Prefers the given
* {@link ResultSetExtractor} over {@link RowMapper}.
*
- * @param extractor must not be {@literal null}.
+ * @param extractor may be {@literal null}.
* @param rowMapper must not be {@literal null}.
* @return a JdbcQueryExecution appropriate for {@literal queryMethod}. Guaranteed to be not {@literal null}.
*/
@@ -155,7 +155,34 @@ private JdbcQueryExecution createSingleReadingQueryExecution(ResultSetExt
* @since 2.3
*/
public interface RowMapperFactory {
+
+ /**
+ * Create a {@link RowMapper} based on the expected return type passed in as an argument.
+ *
+ * @param result must not be {@code null}.
+ * @return a {@code RowMapper} producing instances of {@code result}.
+ */
RowMapper create(Class> result);
+
+ /**
+ * Obtain a {@code RowMapper} from some other source, typically a {@link org.springframework.beans.factory.BeanFactory}.
+ *
+ * @param reference must not be {@code null}.
+ * @since 3.4
+ */
+ default RowMapper getRowMapper(String reference) {
+ throw new UnsupportedOperationException("getRowMapper is not supported");
+ }
+
+ /**
+ * Obtain a {@code ResultSetExtractor} from some other source, typically a {@link org.springframework.beans.factory.BeanFactory}.
+ *
+ * @param reference must not be {@code null}.
+ * @since 3.4
+ */
+ default ResultSetExtractor getResultSetExtractor(String reference) {
+ throw new UnsupportedOperationException("getResultSetExtractor is not supported");
+ }
}
/**
diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java
index 7e8da647ee..0876d099a3 100644
--- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java
+++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java
@@ -77,7 +77,6 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
private final SpelEvaluator spelEvaluator;
private final boolean containsSpelExpressions;
private final String query;
- private BeanFactory beanFactory;
private final CachedRowMapperFactory cachedRowMapperFactory;
private final CachedResultSetExtractorFactory cachedResultSetExtractorFactory;
@@ -353,9 +352,8 @@ private static boolean isUnconfigured(@Nullable Class> configuredClass, Class<
return configuredClass == null || configuredClass == defaultClass;
}
- public void setBeanFactory(BeanFactory beanFactory) {
- this.beanFactory = beanFactory;
- }
+ @Deprecated(since = "3.4")
+ public void setBeanFactory(BeanFactory beanFactory) {}
class CachedRowMapperFactory {
@@ -380,10 +378,7 @@ public CachedRowMapperFactory(Supplier> defaultMapper) {
this.cachedRowMapper = Lazy.of(() -> {
if (!ObjectUtils.isEmpty(rowMapperRef)) {
-
- Assert.notNull(beanFactory, "When a RowMapperRef is specified the BeanFactory must not be null");
-
- return (RowMapper) beanFactory.getBean(rowMapperRef);
+ return rowMapperFactory.getRowMapper(rowMapperRef);
}
if (isUnconfigured(rowMapperClass, RowMapper.class)) {
@@ -434,10 +429,7 @@ public CachedResultSetExtractorFactory(Supplier> resultSetExtractor
this.resultSetExtractorFactory = rowMapper -> {
if (!ObjectUtils.isEmpty(resultSetExtractorRef)) {
-
- Assert.notNull(beanFactory, "When a ResultSetExtractorRef is specified the BeanFactory must not be null");
-
- return (ResultSetExtractor) beanFactory.getBean(resultSetExtractorRef);
+ return rowMapperFactory.getResultSetExtractor(resultSetExtractorRef);
}
if (isUnconfigured(resultSetExtractorClass, ResultSetExtractor.class)) {
diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java
index b1f3f5bd9f..d265b1becd 100644
--- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java
+++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java
@@ -26,6 +26,7 @@
import org.springframework.data.jdbc.core.convert.EntityRowMapper;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.repository.QueryMappingConfiguration;
+import org.springframework.data.jdbc.repository.query.AbstractJdbcQuery;
import org.springframework.data.jdbc.repository.query.JdbcQueryMethod;
import org.springframework.data.jdbc.repository.query.PartTreeJdbcQuery;
import org.springframework.data.jdbc.repository.query.StringBasedJdbcQuery;
@@ -42,6 +43,7 @@
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
+import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SingleColumnRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@@ -71,13 +73,12 @@ abstract class JdbcQueryLookupStrategy extends RelationalQueryLookupStrategy {
private final JdbcConverter converter;
private final QueryMappingConfiguration queryMappingConfiguration;
private final NamedParameterJdbcOperations operations;
- @Nullable private final BeanFactory beanfactory;
protected final QueryMethodEvaluationContextProvider evaluationContextProvider;
JdbcQueryLookupStrategy(ApplicationEventPublisher publisher, @Nullable EntityCallbacks callbacks,
RelationalMappingContext context, JdbcConverter converter, Dialect dialect,
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
- @Nullable BeanFactory beanfactory, QueryMethodEvaluationContextProvider evaluationContextProvider) {
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
super(context, dialect);
@@ -85,7 +86,7 @@ abstract class JdbcQueryLookupStrategy extends RelationalQueryLookupStrategy {
Assert.notNull(converter, "JdbcConverter must not be null");
Assert.notNull(queryMappingConfiguration, "QueryMappingConfiguration must not be null");
Assert.notNull(operations, "NamedParameterJdbcOperations must not be null");
- Assert.notNull(evaluationContextProvider, "QueryMethodEvaluationContextProvier must not be null");
+ Assert.notNull(evaluationContextProvider, "QueryMethodEvaluationContextProvider must not be null");
this.context = context;
this.publisher = publisher;
@@ -93,7 +94,6 @@ abstract class JdbcQueryLookupStrategy extends RelationalQueryLookupStrategy {
this.converter = converter;
this.queryMappingConfiguration = queryMappingConfiguration;
this.operations = operations;
- this.beanfactory = beanfactory;
this.evaluationContextProvider = evaluationContextProvider;
}
@@ -112,9 +112,9 @@ static class CreateQueryLookupStrategy extends JdbcQueryLookupStrategy {
CreateQueryLookupStrategy(ApplicationEventPublisher publisher, @Nullable EntityCallbacks callbacks,
RelationalMappingContext context, JdbcConverter converter, Dialect dialect,
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
- @Nullable BeanFactory beanfactory, QueryMethodEvaluationContextProvider evaluationContextProvider) {
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
- super(publisher, callbacks, context, converter, dialect, queryMappingConfiguration, operations, beanfactory,
+ super(publisher, callbacks, context, converter, dialect, queryMappingConfiguration, operations,
evaluationContextProvider);
}
@@ -138,12 +138,16 @@ public RepositoryQuery resolveQuery(Method method, RepositoryMetadata repository
*/
static class DeclaredQueryLookupStrategy extends JdbcQueryLookupStrategy {
+ private final AbstractJdbcQuery.RowMapperFactory rowMapperFactory;
+
DeclaredQueryLookupStrategy(ApplicationEventPublisher publisher, @Nullable EntityCallbacks callbacks,
RelationalMappingContext context, JdbcConverter converter, Dialect dialect,
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
@Nullable BeanFactory beanfactory, QueryMethodEvaluationContextProvider evaluationContextProvider) {
- super(publisher, callbacks, context, converter, dialect, queryMappingConfiguration, operations, beanfactory,
+ super(publisher, callbacks, context, converter, dialect, queryMappingConfiguration, operations,
evaluationContextProvider);
+
+ this.rowMapperFactory = new BeanFactoryRowMapperFactory(beanfactory);
}
@Override
@@ -161,15 +165,51 @@ public RepositoryQuery resolveQuery(Method method, RepositoryMetadata repository
String queryString = evaluateTableExpressions(repositoryMetadata, queryMethod.getRequiredQuery());
- StringBasedJdbcQuery query = new StringBasedJdbcQuery(queryString, queryMethod, getOperations(),
- this::createMapper, getConverter(), evaluationContextProvider);
- query.setBeanFactory(getBeanFactory());
- return query;
+ return new StringBasedJdbcQuery(queryString, queryMethod, getOperations(), rowMapperFactory, getConverter(),
+ evaluationContextProvider);
}
throw new IllegalStateException(
String.format("Did neither find a NamedQuery nor an annotated query for method %s", method));
}
+
+ @SuppressWarnings("unchecked")
+ private class BeanFactoryRowMapperFactory implements AbstractJdbcQuery.RowMapperFactory {
+
+ private final @Nullable BeanFactory beanFactory;
+
+ BeanFactoryRowMapperFactory(@Nullable BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ public RowMapper create(Class> result) {
+ return createMapper(result);
+ }
+
+ @Override
+ public RowMapper getRowMapper(String reference) {
+
+ if (beanFactory == null) {
+ throw new IllegalStateException(
+ "Cannot resolve RowMapper bean reference '" + reference + "'; BeanFactory is not configured.");
+ }
+
+ return beanFactory.getBean(reference, RowMapper.class);
+ }
+
+ @Override
+ public ResultSetExtractor getResultSetExtractor(String reference) {
+
+ if (beanFactory == null) {
+ throw new IllegalStateException(
+ "Cannot resolve ResultSetExtractor bean reference '" + reference + "'; BeanFactory is not configured.");
+ }
+
+ return beanFactory.getBean(reference, ResultSetExtractor.class);
+ }
+ }
+
}
/**
@@ -194,10 +234,10 @@ static class CreateIfNotFoundQueryLookupStrategy extends JdbcQueryLookupStrategy
CreateIfNotFoundQueryLookupStrategy(ApplicationEventPublisher publisher, @Nullable EntityCallbacks callbacks,
RelationalMappingContext context, JdbcConverter converter, Dialect dialect,
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
- @Nullable BeanFactory beanfactory, CreateQueryLookupStrategy createStrategy,
+ CreateQueryLookupStrategy createStrategy,
DeclaredQueryLookupStrategy lookupStrategy, QueryMethodEvaluationContextProvider evaluationContextProvider) {
- super(publisher, callbacks, context, converter, dialect, queryMappingConfiguration, operations, beanfactory,
+ super(publisher, callbacks, context, converter, dialect, queryMappingConfiguration, operations,
evaluationContextProvider);
Assert.notNull(createStrategy, "CreateQueryLookupStrategy must not be null");
@@ -254,23 +294,23 @@ public static QueryLookupStrategy create(@Nullable Key key, ApplicationEventPubl
Assert.notNull(operations, "NamedParameterJdbcOperations must not be null");
CreateQueryLookupStrategy createQueryLookupStrategy = new CreateQueryLookupStrategy(publisher, callbacks, context,
- converter, dialect, queryMappingConfiguration, operations, beanFactory, evaluationContextProvider);
+ converter, dialect, queryMappingConfiguration, operations, evaluationContextProvider);
DeclaredQueryLookupStrategy declaredQueryLookupStrategy = new DeclaredQueryLookupStrategy(publisher, callbacks,
context, converter, dialect, queryMappingConfiguration, operations, beanFactory, evaluationContextProvider);
- Key cleanedKey = key != null ? key : Key.CREATE_IF_NOT_FOUND;
+ Key keyToUse = key != null ? key : Key.CREATE_IF_NOT_FOUND;
- LOG.debug(String.format("Using the queryLookupStrategy %s", cleanedKey));
+ LOG.debug(String.format("Using the queryLookupStrategy %s", keyToUse));
- switch (cleanedKey) {
+ switch (keyToUse) {
case CREATE:
return createQueryLookupStrategy;
case USE_DECLARED_QUERY:
return declaredQueryLookupStrategy;
case CREATE_IF_NOT_FOUND:
return new CreateIfNotFoundQueryLookupStrategy(publisher, callbacks, context, converter, dialect,
- queryMappingConfiguration, operations, beanFactory, createQueryLookupStrategy, declaredQueryLookupStrategy,
+ queryMappingConfiguration, operations, createQueryLookupStrategy, declaredQueryLookupStrategy,
evaluationContextProvider);
default:
throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s", key));
@@ -285,11 +325,6 @@ NamedParameterJdbcOperations getOperations() {
return operations;
}
- @Nullable
- BeanFactory getBeanFactory() {
- return beanfactory;
- }
-
@SuppressWarnings("unchecked")
RowMapper createMapper(Class> returnedObjectType) {
diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java
index d5fabc8f7c..d9d0a0cc3e 100644
--- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java
+++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java
@@ -33,7 +33,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
-import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.data.convert.ReadingConverter;
@@ -163,14 +162,9 @@ void cachesCustomMapperAndExtractorInstances() {
@Test // GH-1721
void obtainsCustomRowMapperRef() {
- BeanFactory beanFactory = mock(BeanFactory.class);
- JdbcQueryMethod queryMethod = createMethod("findAllCustomRowMapperRef");
- StringBasedJdbcQuery query = createQuery(queryMethod);
- query.setBeanFactory(beanFactory);
-
CustomRowMapper customRowMapper = new CustomRowMapper();
-
- when(beanFactory.getBean("CustomRowMapper")).thenReturn(customRowMapper);
+ JdbcQueryMethod queryMethod = createMethod("findAllCustomRowMapperRef");
+ StringBasedJdbcQuery query = createQuery(queryMethod, "CustomRowMapper", customRowMapper);
RowMapper> rowMapper = query.determineRowMapper(queryMethod.getResultProcessor(), false);
ResultSetExtractor resultSetExtractor = query.determineResultSetExtractor(() -> {
@@ -184,14 +178,9 @@ void obtainsCustomRowMapperRef() {
@Test // GH-1721
void obtainsCustomResultSetExtractorRef() {
- BeanFactory beanFactory = mock(BeanFactory.class);
- JdbcQueryMethod queryMethod = createMethod("findAllCustomResultSetExtractorRef");
- StringBasedJdbcQuery query = createQuery(queryMethod);
- query.setBeanFactory(beanFactory);
-
CustomResultSetExtractor cre = new CustomResultSetExtractor();
-
- when(beanFactory.getBean("CustomResultSetExtractor")).thenReturn(cre);
+ JdbcQueryMethod queryMethod = createMethod("findAllCustomResultSetExtractorRef");
+ StringBasedJdbcQuery query = createQuery(queryMethod, "CustomResultSetExtractor", cre);
RowMapper> rowMapper = query.determineRowMapper(queryMethod.getResultProcessor(), false);
ResultSetExtractor resultSetExtractor = query.determineResultSetExtractor(() -> {
@@ -332,10 +321,10 @@ void queryByListOfTuples() {
String[][] tuples = { new String[] { "Albert", "Einstein" }, new String[] { "Richard", "Feynman" } };
SqlParameterSource parameterSource = forMethod("findByListOfTuples", List.class) //
- .withArguments(Arrays.asList(tuples)) //
+ .withArguments(Arrays.asList(tuples))//
.extractParameterSource();
- assertThat(parameterSource.getValue("tuples")).asInstanceOf(LIST) //
+ assertThat(parameterSource.getValue("tuples")).asInstanceOf(LIST)//
.containsExactly(tuples);
assertThat(parameterSource.getSqlType("tuples")).isEqualTo(JdbcUtil.TYPE_UNKNOWN.getVendorTypeNumber());
@@ -441,7 +430,11 @@ private JdbcQueryMethod createMethod(String methodName, Class>... paramTypes)
}
private StringBasedJdbcQuery createQuery(JdbcQueryMethod queryMethod) {
- return new StringBasedJdbcQuery(queryMethod, operations, defaultRowMapper, converter, evaluationContextProvider);
+ return createQuery(queryMethod, null, null);
+ }
+
+ private StringBasedJdbcQuery createQuery(JdbcQueryMethod queryMethod, String preparedReference, Object value) {
+ return new StringBasedJdbcQuery(queryMethod, operations, new StubRowMapperFactory(preparedReference, value), converter, evaluationContextProvider);
}
interface MyRepository extends Repository {
@@ -636,4 +629,37 @@ public Object getRootObject() {
}
}
+ private class StubRowMapperFactory implements AbstractJdbcQuery.RowMapperFactory {
+
+ private final String preparedReference;
+ private final Object value;
+
+ StubRowMapperFactory(String preparedReference, Object value) {
+ this.preparedReference = preparedReference;
+ this.value = value;
+ }
+
+ @Override
+ public RowMapper create(Class> result) {
+ return defaultRowMapper;
+ }
+
+ @Override
+ public RowMapper getRowMapper(String reference) {
+
+ if (preparedReference.equals(reference)) {
+ return (RowMapper) value;
+ }
+ return AbstractJdbcQuery.RowMapperFactory.super.getRowMapper(reference);
+ }
+
+ @Override
+ public ResultSetExtractor getResultSetExtractor(String reference) {
+
+ if (preparedReference.equals(reference)) {
+ return (ResultSetExtractor) value;
+ }
+ return AbstractJdbcQuery.RowMapperFactory.super.getResultSetExtractor(reference);
+ }
+ }
}
diff --git a/spring-data-r2dbc/pom.xml b/spring-data-r2dbc/pom.xml
index 3168f9d4f6..cc366a6efc 100644
--- a/spring-data-r2dbc/pom.xml
+++ b/spring-data-r2dbc/pom.xml
@@ -6,7 +6,7 @@
4.0.0
spring-data-r2dbc
- 3.4.0-SNAPSHOT
+ 3.4.0-1872-refactor-SBJQ-SNAPSHOT
Spring Data R2DBC
Spring Data module for R2DBC
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-relational-parent
- 3.4.0-SNAPSHOT
+ 3.4.0-1872-refactor-SBJQ-SNAPSHOT
diff --git a/spring-data-relational/pom.xml b/spring-data-relational/pom.xml
index 0287ece743..bbb9d4f4e0 100644
--- a/spring-data-relational/pom.xml
+++ b/spring-data-relational/pom.xml
@@ -6,7 +6,7 @@
4.0.0
spring-data-relational
- 3.4.0-SNAPSHOT
+ 3.4.0-1872-refactor-SBJQ-SNAPSHOT
Spring Data Relational
Spring Data Relational support
@@ -14,7 +14,7 @@
org.springframework.data
spring-data-relational-parent
- 3.4.0-SNAPSHOT
+ 3.4.0-1872-refactor-SBJQ-SNAPSHOT