StringBasedJdbcQuery no longer requires BeanFactory.
The lookup is now performed by the `RowMapperFactory`. Closes #1872 Original pull request: #1874
This commit is contained in:
committed by
Mark Paluch
parent
9e91a0e7a5
commit
d2bb64f4ca
@@ -23,6 +23,7 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcArrayColumns;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.ResultProcessor;
|
||||
import org.springframework.data.repository.query.ReturnedType;
|
||||
@@ -155,7 +156,34 @@ public abstract class AbstractJdbcQuery implements RepositoryQuery {
|
||||
* @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<Object> 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<Object> rowMapperByReference(String reference) {
|
||||
throw new UnsupportedOperationException("rowMapperByReference 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<Object> resultSetExtractorByReference(String reference) {
|
||||
throw new UnsupportedOperationException("resultSetExtractorByReference is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,10 +352,6 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
|
||||
return configuredClass == null || configuredClass == defaultClass;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
class CachedRowMapperFactory {
|
||||
|
||||
private final Lazy<RowMapper<Object>> cachedRowMapper;
|
||||
@@ -380,10 +375,7 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
|
||||
this.cachedRowMapper = Lazy.of(() -> {
|
||||
|
||||
if (!ObjectUtils.isEmpty(rowMapperRef)) {
|
||||
|
||||
Assert.notNull(beanFactory, "When a RowMapperRef is specified the BeanFactory must not be null");
|
||||
|
||||
return (RowMapper<Object>) beanFactory.getBean(rowMapperRef);
|
||||
return rowMapperFactory.rowMapperByReference(rowMapperRef);
|
||||
}
|
||||
|
||||
if (isUnconfigured(rowMapperClass, RowMapper.class)) {
|
||||
@@ -434,10 +426,7 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
|
||||
this.resultSetExtractorFactory = rowMapper -> {
|
||||
|
||||
if (!ObjectUtils.isEmpty(resultSetExtractorRef)) {
|
||||
|
||||
Assert.notNull(beanFactory, "When a ResultSetExtractorRef is specified the BeanFactory must not be null");
|
||||
|
||||
return (ResultSetExtractor<Object>) beanFactory.getBean(resultSetExtractorRef);
|
||||
return rowMapperFactory.resultSetExtractorByReference(resultSetExtractorRef);
|
||||
}
|
||||
|
||||
if (isUnconfigured(resultSetExtractorClass, ResultSetExtractor.class)) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.context.ApplicationEventPublisher;
|
||||
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.core.RepositoryMetadata;
|
||||
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;
|
||||
@@ -161,15 +163,36 @@ abstract class JdbcQueryLookupStrategy extends RelationalQueryLookupStrategy {
|
||||
|
||||
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(),
|
||||
new BeanFactoryRowMapperFactory(getBeanFactory()), getConverter(), evaluationContextProvider);
|
||||
}
|
||||
|
||||
throw new IllegalStateException(
|
||||
String.format("Did neither find a NamedQuery nor an annotated query for method %s", method));
|
||||
}
|
||||
|
||||
private class BeanFactoryRowMapperFactory implements AbstractJdbcQuery.RowMapperFactory {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
BeanFactoryRowMapperFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
@Override
|
||||
public RowMapper<Object> create(Class<?> result) {
|
||||
return createMapper(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<Object> rowMapperByReference(String reference) {
|
||||
return beanFactory.getBean(reference, RowMapper.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSetExtractor<Object> resultSetExtractorByReference(String reference) {
|
||||
return beanFactory.getBean(reference, ResultSetExtractor.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.assertj.core.api.Assertions;
|
||||
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 @@ class StringBasedJdbcQueryUnitTests {
|
||||
@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<Object> resultSetExtractor = query.determineResultSetExtractor(() -> {
|
||||
@@ -184,14 +178,9 @@ class StringBasedJdbcQueryUnitTests {
|
||||
@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<Object> resultSetExtractor = query.determineResultSetExtractor(() -> {
|
||||
@@ -332,10 +321,10 @@ class StringBasedJdbcQueryUnitTests {
|
||||
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 @@ class StringBasedJdbcQueryUnitTests {
|
||||
}
|
||||
|
||||
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<Object, Long> {
|
||||
@@ -636,4 +629,37 @@ class StringBasedJdbcQueryUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
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<Object> create(Class<?> result) {
|
||||
return defaultRowMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<Object> rowMapperByReference(String reference) {
|
||||
|
||||
if (preparedReference.equals(reference)) {
|
||||
return (RowMapper<Object>) value;
|
||||
}
|
||||
return AbstractJdbcQuery.RowMapperFactory.super.rowMapperByReference(reference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSetExtractor<Object> resultSetExtractorByReference(String reference) {
|
||||
|
||||
if (preparedReference.equals(reference)) {
|
||||
return (ResultSetExtractor<Object>) value;
|
||||
}
|
||||
return AbstractJdbcQuery.RowMapperFactory.super.resultSetExtractorByReference(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user