StringBasedJdbcQuery no longer requires BeanFactory.

The lookup is now performed by the `RowMapperFactory`.

Closes #1872
Original pull request: #1874
This commit is contained in:
Jens Schauder
2024-09-06 10:35:28 +02:00
committed by Mark Paluch
parent 9e91a0e7a5
commit d2bb64f4ca
4 changed files with 101 additions and 35 deletions

View File

@@ -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");
}
}
/**

View File

@@ -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)) {

View File

@@ -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);
}
}
}
/**