From 3769db7a272c747e3095036b4855cadc46d6881f Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Mon, 3 Dec 2018 17:21:31 +0100 Subject: [PATCH] DATAJDBC-290 - Polishing. Naming, formatting, and code structure improved. Original pull request: #101. --- .../repository/QueryMappingConfiguration.java | 14 ++- .../DefaultQueryMappingConfiguration.java | 32 ++++-- .../data/jdbc/repository/query/Query.java | 10 +- .../support/InvalidQueryConfiguration.java | 19 ---- .../support/JdbcQueryLookupStrategy.java | 39 ++++--- .../repository/support/JdbcQueryMethod.java | 2 +- .../support/JdbcRepositoryFactory.java | 14 ++- .../support/JdbcRepositoryFactoryBean.java | 16 +-- .../support/JdbcRepositoryQuery.java | 107 +++++++++++------- .../RowMapperOrResultsetExtractor.java | 42 +++++++ .../RowMapperResultsetExtractorEither.java | 76 ------------- ...MapResultSetExtractorIntegrationTests.java | 12 +- ...oryResultSetExtractorIntegrationTests.java | 80 ++++++++----- .../ConfigurableRowMapperMapUnitTests.java | 73 ++++++------ ...nableJdbcRepositoriesIntegrationTests.java | 23 ++-- .../JdbcQueryLookupStrategyUnitTests.java | 13 ++- .../JdbcRepositoryFactoryBeanUnitTests.java | 4 +- .../support/JdbcRepositoryQueryUnitTests.java | 13 ++- 18 files changed, 313 insertions(+), 276 deletions(-) delete mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/InvalidQueryConfiguration.java create mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/RowMapperOrResultsetExtractor.java delete mode 100644 spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/RowMapperResultsetExtractorEither.java diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/QueryMappingConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/QueryMappingConfiguration.java index f0ed2f83..70c55f2b 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/QueryMappingConfiguration.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/QueryMappingConfiguration.java @@ -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 { - RowMapperResultsetExtractorEither getMapper(Class type); - + + @Nullable + RowMapperOrResultsetExtractor getMapperOrExtractor(Class type); + /** * An immutable empty instance that will return {@literal null} for all arguments. */ QueryMappingConfiguration EMPTY = new QueryMappingConfiguration() { @Override - public RowMapperResultsetExtractorEither getMapper(Class type) { + public RowMapperOrResultsetExtractor getMapperOrExtractor(Class type) { return null; } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DefaultQueryMappingConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DefaultQueryMappingConfiguration.java index 2d1b0810..3c53250a 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DefaultQueryMappingConfiguration.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DefaultQueryMappingConfiguration.java @@ -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, RowMapperResultsetExtractorEither> mappers = new LinkedHashMap<>(); +public class DefaultQueryMappingConfiguration implements QueryMappingConfiguration { + + private Map, RowMapperOrResultsetExtractor> mappers = new LinkedHashMap<>(); + + @Nullable + public RowMapperOrResultsetExtractor getMapperOrExtractor(Class type) { - public RowMapperResultsetExtractorEither getMapper(Class 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, RowMapperResultsetExtractorEither> entry : mappers.entrySet()) { + for (Map.Entry, 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 DefaultQueryMappingConfiguration registerRowMapper(Class type, RowMapper 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 DefaultQueryMappingConfiguration registerResultSetExtractor(Class type, ResultSetExtractor resultSetExtractor) { - mappers.put(type, RowMapperResultsetExtractorEither.of(resultSetExtractor)); + public DefaultQueryMappingConfiguration registerResultSetExtractor(Class type, + ResultSetExtractor resultSetExtractor) { + + mappers.put(type, RowMapperOrResultsetExtractor.of(resultSetExtractor)); + return this; } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/Query.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/Query.java index 796da650..8de60ef9 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/Query.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/Query.java @@ -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 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 resultSetExtractorClass() default ResultSetExtractor.class; } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/InvalidQueryConfiguration.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/InvalidQueryConfiguration.java deleted file mode 100644 index bd059ad8..00000000 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/InvalidQueryConfiguration.java +++ /dev/null @@ -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); - } -} 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 3c3d27a9..deeefdc0 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 @@ -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); } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryMethod.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryMethod.java index 6eb61740..9cdca60e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryMethod.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryMethod.java @@ -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} * diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java index 95be4d57..d9192617 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java @@ -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)); } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java index aa63d89f..de182f22 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java @@ -49,7 +49,7 @@ public class JdbcRepositoryFactoryBean, 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, 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, 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, S, ID extend operations); } - if (mapperMap == null) { - this.mapperMap = QueryMappingConfiguration.EMPTY; + if (queryMappingConfiguration == null) { + this.queryMappingConfiguration = QueryMappingConfiguration.EMPTY; } super.afterPropertiesSet(); diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQuery.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQuery.java index cc9caf6b..64f0ba8e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQuery.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQuery.java @@ -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 void publishAfterLoad(Iterable 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)); diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/RowMapperOrResultsetExtractor.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/RowMapperOrResultsetExtractor.java new file mode 100644 index 00000000..9506119c --- /dev/null +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/RowMapperOrResultsetExtractor.java @@ -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 { + + private final RowMapper rowMapper; + private final ResultSetExtractor resultSetExtractor; + + private RowMapperOrResultsetExtractor(RowMapper rowMapper, ResultSetExtractor 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; + } + +} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/RowMapperResultsetExtractorEither.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/RowMapperResultsetExtractorEither.java deleted file mode 100644 index b24b651c..00000000 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/RowMapperResultsetExtractorEither.java +++ /dev/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 { - private final RowMapper rowMapper; - private final ResultSetExtractor resultSetExtractor; - - private RowMapperResultsetExtractorEither(RowMapper rowMapper, ResultSetExtractor 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; - } - -} diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryMapperMapResultSetExtractorIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryMapperMapResultSetExtractorIntegrationTests.java index 0c2cf97e..ce3ff747 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryMapperMapResultSetExtractorIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryMapperMapResultSetExtractorIntegrationTests.java @@ -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 cars = carRepository.customFindAll(); + assertThat(cars).hasSize(1); assertThat(cars).allMatch(car -> CAR_MODEL.equals(car.getModel())); } interface CarRepository extends CrudRepository { + @Query("select * from car") - public List customFindAll(); + List customFindAll(); } @Data @AllArgsConstructor static class Car { - @Id + + @Id private Long id; private String model; } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryResultSetExtractorIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryResultSetExtractorIntegrationTests.java index b474d9de..2bd64781 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryResultSetExtractorIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryResultSetExtractorIntegrationTests.java @@ -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 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 { - @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 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 findAllPeopleWithAdresses(); } @Data @AllArgsConstructor static class Person { - @Id - private Long id; + + @Id private Long id; private String name; private List
adresses; } - + @Data @AllArgsConstructor static class Address { - @Id - private Long id; + + @Id private Long id; private String street; } - + static class PersonResultSetExtractor implements ResultSetExtractor> { @Override public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map 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(peopleById.values()); + + return new ArrayList<>(peopleById.values()); } - + } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/ConfigurableRowMapperMapUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/ConfigurableRowMapperMapUnitTests.java index c994adde..ff8f1608 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/ConfigurableRowMapperMapUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/ConfigurableRowMapperMapUnitTests.java @@ -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)); } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java index 9f82d975..380f810e 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java @@ -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_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 { @@ -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) diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java index eb5be6a9..654d9e6e 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java @@ -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 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 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); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java index bdf19a88..16886f46 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java @@ -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 { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQueryUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQueryUnitTests.java index 22a2b0c0..f38688e2 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQueryUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQueryUnitTests.java @@ -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)); }