DATAJDBC-290 - Polishing.
Naming, formatting, and code structure improved. Original pull request: #101.
This commit is contained in:
@@ -1,24 +1,28 @@
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import org.springframework.data.jdbc.support.RowMapperResultsetExtractorEither;
|
||||
import org.springframework.data.jdbc.support.RowMapperOrResultsetExtractor;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A map from a type to a {@link ResultSetExtractor} to be used for extracting that type from {@link java.sql.ResultSet}s.
|
||||
* Configures a {@link org.springframework.jdbc.core.RowMapper} or a {@link ResultSetExtractor} for each type to be used
|
||||
* for extracting entities of that type from a {@link java.sql.ResultSet}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Evgeni Dimitrov
|
||||
*/
|
||||
public interface QueryMappingConfiguration {
|
||||
<T> RowMapperResultsetExtractorEither<?> getMapper(Class<T> type);
|
||||
|
||||
|
||||
@Nullable
|
||||
<T> RowMapperOrResultsetExtractor<?> getMapperOrExtractor(Class<T> type);
|
||||
|
||||
/**
|
||||
* An immutable empty instance that will return {@literal null} for all arguments.
|
||||
*/
|
||||
QueryMappingConfiguration EMPTY = new QueryMappingConfiguration() {
|
||||
|
||||
@Override
|
||||
public <T> RowMapperResultsetExtractorEither<?> getMapper(Class<T> type) {
|
||||
public <T> RowMapperOrResultsetExtractor<?> getMapperOrExtractor(Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,28 +4,33 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.jdbc.repository.QueryMappingConfiguration;
|
||||
import org.springframework.data.jdbc.support.RowMapperResultsetExtractorEither;
|
||||
import org.springframework.data.jdbc.support.RowMapperOrResultsetExtractor;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link QueryMappingConfiguration} that allows for registration of {@link RowMapper}s and {@link ResultSetExtractor}s via a fluent Api.
|
||||
* A {@link QueryMappingConfiguration} that allows for registration of {@link RowMapper}s and
|
||||
* {@link ResultSetExtractor}s via a fluent Api.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Evgeni Dimitrov
|
||||
*/
|
||||
public class DefaultQueryMappingConfiguration implements QueryMappingConfiguration{
|
||||
private Map<Class<?>, RowMapperResultsetExtractorEither<?>> mappers = new LinkedHashMap<>();
|
||||
public class DefaultQueryMappingConfiguration implements QueryMappingConfiguration {
|
||||
|
||||
private Map<Class<?>, RowMapperOrResultsetExtractor<?>> mappers = new LinkedHashMap<>();
|
||||
|
||||
@Nullable
|
||||
public <T> RowMapperOrResultsetExtractor<?> getMapperOrExtractor(Class<T> type) {
|
||||
|
||||
public <T> RowMapperResultsetExtractorEither<?> getMapper(Class<T> type) {
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
RowMapperResultsetExtractorEither<?> candidate = mappers.get(type);
|
||||
RowMapperOrResultsetExtractor<?> candidate = mappers.get(type);
|
||||
|
||||
if (candidate == null) {
|
||||
|
||||
for (Map.Entry<Class<?>, RowMapperResultsetExtractorEither<?>> entry : mappers.entrySet()) {
|
||||
for (Map.Entry<Class<?>, RowMapperOrResultsetExtractor<?>> entry : mappers.entrySet()) {
|
||||
|
||||
if (type.isAssignableFrom(entry.getKey())) {
|
||||
candidate = entry.getValue();
|
||||
@@ -41,17 +46,22 @@ public class DefaultQueryMappingConfiguration implements QueryMappingConfigurati
|
||||
* @return this instance, so this can be used as a fluent interface.
|
||||
*/
|
||||
public <T> DefaultQueryMappingConfiguration registerRowMapper(Class<T> type, RowMapper<? extends T> rowMapper) {
|
||||
mappers.put(type, RowMapperResultsetExtractorEither.of(rowMapper));
|
||||
|
||||
mappers.put(type, RowMapperOrResultsetExtractor.of(rowMapper));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers a the given {@link ResultSetExtractor} as to be used for the given type.
|
||||
*
|
||||
* @return this instance, so this can be used as a fluent interface.
|
||||
*/
|
||||
public <T> DefaultQueryMappingConfiguration registerResultSetExtractor(Class<T> type, ResultSetExtractor resultSetExtractor) {
|
||||
mappers.put(type, RowMapperResultsetExtractorEither.of(resultSetExtractor));
|
||||
public <T> DefaultQueryMappingConfiguration registerResultSetExtractor(Class<T> type,
|
||||
ResultSetExtractor resultSetExtractor) {
|
||||
|
||||
mappers.put(type, RowMapperOrResultsetExtractor.of(resultSetExtractor));
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,14 +44,14 @@ public @interface Query {
|
||||
String value();
|
||||
|
||||
/**
|
||||
* Optional {@link RowMapper} to use to convert the result of the query to domain class instances.
|
||||
* Cannot be used along with {@link #resultSetExtractorClass()} only one of the two can be set.
|
||||
* Optional {@link RowMapper} to use to convert the result of the query to domain class instances. Cannot be used
|
||||
* along with {@link #resultSetExtractorClass()} only one of the two can be set.
|
||||
*/
|
||||
Class<? extends RowMapper> rowMapperClass() default RowMapper.class;
|
||||
|
||||
|
||||
/**
|
||||
* Optional {@link ResultSetExtractor} to use to convert the result of the query to domain class instances.
|
||||
* Cannot be used along with {@link #rowMapperClass()} only one of the two can be set.
|
||||
* Optional {@link ResultSetExtractor} to use to convert the result of the query to domain class instances. Cannot be
|
||||
* used along with {@link #rowMapperClass()} only one of the two can be set.
|
||||
*/
|
||||
Class<? extends ResultSetExtractor> resultSetExtractorClass() default ResultSetExtractor.class;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package org.springframework.data.jdbc.repository.support;
|
||||
|
||||
import org.springframework.data.jdbc.repository.query.Query;
|
||||
|
||||
/**
|
||||
* Exception thrown when both {@link Query#resultSetExtractorClass()} and {@link Query#rowMapperClass()} are used in one {@link Query}.
|
||||
*
|
||||
* @author Evgeni Dimitrov
|
||||
*/
|
||||
public class InvalidQueryConfiguration extends RuntimeException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6604189906427682546L;
|
||||
|
||||
public InvalidQueryConfiguration(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.data.jdbc.core.DataAccessStrategy;
|
||||
import org.springframework.data.jdbc.core.EntityRowMapper;
|
||||
import org.springframework.data.jdbc.repository.QueryMappingConfiguration;
|
||||
import org.springframework.data.jdbc.support.RowMapperResultsetExtractorEither;
|
||||
import org.springframework.data.jdbc.support.RowMapperOrResultsetExtractor;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
@@ -30,8 +30,6 @@ import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
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;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -51,7 +49,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
private final RelationalMappingContext context;
|
||||
private final RelationalConverter converter;
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
private final QueryMappingConfiguration mapperMap;
|
||||
private final QueryMappingConfiguration queryMappingConfiguration;
|
||||
private final NamedParameterJdbcOperations operations;
|
||||
|
||||
/**
|
||||
@@ -62,22 +60,23 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
* @param context must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
* @param accessStrategy must not be {@literal null}.
|
||||
* @param rowMapperMap must not be {@literal null}.
|
||||
* @param queryMappingConfiguration must not be {@literal null}.
|
||||
*/
|
||||
JdbcQueryLookupStrategy(ApplicationEventPublisher publisher, RelationalMappingContext context, RelationalConverter converter,
|
||||
DataAccessStrategy accessStrategy, QueryMappingConfiguration rowMapperMap, NamedParameterJdbcOperations operations) {
|
||||
JdbcQueryLookupStrategy(ApplicationEventPublisher publisher, RelationalMappingContext context,
|
||||
RelationalConverter converter, DataAccessStrategy accessStrategy,
|
||||
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations) {
|
||||
|
||||
Assert.notNull(publisher, "Publisher must not be null!");
|
||||
Assert.notNull(context, "RelationalMappingContext must not be null!");
|
||||
Assert.notNull(converter, "RelationalConverter must not be null!");
|
||||
Assert.notNull(accessStrategy, "DataAccessStrategy must not be null!");
|
||||
Assert.notNull(rowMapperMap, "RowMapperMap must not be null!");
|
||||
Assert.notNull(queryMappingConfiguration, "RowMapperMap must not be null!");
|
||||
|
||||
this.publisher = publisher;
|
||||
this.context = context;
|
||||
this.converter = converter;
|
||||
this.accessStrategy = accessStrategy;
|
||||
this.mapperMap = rowMapperMap;
|
||||
this.queryMappingConfiguration = queryMappingConfiguration;
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
@@ -91,35 +90,39 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
|
||||
JdbcQueryMethod queryMethod = new JdbcQueryMethod(method, repositoryMetadata, projectionFactory);
|
||||
|
||||
RowMapperResultsetExtractorEither<?> mapper = queryMethod.isModifyingQuery() ? null : createMapper(queryMethod);
|
||||
RowMapperOrResultsetExtractor<?> mapper = queryMethod.isModifyingQuery() ? null : createMapper(queryMethod);
|
||||
|
||||
return new JdbcRepositoryQuery(publisher, context, queryMethod, operations, mapper);
|
||||
}
|
||||
|
||||
private RowMapperResultsetExtractorEither<?> createMapper(JdbcQueryMethod queryMethod) {
|
||||
private RowMapperOrResultsetExtractor<?> createMapper(JdbcQueryMethod queryMethod) {
|
||||
|
||||
Class<?> returnedObjectType = queryMethod.getReturnedObjectType();
|
||||
|
||||
RelationalPersistentEntity<?> persistentEntity = context.getPersistentEntity(returnedObjectType);
|
||||
|
||||
if (persistentEntity == null) {
|
||||
return RowMapperResultsetExtractorEither.of(
|
||||
SingleColumnRowMapper.newInstance(returnedObjectType, converter.getConversionService()));
|
||||
return RowMapperOrResultsetExtractor
|
||||
.of(SingleColumnRowMapper.newInstance(returnedObjectType, converter.getConversionService()));
|
||||
}
|
||||
|
||||
return determineDefaultMapper(queryMethod);
|
||||
}
|
||||
|
||||
private RowMapperResultsetExtractorEither<?> determineDefaultMapper(JdbcQueryMethod queryMethod) {
|
||||
private RowMapperOrResultsetExtractor<?> determineDefaultMapper(JdbcQueryMethod queryMethod) {
|
||||
|
||||
Class<?> domainType = queryMethod.getReturnedObjectType();
|
||||
RowMapperResultsetExtractorEither<?> configuredQueryMapper = mapperMap.getMapper(domainType);
|
||||
if(configuredQueryMapper != null) return configuredQueryMapper;
|
||||
|
||||
RowMapperOrResultsetExtractor<?> configuredQueryMapper = queryMappingConfiguration.getMapperOrExtractor(domainType);
|
||||
|
||||
if (configuredQueryMapper != null)
|
||||
return configuredQueryMapper;
|
||||
|
||||
EntityRowMapper<?> defaultEntityRowMapper = new EntityRowMapper<>( //
|
||||
context.getRequiredPersistentEntity(domainType), //
|
||||
context, //
|
||||
converter, //
|
||||
accessStrategy);
|
||||
return RowMapperResultsetExtractorEither.of(defaultEntityRowMapper);
|
||||
|
||||
return RowMapperOrResultsetExtractor.of(defaultEntityRowMapper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class JdbcQueryMethod extends QueryMethod {
|
||||
public Class<?> getRowMapperClass() {
|
||||
return getMergedAnnotationAttribute("rowMapperClass");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the class to be used as {@link org.springframework.jdbc.core.ResultSetExtractor}
|
||||
*
|
||||
|
||||
@@ -51,7 +51,7 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
private final NamedParameterJdbcOperations operations;
|
||||
|
||||
private QueryMappingConfiguration mapperMap = QueryMappingConfiguration.EMPTY;
|
||||
private QueryMappingConfiguration queryMappingConfiguration = QueryMappingConfiguration.EMPTY;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JdbcRepositoryFactory} for the given {@link DataAccessStrategy},
|
||||
@@ -79,13 +79,14 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rowMapperMap must not be {@literal null} consider {@link RowMapperMap#EMPTY} instead.
|
||||
* @param queryMappingConfiguration must not be {@literal null} consider {@link QueryMappingConfiguration#EMPTY}
|
||||
* instead.
|
||||
*/
|
||||
public void setRowMapperMap(QueryMappingConfiguration rowMapperMap) {
|
||||
public void setQueryMappingConfiguration(QueryMappingConfiguration queryMappingConfiguration) {
|
||||
|
||||
Assert.notNull(rowMapperMap, "RowMapperMap must not be null!");
|
||||
Assert.notNull(queryMappingConfiguration, "QueryMappingConfiguration must not be null!");
|
||||
|
||||
this.mapperMap = rowMapperMap;
|
||||
this.queryMappingConfiguration = queryMappingConfiguration;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -133,6 +134,7 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
|
||||
throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key));
|
||||
}
|
||||
|
||||
return Optional.of(new JdbcQueryLookupStrategy(publisher, context, converter, accessStrategy, mapperMap, operations));
|
||||
return Optional.of(new JdbcQueryLookupStrategy(publisher, context, converter, accessStrategy,
|
||||
queryMappingConfiguration, operations));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
private RelationalMappingContext mappingContext;
|
||||
private RelationalConverter converter;
|
||||
private DataAccessStrategy dataAccessStrategy;
|
||||
private QueryMappingConfiguration mapperMap = QueryMappingConfiguration.EMPTY;
|
||||
private QueryMappingConfiguration queryMappingConfiguration = QueryMappingConfiguration.EMPTY;
|
||||
private NamedParameterJdbcOperations operations;
|
||||
|
||||
/**
|
||||
@@ -81,7 +81,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
|
||||
JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(dataAccessStrategy, mappingContext,
|
||||
converter, publisher, operations);
|
||||
jdbcRepositoryFactory.setRowMapperMap(mapperMap);
|
||||
jdbcRepositoryFactory.setQueryMappingConfiguration(queryMappingConfiguration);
|
||||
|
||||
return jdbcRepositoryFactory;
|
||||
}
|
||||
@@ -102,12 +102,12 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rowMapperMap can be {@literal null}. {@link #afterPropertiesSet()} defaults to {@link RowMapperMap#EMPTY} if
|
||||
* {@literal null}.
|
||||
* @param rowMapperMap can be {@literal null}. {@link #afterPropertiesSet()} defaults to
|
||||
* {@link QueryMappingConfiguration#EMPTY} if {@literal null}.
|
||||
*/
|
||||
@Autowired(required = false)
|
||||
public void setRowMapperMap(QueryMappingConfiguration rowMapperMap) {
|
||||
this.mapperMap = rowMapperMap;
|
||||
public void setQueryMappingConfiguration(QueryMappingConfiguration rowMapperMap) {
|
||||
this.queryMappingConfiguration = rowMapperMap;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@@ -137,8 +137,8 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
operations);
|
||||
}
|
||||
|
||||
if (mapperMap == null) {
|
||||
this.mapperMap = QueryMappingConfiguration.EMPTY;
|
||||
if (queryMappingConfiguration == null) {
|
||||
this.queryMappingConfiguration = QueryMappingConfiguration.EMPTY;
|
||||
}
|
||||
|
||||
super.afterPropertiesSet();
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.data.jdbc.support.RowMapperResultsetExtractorEither;
|
||||
import org.springframework.data.jdbc.support.RowMapperOrResultsetExtractor;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterLoadEvent;
|
||||
@@ -32,8 +34,6 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A query to be executed based on a repository method, it's annotated SQL query and the arguments provided to the
|
||||
* method.
|
||||
@@ -51,7 +51,8 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
private final RelationalMappingContext context;
|
||||
private final JdbcQueryMethod queryMethod;
|
||||
private final NamedParameterJdbcOperations operations;
|
||||
private final RowMapperResultsetExtractorEither<?> mapper;
|
||||
|
||||
@Nullable private final RowMapperOrResultsetExtractor<?> mapperOrExtractor;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JdbcRepositoryQuery} for the given {@link JdbcQueryMethod}, {@link RelationalMappingContext}
|
||||
@@ -61,10 +62,11 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
* @param context must not be {@literal null}.
|
||||
* @param queryMethod must not be {@literal null}.
|
||||
* @param operations must not be {@literal null}.
|
||||
* @param defaultRowMapper can be {@literal null} (only in case of a modifying query).
|
||||
* @param defaultMapper can be {@literal null} (only in case of a modifying query).
|
||||
*/
|
||||
JdbcRepositoryQuery(ApplicationEventPublisher publisher, RelationalMappingContext context, JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
|
||||
@Nullable RowMapperResultsetExtractorEither<?> defaultMapper) {
|
||||
JdbcRepositoryQuery(ApplicationEventPublisher publisher, RelationalMappingContext context,
|
||||
JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
|
||||
@Nullable RowMapperOrResultsetExtractor<?> defaultMapper) {
|
||||
|
||||
Assert.notNull(publisher, "Publisher must not be null!");
|
||||
Assert.notNull(context, "Context must not be null!");
|
||||
@@ -79,7 +81,7 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
this.context = context;
|
||||
this.queryMethod = queryMethod;
|
||||
this.operations = operations;
|
||||
this.mapper = determineMapper(defaultMapper);
|
||||
this.mapperOrExtractor = determineMapper(defaultMapper);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -100,26 +102,31 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
: updatedCount;
|
||||
}
|
||||
|
||||
assert this.mapperOrExtractor != null;
|
||||
|
||||
if (queryMethod.isCollectionQuery() || queryMethod.isStreamQuery()) {
|
||||
List<?> result = null;
|
||||
if(this.mapper.isResultSetExtractor()) {
|
||||
result = (List<?>) operations.query(query, parameters, this.mapper.resultSetExtractor());
|
||||
} else {
|
||||
result = operations.query(query, parameters, this.mapper.rowMapper());
|
||||
}
|
||||
|
||||
List<?> result = this.mapperOrExtractor.isResultSetExtractor()
|
||||
? (List<?>) operations.query(query, parameters, this.mapperOrExtractor.getResultSetExtractor())
|
||||
: operations.query(query, parameters, this.mapperOrExtractor.getRowMapper());
|
||||
|
||||
Assert.notNull(result, "A collection valued result must never be null.");
|
||||
|
||||
publishAfterLoad(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
Object result = null;
|
||||
if(this.mapper.isResultSetExtractor()) {
|
||||
result = operations.query(query,parameters, this.mapper.resultSetExtractor());
|
||||
} else {
|
||||
result = operations.queryForObject(query, parameters, this.mapper.rowMapper());
|
||||
}
|
||||
|
||||
Object result = this.mapperOrExtractor.isResultSetExtractor()
|
||||
? operations.query(query, parameters, this.mapperOrExtractor.getResultSetExtractor())
|
||||
: operations.queryForObject(query, parameters, this.mapperOrExtractor.getRowMapper());
|
||||
|
||||
publishAfterLoad(result);
|
||||
|
||||
return result;
|
||||
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
@@ -158,30 +165,51 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private RowMapperResultsetExtractorEither<?> determineMapper(RowMapperResultsetExtractorEither<?> defaultMapper) {
|
||||
RowMapperResultsetExtractorEither<?> configuredMapper = getConfiguredMapper(queryMethod);
|
||||
if(configuredMapper != null) return configuredMapper;
|
||||
return defaultMapper;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static RowMapperResultsetExtractorEither<?> getConfiguredMapper(JdbcQueryMethod queryMethod) {
|
||||
private RowMapperOrResultsetExtractor<?> determineMapper(@Nullable RowMapperOrResultsetExtractor<?> defaultMapper) {
|
||||
|
||||
RowMapperOrResultsetExtractor<?> configuredMapper = getConfiguredMapper(queryMethod);
|
||||
|
||||
return (configuredMapper == null) ? defaultMapper : configuredMapper;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static RowMapperOrResultsetExtractor<?> getConfiguredMapper(JdbcQueryMethod queryMethod) {
|
||||
|
||||
Class<?> rowMapperClass = queryMethod.getRowMapperClass();
|
||||
Class<?> resultSetExtractorClass = queryMethod.getResultSetExtractorClass();
|
||||
if(isConfigured(rowMapperClass, RowMapper.class) && isConfigured(resultSetExtractorClass, ResultSetExtractor.class))
|
||||
throw new InvalidQueryConfiguration("Cannot use both rowMapperClass and resultSetExtractorClass on @Query annotation. Query method: [" + queryMethod.getName() + "] query: [" + queryMethod.getAnnotatedQuery() + "]");
|
||||
|
||||
if(!isConfigured(rowMapperClass, RowMapper.class) && !isConfigured(resultSetExtractorClass, ResultSetExtractor.class))
|
||||
return null;
|
||||
if(isConfigured(rowMapperClass, RowMapper.class)) {
|
||||
return RowMapperResultsetExtractorEither.of((RowMapper<?>) BeanUtils.instantiateClass(rowMapperClass));
|
||||
} else {
|
||||
return RowMapperResultsetExtractorEither.of((ResultSetExtractor<?>) BeanUtils.instantiateClass(resultSetExtractorClass));
|
||||
|
||||
assertOnlyOneIsConfigured(queryMethod, rowMapperClass, resultSetExtractorClass);
|
||||
|
||||
if (isConfigured(rowMapperClass, RowMapper.class)) {
|
||||
return RowMapperOrResultsetExtractor.of((RowMapper<?>) BeanUtils.instantiateClass(rowMapperClass));
|
||||
}
|
||||
|
||||
if (isConfigured(resultSetExtractorClass, ResultSetExtractor.class)) {
|
||||
return RowMapperOrResultsetExtractor
|
||||
.of((ResultSetExtractor<?>) BeanUtils.instantiateClass(resultSetExtractorClass));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void assertOnlyOneIsConfigured(JdbcQueryMethod queryMethod, @Nullable Class<?> rowMapperClass,
|
||||
@Nullable Class<?> resultSetExtractorClass) {
|
||||
|
||||
if (isConfigured(rowMapperClass, RowMapper.class)
|
||||
&& isConfigured(resultSetExtractorClass, ResultSetExtractor.class)) {
|
||||
|
||||
throw new IllegalStateException( //
|
||||
String.format( //
|
||||
"Cannot use both rowMapperClass and resultSetExtractorClass on @Query annotation. Query // method: [%s] query: [%s]",
|
||||
queryMethod.getName(), //
|
||||
queryMethod.getAnnotatedQuery() //
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isConfigured(Class<?> rowMapperClass, Class<?> defaultClass) {
|
||||
return rowMapperClass != null && rowMapperClass != defaultClass;
|
||||
private static boolean isConfigured(@Nullable Class<?> configuredClass, Class<?> defaultClass) {
|
||||
return configuredClass != null && configuredClass != defaultClass;
|
||||
}
|
||||
|
||||
private <T> void publishAfterLoad(Iterable<T> all) {
|
||||
@@ -196,8 +224,7 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
if (entity != null && context.hasPersistentEntityFor(entity.getClass())) {
|
||||
|
||||
RelationalPersistentEntity<?> e = context.getRequiredPersistentEntity(entity.getClass());
|
||||
Object identifier = e.getIdentifierAccessor(entity)
|
||||
.getIdentifier();
|
||||
Object identifier = e.getIdentifierAccessor(entity).getIdentifier();
|
||||
|
||||
if (identifier != null) {
|
||||
publisher.publishEvent(new AfterLoadEvent(Identifier.of(identifier), entity));
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.springframework.data.jdbc.support;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
* Represents either a RowMapper or a ResultSetExtractor
|
||||
*
|
||||
* @author Evgeni Dimitrov
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@Value
|
||||
public class RowMapperOrResultsetExtractor<T> {
|
||||
|
||||
private final RowMapper<T> rowMapper;
|
||||
private final ResultSetExtractor<T> resultSetExtractor;
|
||||
|
||||
private RowMapperOrResultsetExtractor(RowMapper<T> rowMapper, ResultSetExtractor<T> resultSetExtractor) {
|
||||
|
||||
this.rowMapper = rowMapper;
|
||||
this.resultSetExtractor = resultSetExtractor;
|
||||
}
|
||||
|
||||
public static RowMapperOrResultsetExtractor<?> of(RowMapper<?> rowMapper) {
|
||||
return new RowMapperOrResultsetExtractor<>(rowMapper, null);
|
||||
}
|
||||
|
||||
public static RowMapperOrResultsetExtractor<?> of(ResultSetExtractor<?> resultSetExtractor) {
|
||||
return new RowMapperOrResultsetExtractor<>(null, resultSetExtractor);
|
||||
}
|
||||
|
||||
public boolean isRowMapper() {
|
||||
return this.rowMapper != null;
|
||||
}
|
||||
|
||||
public boolean isResultSetExtractor() {
|
||||
return this.resultSetExtractor != null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package org.springframework.data.jdbc.support;
|
||||
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
/**
|
||||
* Represents either a RowMapper or a ResultSetExtractor
|
||||
*
|
||||
* @author Evgeni Dimitrov
|
||||
*/
|
||||
public class RowMapperResultsetExtractorEither<T> {
|
||||
private final RowMapper<T> rowMapper;
|
||||
private final ResultSetExtractor<T> resultSetExtractor;
|
||||
|
||||
private RowMapperResultsetExtractorEither(RowMapper<T> rowMapper, ResultSetExtractor<T> resultSetExtractor) {
|
||||
this.rowMapper = rowMapper;
|
||||
this.resultSetExtractor = resultSetExtractor;
|
||||
}
|
||||
|
||||
public static RowMapperResultsetExtractorEither<?> of(RowMapper<?> rowMapper) {
|
||||
return new RowMapperResultsetExtractorEither<>(rowMapper, null);
|
||||
}
|
||||
|
||||
public boolean isRowMapper() {
|
||||
return this.rowMapper != null;
|
||||
}
|
||||
|
||||
public RowMapper<?> rowMapper() {
|
||||
return this.rowMapper;
|
||||
}
|
||||
|
||||
public static RowMapperResultsetExtractorEither<?> of(ResultSetExtractor<?> resultSetExtractor) {
|
||||
return new RowMapperResultsetExtractorEither<>(null, resultSetExtractor);
|
||||
}
|
||||
|
||||
public boolean isResultSetExtractor() {
|
||||
return this.resultSetExtractor != null;
|
||||
}
|
||||
|
||||
public ResultSetExtractor<?> resultSetExtractor() {
|
||||
return this.resultSetExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("RowMapperResultsetExtractorEither[%s]", this.rowMapper != null ? this.rowMapper : this.resultSetExtractor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((resultSetExtractor == null) ? 0 : resultSetExtractor.hashCode());
|
||||
result = prime * result + ((rowMapper == null) ? 0 : rowMapper.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
RowMapperResultsetExtractorEither other = (RowMapperResultsetExtractorEither) obj;
|
||||
if (resultSetExtractor == null) {
|
||||
if (other.resultSetExtractor != null) return false;
|
||||
} else {
|
||||
if (!resultSetExtractor.equals(other.resultSetExtractor)) return false;
|
||||
}
|
||||
if (rowMapper == null) {
|
||||
if (other.rowMapper != null) return false;
|
||||
} else {
|
||||
if (!rowMapper.equals(other.rowMapper)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,7 +54,9 @@ import lombok.Data;
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
public class JdbcRepositoryMapperMapResultSetExtractorIntegrationTests {
|
||||
private static String CAR_MODEL = "ResultSetExtracotr Car";
|
||||
|
||||
private static String CAR_MODEL = "ResultSetExtractor Car";
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
@EnableJdbcRepositories(considerNestedRepositories = true)
|
||||
@@ -80,21 +82,25 @@ public class JdbcRepositoryMapperMapResultSetExtractorIntegrationTests {
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
public void customFindAllCarsPicksResultSetExtractorFromMapperMap() {
|
||||
|
||||
carRepository.save(new Car(null, "Some model"));
|
||||
Iterable<Car> cars = carRepository.customFindAll();
|
||||
|
||||
assertThat(cars).hasSize(1);
|
||||
assertThat(cars).allMatch(car -> CAR_MODEL.equals(car.getModel()));
|
||||
}
|
||||
|
||||
interface CarRepository extends CrudRepository<Car, Long> {
|
||||
|
||||
@Query("select * from car")
|
||||
public List<Car> customFindAll();
|
||||
List<Car> customFindAll();
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
static class Car {
|
||||
@Id
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
private String model;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
@@ -47,9 +50,6 @@ import org.springframework.test.context.junit4.rules.SpringClassRule;
|
||||
import org.springframework.test.context.junit4.rules.SpringMethodRule;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Very simple use cases for creation and usage of {@link ResultSetExtractor}s in JdbcRepository.
|
||||
*
|
||||
@@ -58,6 +58,7 @@ import lombok.Data;
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
public class JdbcRepositoryResultSetExtractorIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
static class Config {
|
||||
@@ -84,88 +85,109 @@ public class JdbcRepositoryResultSetExtractorIntegrationTests {
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
public void findAllPeopleWithAdressesReturnsEmptyWhenNoneFound() {
|
||||
|
||||
// NOT saving anything, so DB is empty
|
||||
|
||||
assertThat(personRepository.findAllPeopleWithAdresses()).isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
public void findAllPeopleWithAdressesReturnsOnePersonWithoutAdresses() {
|
||||
|
||||
personRepository.save(new Person(null, "Joe", null));
|
||||
|
||||
assertThat(personRepository.findAllPeopleWithAdresses()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
public void findAllPeopleWithAdressesReturnsOnePersonWithAdresses() {
|
||||
|
||||
final String personName = "Joe";
|
||||
Person savedPerson = personRepository.save(new Person(null, personName, null));
|
||||
String street1 = "Klokotnitsa";
|
||||
|
||||
String street1 = "Some Street";
|
||||
String street2 = "Some other Street";
|
||||
|
||||
MapSqlParameterSource paramsAddress1 = buildAddressParameters(savedPerson.getId(), street1);
|
||||
template.update("insert into address (street, person_id) values (:street, :personId)",paramsAddress1);
|
||||
String street2 = "bul. Hristo Botev";
|
||||
template.update("insert into address (street, person_id) values (:street, :personId)", paramsAddress1);
|
||||
|
||||
MapSqlParameterSource paramsAddress2 = buildAddressParameters(savedPerson.getId(), street2);
|
||||
template.update("insert into address (street, person_id) values (:street, :personId)",paramsAddress2);
|
||||
|
||||
template.update("insert into address (street, person_id) values (:street, :personId)", paramsAddress2);
|
||||
|
||||
List<Person> people = personRepository.findAllPeopleWithAdresses();
|
||||
|
||||
assertThat(people).hasSize(1);
|
||||
Person person = people.get(0);
|
||||
assertThat(person.getName()).isEqualTo(personName);
|
||||
assertThat(person.getAdresses()).hasSize(2);
|
||||
assertThat(person.getAdresses()).extracting(a -> a.getStreet()).containsExactlyInAnyOrder(street1, street2);
|
||||
}
|
||||
|
||||
private MapSqlParameterSource buildAddressParameters(Long id, String streetName) {
|
||||
|
||||
MapSqlParameterSource params = new MapSqlParameterSource();
|
||||
params.addValue("street", streetName, Types.VARCHAR);
|
||||
params.addValue("personId", id, Types.NUMERIC);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
interface PersonRepository extends CrudRepository<Person, Long> {
|
||||
@Query(value="select p.id, p.name, a.id addrId, a.street from person p left join address a on(p.id = a.person_id)",
|
||||
resultSetExtractorClass=PersonResultSetExtractor.class)
|
||||
public List<Person> findAllPeopleWithAdresses();
|
||||
|
||||
@Query(
|
||||
value = "select p.id, p.name, a.id addrId, a.street from person p left join address a on(p.id = a.person_id)",
|
||||
resultSetExtractorClass = PersonResultSetExtractor.class)
|
||||
List<Person> findAllPeopleWithAdresses();
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
static class Person {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Id private Long id;
|
||||
private String name;
|
||||
private List<Address> adresses;
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
static class Address {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Id private Long id;
|
||||
private String street;
|
||||
}
|
||||
|
||||
|
||||
static class PersonResultSetExtractor implements ResultSetExtractor<List<Person>> {
|
||||
|
||||
@Override
|
||||
public List<Person> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
|
||||
Map<Long, Person> peopleById = new HashMap<>();
|
||||
while(rs.next()) {
|
||||
|
||||
while (rs.next()) {
|
||||
|
||||
long personId = rs.getLong("id");
|
||||
Person currentPerson = peopleById.computeIfAbsent(personId, t -> {
|
||||
|
||||
try {
|
||||
return new Person(personId, rs.getString("name"), new ArrayList<>());
|
||||
} catch (SQLException e) {
|
||||
throw new RecoverableDataAccessException("Error mapping Person", e);
|
||||
}
|
||||
});
|
||||
|
||||
if(currentPerson.getAdresses() == null) currentPerson.setAdresses(new ArrayList<>());
|
||||
});
|
||||
|
||||
if (currentPerson.getAdresses() == null) {
|
||||
currentPerson.setAdresses(new ArrayList<>());
|
||||
}
|
||||
|
||||
long addrId = rs.getLong("addrId");
|
||||
if(!rs.wasNull()) {
|
||||
if (!rs.wasNull()) {
|
||||
currentPerson.getAdresses().add(new Address(addrId, rs.getString("street")));
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<Person>(peopleById.values());
|
||||
|
||||
return new ArrayList<>(peopleById.values());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,89 +19,94 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.data.jdbc.repository.QueryMappingConfiguration;
|
||||
import org.springframework.data.jdbc.support.RowMapperResultsetExtractorEither;
|
||||
import org.springframework.data.jdbc.support.RowMapperOrResultsetExtractor;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ConfigurableRowMapperMap}.
|
||||
* Unit tests for {@link DefaultQueryMappingConfiguration}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Evgeni Dimitrov
|
||||
*/
|
||||
public class ConfigurableRowMapperMapUnitTests {
|
||||
|
||||
@Test
|
||||
@Test // DATAJDBC-166
|
||||
public void freshInstanceReturnsNull() {
|
||||
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration();
|
||||
|
||||
assertThat(map.getMapper(Object.class)).isNull();
|
||||
assertThat(map.getMapperOrExtractor(Object.class)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // DATAJDBC-166
|
||||
public void returnsConfiguredInstanceForClass() {
|
||||
|
||||
RowMapper rowMapper = mock(RowMapper.class);
|
||||
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration().registerRowMapper(Object.class, rowMapper);
|
||||
|
||||
assertThat(map.getMapper(Object.class)).isEqualTo(RowMapperResultsetExtractorEither.of(rowMapper));
|
||||
assertThat(map.getMapperOrExtractor(Object.class)).isEqualTo(RowMapperOrResultsetExtractor.of(rowMapper));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@Test // DATAJDBC-166
|
||||
public void returnsConfiguredInstanceResultSetExtractorForClass() {
|
||||
|
||||
ResultSetExtractor resultSetExtractor = mock(ResultSetExtractor.class);
|
||||
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration().registerResultSetExtractor(Object.class, resultSetExtractor);
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration().registerResultSetExtractor(Object.class,
|
||||
resultSetExtractor);
|
||||
|
||||
assertThat(map.getMapper(Object.class)).isEqualTo(RowMapperResultsetExtractorEither.of(resultSetExtractor));
|
||||
assertThat(map.getMapperOrExtractor(Object.class)).isEqualTo(RowMapperOrResultsetExtractor.of(resultSetExtractor));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // DATAJDBC-166
|
||||
public void returnsNullForClassNotConfigured() {
|
||||
|
||||
RowMapper rowMapper = mock(RowMapper.class);
|
||||
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration().registerRowMapper(Number.class, rowMapper);
|
||||
|
||||
assertThat(map.getMapper(Integer.class)).isNull();
|
||||
assertThat(map.getMapper(String.class)).isNull();
|
||||
assertThat(map.getMapperOrExtractor(Integer.class)).isNull();
|
||||
assertThat(map.getMapperOrExtractor(String.class)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@Test // DATAJDBC-166
|
||||
public void returnsNullResultSetExtractorForClassNotConfigured() {
|
||||
|
||||
ResultSetExtractor resultSetExtractor = mock(ResultSetExtractor.class);
|
||||
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration().registerResultSetExtractor(Number.class, resultSetExtractor);
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration().registerResultSetExtractor(Number.class,
|
||||
resultSetExtractor);
|
||||
|
||||
assertThat(map.getMapper(Integer.class)).isNull();
|
||||
assertThat(map.getMapper(String.class)).isNull();
|
||||
assertThat(map.getMapperOrExtractor(Integer.class)).isNull();
|
||||
assertThat(map.getMapperOrExtractor(String.class)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // DATAJDBC-166
|
||||
public void returnsInstanceRegisteredForSubClass() {
|
||||
|
||||
RowMapper rowMapper = mock(RowMapper.class);
|
||||
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration().registerRowMapper(String.class, rowMapper);
|
||||
|
||||
assertThat(map.getMapper(Object.class)).isEqualTo(RowMapperResultsetExtractorEither.of(rowMapper));
|
||||
assertThat(map.getMapperOrExtractor(Object.class)).isEqualTo(RowMapperOrResultsetExtractor.of(rowMapper));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
public void returnsInstanceOfResultSetExtractorRegisteredForSubClass() {
|
||||
|
||||
ResultSetExtractor resultSetExtractor = mock(ResultSetExtractor.class);
|
||||
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration().registerResultSetExtractor(String.class, resultSetExtractor);
|
||||
QueryMappingConfiguration map = new DefaultQueryMappingConfiguration().registerResultSetExtractor(String.class,
|
||||
resultSetExtractor);
|
||||
|
||||
assertThat(map.getMapper(Object.class)).isEqualTo(RowMapperResultsetExtractorEither.of(resultSetExtractor));
|
||||
assertThat(map.getMapperOrExtractor(Object.class)).isEqualTo(RowMapperOrResultsetExtractor.of(resultSetExtractor));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // DATAJDBC-166
|
||||
public void prefersExactTypeMatchClass() {
|
||||
|
||||
RowMapper rowMapper = mock(RowMapper.class);
|
||||
@@ -111,10 +116,10 @@ public class ConfigurableRowMapperMapUnitTests {
|
||||
.registerRowMapper(Integer.class, rowMapper) //
|
||||
.registerRowMapper(Number.class, mock(RowMapper.class));
|
||||
|
||||
assertThat(map.getMapper(Integer.class)).isEqualTo(RowMapperResultsetExtractorEither.of(rowMapper));
|
||||
assertThat(map.getMapperOrExtractor(Integer.class)).isEqualTo(RowMapperOrResultsetExtractor.of(rowMapper));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
public void prefersExactResultSetExtractorTypeMatchClass() {
|
||||
|
||||
ResultSetExtractor resultSetExtractor = mock(ResultSetExtractor.class);
|
||||
@@ -124,10 +129,10 @@ public class ConfigurableRowMapperMapUnitTests {
|
||||
.registerResultSetExtractor(Integer.class, resultSetExtractor) //
|
||||
.registerResultSetExtractor(Number.class, mock(ResultSetExtractor.class));
|
||||
|
||||
assertThat(map.getMapper(Integer.class)).isEqualTo(RowMapperResultsetExtractorEither.of(resultSetExtractor));
|
||||
assertThat(map.getMapperOrExtractor(Integer.class)).isEqualTo(RowMapperOrResultsetExtractor.of(resultSetExtractor));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // DATAJDBC-166
|
||||
public void prefersLatestRegistrationForSuperTypeMatch() {
|
||||
|
||||
RowMapper rowMapper = mock(RowMapper.class);
|
||||
@@ -136,10 +141,10 @@ public class ConfigurableRowMapperMapUnitTests {
|
||||
.registerRowMapper(Integer.class, mock(RowMapper.class)) //
|
||||
.registerRowMapper(Number.class, rowMapper);
|
||||
|
||||
assertThat(map.getMapper(Object.class)).isEqualTo(RowMapperResultsetExtractorEither.of(rowMapper));
|
||||
assertThat(map.getMapperOrExtractor(Object.class)).isEqualTo(RowMapperOrResultsetExtractor.of(rowMapper));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
public void prefersLatestRegistrationOfResultSetExtractorForSuperTypeMatch() {
|
||||
|
||||
ResultSetExtractor resultSetExtractor = mock(ResultSetExtractor.class);
|
||||
@@ -148,6 +153,6 @@ public class ConfigurableRowMapperMapUnitTests {
|
||||
.registerResultSetExtractor(Integer.class, mock(ResultSetExtractor.class)) //
|
||||
.registerResultSetExtractor(Number.class, resultSetExtractor);
|
||||
|
||||
assertThat(map.getMapper(Object.class)).isEqualTo(RowMapperResultsetExtractorEither.of(resultSetExtractor));
|
||||
assertThat(map.getMapperOrExtractor(Object.class)).isEqualTo(RowMapperOrResultsetExtractor.of(resultSetExtractor));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.repository.QueryMappingConfiguration;
|
||||
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositoriesIntegrationTests.TestConfiguration;
|
||||
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactoryBean;
|
||||
import org.springframework.data.jdbc.support.RowMapperResultsetExtractorEither;
|
||||
import org.springframework.data.jdbc.support.RowMapperOrResultsetExtractor;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
@@ -46,12 +46,13 @@ import org.springframework.util.ReflectionUtils;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Greg Turnquist
|
||||
* @author Evgeni Dimitrov
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = TestConfiguration.class)
|
||||
public class EnableJdbcRepositoriesIntegrationTests {
|
||||
|
||||
static final Field MAPPER_MAP = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class, "mapperMap");
|
||||
static final Field MAPPER_MAP = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class, "queryMappingConfiguration");
|
||||
public static final RowMapper DUMMY_ENTITY_ROW_MAPPER = mock(RowMapper.class);
|
||||
public static final RowMapper STRING_ROW_MAPPER = mock(RowMapper.class);
|
||||
public static final ResultSetExtractor<Integer> INTEGER_RESULT_SET_EXTRACTOR = mock(ResultSetExtractor.class);
|
||||
@@ -76,23 +77,28 @@ public class EnableJdbcRepositoriesIntegrationTests {
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
public void customResultSetExtractorConfigurationGetsPickedUp() {
|
||||
|
||||
QueryMappingConfiguration mapping = (QueryMappingConfiguration) ReflectionUtils.getField(MAPPER_MAP, factoryBean);
|
||||
assertThat(mapping.getMapper(Integer.class)).isEqualTo(RowMapperResultsetExtractorEither.of(INTEGER_RESULT_SET_EXTRACTOR));
|
||||
assertThat(mapping.getMapperOrExtractor(Integer.class))
|
||||
.isEqualTo(RowMapperOrResultsetExtractor.of(INTEGER_RESULT_SET_EXTRACTOR));
|
||||
}
|
||||
|
||||
|
||||
@Test // DATAJDBC-290
|
||||
public void customResultSetExtractorConfigurationIsNotPickedUpIfRowMapperIsRegisteredForTheSameType() {
|
||||
|
||||
QueryMappingConfiguration mapping = (QueryMappingConfiguration) ReflectionUtils.getField(MAPPER_MAP, factoryBean);
|
||||
assertThat(mapping.getMapper(String.class).isResultSetExtractor()).isFalse();
|
||||
assertThat(mapping.getMapperOrExtractor(String.class).isResultSetExtractor()).isFalse();
|
||||
}
|
||||
|
||||
|
||||
@Test // DATAJDBC-166
|
||||
public void customRowMapperConfigurationGetsPickedUp() {
|
||||
|
||||
QueryMappingConfiguration mapping = (QueryMappingConfiguration) ReflectionUtils.getField(MAPPER_MAP, factoryBean);
|
||||
|
||||
assertThat(mapping.getMapper(String.class)).isEqualTo(RowMapperResultsetExtractorEither.of(STRING_ROW_MAPPER));
|
||||
assertThat(mapping.getMapper(DummyEntity.class)).isEqualTo(RowMapperResultsetExtractorEither.of(DUMMY_ENTITY_ROW_MAPPER));
|
||||
assertThat(mapping.getMapperOrExtractor(String.class))
|
||||
.isEqualTo(RowMapperOrResultsetExtractor.of(STRING_ROW_MAPPER));
|
||||
assertThat(mapping.getMapperOrExtractor(DummyEntity.class))
|
||||
.isEqualTo(RowMapperOrResultsetExtractor.of(DUMMY_ENTITY_ROW_MAPPER));
|
||||
}
|
||||
|
||||
interface DummyRepository extends CrudRepository<DummyEntity, Long> {
|
||||
@@ -116,6 +122,7 @@ public class EnableJdbcRepositoriesIntegrationTests {
|
||||
|
||||
@Bean
|
||||
QueryMappingConfiguration rowMappers() {
|
||||
|
||||
return new DefaultQueryMappingConfiguration() //
|
||||
.registerRowMapper(DummyEntity.class, DUMMY_ENTITY_ROW_MAPPER) //
|
||||
.registerRowMapper(String.class, STRING_ROW_MAPPER)
|
||||
|
||||
@@ -49,6 +49,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @author Maciej Walkowiak
|
||||
* @author Evgeni Dimitrov
|
||||
*/
|
||||
public class JdbcQueryLookupStrategyUnitTests {
|
||||
|
||||
@@ -75,9 +76,9 @@ public class JdbcQueryLookupStrategyUnitTests {
|
||||
public void typeBasedRowMapperGetsUsedForQuery() {
|
||||
|
||||
RowMapper<? extends NumberFormat> numberFormatMapper = mock(RowMapper.class);
|
||||
QueryMappingConfiguration rowMapperMap = new DefaultQueryMappingConfiguration().registerRowMapper(NumberFormat.class, numberFormatMapper);
|
||||
QueryMappingConfiguration mappingConfiguration = new DefaultQueryMappingConfiguration().registerRowMapper(NumberFormat.class, numberFormatMapper);
|
||||
|
||||
RepositoryQuery repositoryQuery = getRepositoryQuery("returningNumberFormat", rowMapperMap);
|
||||
RepositoryQuery repositoryQuery = getRepositoryQuery("returningNumberFormat", mappingConfiguration);
|
||||
|
||||
repositoryQuery.execute(new Object[] {});
|
||||
|
||||
@@ -89,19 +90,19 @@ public class JdbcQueryLookupStrategyUnitTests {
|
||||
public void typeBasedResultSetExtractorGetsUsedForQuery() {
|
||||
|
||||
ResultSetExtractor<? extends NumberFormat> numberFormatMapper = mock(ResultSetExtractor.class);
|
||||
QueryMappingConfiguration rowMapperMap = new DefaultQueryMappingConfiguration().registerResultSetExtractor(NumberFormat.class, numberFormatMapper);
|
||||
QueryMappingConfiguration mappingConfiguration = new DefaultQueryMappingConfiguration().registerResultSetExtractor(NumberFormat.class, numberFormatMapper);
|
||||
|
||||
RepositoryQuery repositoryQuery = getRepositoryQuery("returningNumberFormat", rowMapperMap);
|
||||
RepositoryQuery repositoryQuery = getRepositoryQuery("returningNumberFormat", mappingConfiguration);
|
||||
|
||||
repositoryQuery.execute(new Object[] {});
|
||||
|
||||
verify(operations).query(anyString(), any(SqlParameterSource.class), eq(numberFormatMapper));
|
||||
}
|
||||
|
||||
private RepositoryQuery getRepositoryQuery(String name, QueryMappingConfiguration rowMapperMap) {
|
||||
private RepositoryQuery getRepositoryQuery(String name, QueryMappingConfiguration mappingConfiguration) {
|
||||
|
||||
JdbcQueryLookupStrategy queryLookupStrategy = new JdbcQueryLookupStrategy(publisher, mappingContext, converter, accessStrategy,
|
||||
rowMapperMap, operations);
|
||||
mappingConfiguration, operations);
|
||||
|
||||
return queryLookupStrategy.resolveQuery(getMethod(name), metadata, projectionFactory, namedQueries);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @author Evgeni Dimitrov
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class JdbcRepositoryFactoryBeanUnitTests {
|
||||
@@ -100,7 +102,7 @@ public class JdbcRepositoryFactoryBeanUnitTests {
|
||||
assertThat(factoryBean.getObject()).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(factoryBean, "dataAccessStrategy"))
|
||||
.isInstanceOf(DefaultDataAccessStrategy.class);
|
||||
assertThat(ReflectionTestUtils.getField(factoryBean, "mapperMap")).isEqualTo(QueryMappingConfiguration.EMPTY);
|
||||
assertThat(ReflectionTestUtils.getField(factoryBean, "queryMappingConfiguration")).isEqualTo(QueryMappingConfiguration.EMPTY);
|
||||
}
|
||||
|
||||
private static class DummyEntity {
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.jdbc.support.RowMapperResultsetExtractorEither;
|
||||
import org.springframework.data.jdbc.support.RowMapperOrResultsetExtractor;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterLoadEvent;
|
||||
import org.springframework.data.repository.query.DefaultParameters;
|
||||
@@ -46,6 +46,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
* @author Jens Schauder
|
||||
* @author Oliver Gierke
|
||||
* @author Maciej Walkowiak
|
||||
* @author Evgeni Dimitrov
|
||||
*/
|
||||
public class JdbcRepositoryQueryUnitTests {
|
||||
|
||||
@@ -72,7 +73,7 @@ public class JdbcRepositoryQueryUnitTests {
|
||||
this.publisher = mock(ApplicationEventPublisher.class);
|
||||
this.context = mock(RelationalMappingContext.class, RETURNS_DEEP_STUBS);
|
||||
|
||||
this.query = new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperResultsetExtractorEither.of(defaultRowMapper));
|
||||
this.query = new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperOrResultsetExtractor.of(defaultRowMapper));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-165
|
||||
@@ -111,7 +112,7 @@ public class JdbcRepositoryQueryUnitTests {
|
||||
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
|
||||
doReturn(CustomRowMapper.class).when(queryMethod).getRowMapperClass();
|
||||
|
||||
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperResultsetExtractorEither.of(defaultRowMapper)).execute(new Object[] {});
|
||||
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperOrResultsetExtractor.of(defaultRowMapper)).execute(new Object[] {});
|
||||
|
||||
verify(operations) //
|
||||
.queryForObject(anyString(), any(SqlParameterSource.class), isA(CustomRowMapper.class));
|
||||
@@ -123,7 +124,7 @@ public class JdbcRepositoryQueryUnitTests {
|
||||
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
|
||||
doReturn(CustomResultSetExtractor.class).when(queryMethod).getResultSetExtractorClass();
|
||||
|
||||
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperResultsetExtractorEither.of(defaultRowMapper)).execute(new Object[] {});
|
||||
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperOrResultsetExtractor.of(defaultRowMapper)).execute(new Object[] {});
|
||||
|
||||
verify(operations) //
|
||||
.query(anyString(), any(SqlParameterSource.class), isA(CustomResultSetExtractor.class));
|
||||
@@ -139,7 +140,7 @@ public class JdbcRepositoryQueryUnitTests {
|
||||
doReturn(true).when(context).hasPersistentEntityFor(DummyEntity.class);
|
||||
when(context.getRequiredPersistentEntity(DummyEntity.class).getIdentifierAccessor(any()).getRequiredIdentifier()).thenReturn("some identifier");
|
||||
|
||||
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperResultsetExtractorEither.of(defaultRowMapper)).execute(new Object[] {});
|
||||
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperOrResultsetExtractor.of(defaultRowMapper)).execute(new Object[] {});
|
||||
|
||||
verify(publisher).publishEvent(any(AfterLoadEvent.class));
|
||||
}
|
||||
@@ -153,7 +154,7 @@ public class JdbcRepositoryQueryUnitTests {
|
||||
doReturn(true).when(context).hasPersistentEntityFor(DummyEntity.class);
|
||||
when(context.getRequiredPersistentEntity(DummyEntity.class).getIdentifierAccessor(any()).getRequiredIdentifier()).thenReturn("some identifier");
|
||||
|
||||
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperResultsetExtractorEither.of(defaultRowMapper)).execute(new Object[] {});
|
||||
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, RowMapperOrResultsetExtractor.of(defaultRowMapper)).execute(new Object[] {});
|
||||
|
||||
verify(publisher, times(2)).publishEvent(any(AfterLoadEvent.class));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user