Skip to content

Commit d2bb64f

Browse files
schaudermp911de
authored andcommitted
StringBasedJdbcQuery no longer requires BeanFactory.
The lookup is now performed by the `RowMapperFactory`. Closes #1872 Original pull request: #1874
1 parent 9e91a0e commit d2bb64f

File tree

4 files changed

+101
-35
lines changed

4 files changed

+101
-35
lines changed

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/AbstractJdbcQuery.java

+28
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import org.springframework.core.convert.converter.Converter;
2525
import org.springframework.dao.EmptyResultDataAccessException;
26+
import org.springframework.data.jdbc.core.convert.JdbcArrayColumns;
2627
import org.springframework.data.repository.query.RepositoryQuery;
2728
import org.springframework.data.repository.query.ResultProcessor;
2829
import org.springframework.data.repository.query.ReturnedType;
@@ -155,7 +156,34 @@ private <T> JdbcQueryExecution<T> createSingleReadingQueryExecution(ResultSetExt
155156
* @since 2.3
156157
*/
157158
public interface RowMapperFactory {
159+
160+
/**
161+
* Create a {@link RowMapper} based on the expected return type passed in as an argument.
162+
*
163+
* @param result must not be {@code null}.
164+
* @return a {@code RowMapper} producing instances of {@code result}.
165+
*/
158166
RowMapper<Object> create(Class<?> result);
167+
168+
/**
169+
* Obtain a {@code RowMapper} from some other source, typically a {@link org.springframework.beans.factory.BeanFactory}.
170+
*
171+
* @param reference must not be {@code null}.
172+
* @since 3.4
173+
*/
174+
default RowMapper<Object> rowMapperByReference(String reference) {
175+
throw new UnsupportedOperationException("rowMapperByReference is not supported");
176+
}
177+
178+
/**
179+
* Obtain a {@code ResultSetExtractor} from some other source, typically a {@link org.springframework.beans.factory.BeanFactory}.
180+
*
181+
* @param reference must not be {@code null}.
182+
* @since 3.4
183+
*/
184+
default ResultSetExtractor<Object> resultSetExtractorByReference(String reference) {
185+
throw new UnsupportedOperationException("resultSetExtractorByReference is not supported");
186+
}
159187
}
160188

161189
/**

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java

+2-13
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
7777
private final SpelEvaluator spelEvaluator;
7878
private final boolean containsSpelExpressions;
7979
private final String query;
80-
private BeanFactory beanFactory;
8180

8281
private final CachedRowMapperFactory cachedRowMapperFactory;
8382
private final CachedResultSetExtractorFactory cachedResultSetExtractorFactory;
@@ -353,10 +352,6 @@ private static boolean isUnconfigured(@Nullable Class<?> configuredClass, Class<
353352
return configuredClass == null || configuredClass == defaultClass;
354353
}
355354

356-
public void setBeanFactory(BeanFactory beanFactory) {
357-
this.beanFactory = beanFactory;
358-
}
359-
360355
class CachedRowMapperFactory {
361356

362357
private final Lazy<RowMapper<Object>> cachedRowMapper;
@@ -380,10 +375,7 @@ public CachedRowMapperFactory(Supplier<RowMapper<Object>> defaultMapper) {
380375
this.cachedRowMapper = Lazy.of(() -> {
381376

382377
if (!ObjectUtils.isEmpty(rowMapperRef)) {
383-
384-
Assert.notNull(beanFactory, "When a RowMapperRef is specified the BeanFactory must not be null");
385-
386-
return (RowMapper<Object>) beanFactory.getBean(rowMapperRef);
378+
return rowMapperFactory.rowMapperByReference(rowMapperRef);
387379
}
388380

389381
if (isUnconfigured(rowMapperClass, RowMapper.class)) {
@@ -434,10 +426,7 @@ public CachedResultSetExtractorFactory(Supplier<RowMapper<?>> resultSetExtractor
434426
this.resultSetExtractorFactory = rowMapper -> {
435427

436428
if (!ObjectUtils.isEmpty(resultSetExtractorRef)) {
437-
438-
Assert.notNull(beanFactory, "When a ResultSetExtractorRef is specified the BeanFactory must not be null");
439-
440-
return (ResultSetExtractor<Object>) beanFactory.getBean(resultSetExtractorRef);
429+
return rowMapperFactory.resultSetExtractorByReference(resultSetExtractorRef);
441430
}
442431

443432
if (isUnconfigured(resultSetExtractorClass, ResultSetExtractor.class)) {

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java

+27-4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.data.jdbc.core.convert.EntityRowMapper;
2727
import org.springframework.data.jdbc.core.convert.JdbcConverter;
2828
import org.springframework.data.jdbc.repository.QueryMappingConfiguration;
29+
import org.springframework.data.jdbc.repository.query.AbstractJdbcQuery;
2930
import org.springframework.data.jdbc.repository.query.JdbcQueryMethod;
3031
import org.springframework.data.jdbc.repository.query.PartTreeJdbcQuery;
3132
import org.springframework.data.jdbc.repository.query.StringBasedJdbcQuery;
@@ -42,6 +43,7 @@
4243
import org.springframework.data.repository.query.QueryLookupStrategy;
4344
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
4445
import org.springframework.data.repository.query.RepositoryQuery;
46+
import org.springframework.jdbc.core.ResultSetExtractor;
4547
import org.springframework.jdbc.core.RowMapper;
4648
import org.springframework.jdbc.core.SingleColumnRowMapper;
4749
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@@ -161,15 +163,36 @@ public RepositoryQuery resolveQuery(Method method, RepositoryMetadata repository
161163

162164
String queryString = evaluateTableExpressions(repositoryMetadata, queryMethod.getRequiredQuery());
163165

164-
StringBasedJdbcQuery query = new StringBasedJdbcQuery(queryString, queryMethod, getOperations(),
165-
this::createMapper, getConverter(), evaluationContextProvider);
166-
query.setBeanFactory(getBeanFactory());
167-
return query;
166+
return new StringBasedJdbcQuery(queryString, queryMethod, getOperations(),
167+
new BeanFactoryRowMapperFactory(getBeanFactory()), getConverter(), evaluationContextProvider);
168168
}
169169

170170
throw new IllegalStateException(
171171
String.format("Did neither find a NamedQuery nor an annotated query for method %s", method));
172172
}
173+
174+
private class BeanFactoryRowMapperFactory implements AbstractJdbcQuery.RowMapperFactory {
175+
176+
private final BeanFactory beanFactory;
177+
178+
BeanFactoryRowMapperFactory(BeanFactory beanFactory) {
179+
this.beanFactory = beanFactory;
180+
}
181+
@Override
182+
public RowMapper<Object> create(Class<?> result) {
183+
return createMapper(result);
184+
}
185+
186+
@Override
187+
public RowMapper<Object> rowMapperByReference(String reference) {
188+
return beanFactory.getBean(reference, RowMapper.class);
189+
}
190+
191+
@Override
192+
public ResultSetExtractor<Object> resultSetExtractorByReference(String reference) {
193+
return beanFactory.getBean(reference, ResultSetExtractor.class);
194+
}
195+
}
173196
}
174197

175198
/**

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java

+44-18
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.junit.jupiter.api.BeforeEach;
3434
import org.junit.jupiter.api.Test;
3535
import org.mockito.ArgumentCaptor;
36-
import org.springframework.beans.factory.BeanFactory;
3736
import org.springframework.core.convert.converter.Converter;
3837
import org.springframework.dao.DataAccessException;
3938
import org.springframework.data.convert.ReadingConverter;
@@ -163,14 +162,9 @@ void cachesCustomMapperAndExtractorInstances() {
163162
@Test // GH-1721
164163
void obtainsCustomRowMapperRef() {
165164

166-
BeanFactory beanFactory = mock(BeanFactory.class);
167-
JdbcQueryMethod queryMethod = createMethod("findAllCustomRowMapperRef");
168-
StringBasedJdbcQuery query = createQuery(queryMethod);
169-
query.setBeanFactory(beanFactory);
170-
171165
CustomRowMapper customRowMapper = new CustomRowMapper();
172-
173-
when(beanFactory.getBean("CustomRowMapper")).thenReturn(customRowMapper);
166+
JdbcQueryMethod queryMethod = createMethod("findAllCustomRowMapperRef");
167+
StringBasedJdbcQuery query = createQuery(queryMethod, "CustomRowMapper", customRowMapper);
174168

175169
RowMapper<?> rowMapper = query.determineRowMapper(queryMethod.getResultProcessor(), false);
176170
ResultSetExtractor<Object> resultSetExtractor = query.determineResultSetExtractor(() -> {
@@ -184,14 +178,9 @@ void obtainsCustomRowMapperRef() {
184178
@Test // GH-1721
185179
void obtainsCustomResultSetExtractorRef() {
186180

187-
BeanFactory beanFactory = mock(BeanFactory.class);
188-
JdbcQueryMethod queryMethod = createMethod("findAllCustomResultSetExtractorRef");
189-
StringBasedJdbcQuery query = createQuery(queryMethod);
190-
query.setBeanFactory(beanFactory);
191-
192181
CustomResultSetExtractor cre = new CustomResultSetExtractor();
193-
194-
when(beanFactory.getBean("CustomResultSetExtractor")).thenReturn(cre);
182+
JdbcQueryMethod queryMethod = createMethod("findAllCustomResultSetExtractorRef");
183+
StringBasedJdbcQuery query = createQuery(queryMethod, "CustomResultSetExtractor", cre);
195184

196185
RowMapper<?> rowMapper = query.determineRowMapper(queryMethod.getResultProcessor(), false);
197186
ResultSetExtractor<Object> resultSetExtractor = query.determineResultSetExtractor(() -> {
@@ -332,10 +321,10 @@ void queryByListOfTuples() {
332321
String[][] tuples = { new String[] { "Albert", "Einstein" }, new String[] { "Richard", "Feynman" } };
333322

334323
SqlParameterSource parameterSource = forMethod("findByListOfTuples", List.class) //
335-
.withArguments(Arrays.asList(tuples)) //
324+
.withArguments(Arrays.asList(tuples))//
336325
.extractParameterSource();
337326

338-
assertThat(parameterSource.getValue("tuples")).asInstanceOf(LIST) //
327+
assertThat(parameterSource.getValue("tuples")).asInstanceOf(LIST)//
339328
.containsExactly(tuples);
340329

341330
assertThat(parameterSource.getSqlType("tuples")).isEqualTo(JdbcUtil.TYPE_UNKNOWN.getVendorTypeNumber());
@@ -441,7 +430,11 @@ private JdbcQueryMethod createMethod(String methodName, Class<?>... paramTypes)
441430
}
442431

443432
private StringBasedJdbcQuery createQuery(JdbcQueryMethod queryMethod) {
444-
return new StringBasedJdbcQuery(queryMethod, operations, defaultRowMapper, converter, evaluationContextProvider);
433+
return createQuery(queryMethod, null, null);
434+
}
435+
436+
private StringBasedJdbcQuery createQuery(JdbcQueryMethod queryMethod, String preparedReference, Object value) {
437+
return new StringBasedJdbcQuery(queryMethod, operations, new StubRowMapperFactory(preparedReference, value), converter, evaluationContextProvider);
445438
}
446439

447440
interface MyRepository extends Repository<Object, Long> {
@@ -636,4 +629,37 @@ public Object getRootObject() {
636629
}
637630
}
638631

632+
private class StubRowMapperFactory implements AbstractJdbcQuery.RowMapperFactory {
633+
634+
private final String preparedReference;
635+
private final Object value;
636+
637+
StubRowMapperFactory(String preparedReference, Object value) {
638+
this.preparedReference = preparedReference;
639+
this.value = value;
640+
}
641+
642+
@Override
643+
public RowMapper<Object> create(Class<?> result) {
644+
return defaultRowMapper;
645+
}
646+
647+
@Override
648+
public RowMapper<Object> rowMapperByReference(String reference) {
649+
650+
if (preparedReference.equals(reference)) {
651+
return (RowMapper<Object>) value;
652+
}
653+
return AbstractJdbcQuery.RowMapperFactory.super.rowMapperByReference(reference);
654+
}
655+
656+
@Override
657+
public ResultSetExtractor<Object> resultSetExtractorByReference(String reference) {
658+
659+
if (preparedReference.equals(reference)) {
660+
return (ResultSetExtractor<Object>) value;
661+
}
662+
return AbstractJdbcQuery.RowMapperFactory.super.resultSetExtractorByReference(reference);
663+
}
664+
}
639665
}

0 commit comments

Comments
 (0)