Browse Source

Add support for repository query method projections.

JDBC repository methods now support interface and DTO projections by specifying either the projection type as return type or using generics and providing a Class parameter to query methods.

Closes #971
Original pull request #980
pull/981/head
Mark Paluch 5 years ago committed by Jens Schauder
parent
commit
b3a2925573
No known key found for this signature in database
GPG Key ID: 45CC872F17423DBF
  1. 68
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/AbstractJdbcQuery.java
  2. 6
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcCountQueryCreator.java
  3. 15
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryCreator.java
  4. 47
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryExecution.java
  5. 74
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQuery.java
  6. 75
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java
  7. 18
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java
  8. 63
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
  9. 99
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java
  10. 5
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/BasicRelationalConverter.java
  11. 9
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/RelationalConverter.java
  12. 4
      src/main/asciidoc/jdbc.adoc

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

@ -15,10 +15,15 @@
*/ */
package org.springframework.data.jdbc.repository.query; package org.springframework.data.jdbc.repository.query;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List; import java.util.List;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.RowMapperResultSetExtractor; import org.springframework.jdbc.core.RowMapperResultSetExtractor;
@ -43,23 +48,17 @@ public abstract class AbstractJdbcQuery implements RepositoryQuery {
private final NamedParameterJdbcOperations operations; private final NamedParameterJdbcOperations operations;
/** /**
* Creates a new {@link AbstractJdbcQuery} for the given {@link JdbcQueryMethod}, {@link NamedParameterJdbcOperations} * Creates a new {@link AbstractJdbcQuery} for the given {@link JdbcQueryMethod} and
* and {@link RowMapper}. * {@link NamedParameterJdbcOperations}.
* *
* @param queryMethod must not be {@literal null}. * @param queryMethod must not be {@literal null}.
* @param operations 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).
*/ */
AbstractJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations, AbstractJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations) {
@Nullable RowMapper<?> defaultRowMapper) {
Assert.notNull(queryMethod, "Query method must not be null!"); Assert.notNull(queryMethod, "Query method must not be null!");
Assert.notNull(operations, "NamedParameterJdbcOperations must not be null!"); Assert.notNull(operations, "NamedParameterJdbcOperations must not be null!");
if (!queryMethod.isModifyingQuery()) {
Assert.notNull(defaultRowMapper, "Mapper must not be null!");
}
this.queryMethod = queryMethod; this.queryMethod = queryMethod;
this.operations = operations; this.operations = operations;
} }
@ -123,8 +122,59 @@ public abstract class AbstractJdbcQuery implements RepositoryQuery {
return getQueryExecution(new RowMapperResultSetExtractor<>(rowMapper)); return getQueryExecution(new RowMapperResultSetExtractor<>(rowMapper));
} }
/**
* Obtain the result type to read from {@link ResultProcessor}.
*
* @param resultProcessor
* @return
*/
protected Class<?> resolveTypeToRead(ResultProcessor resultProcessor) {
ReturnedType returnedType = resultProcessor.getReturnedType();
if (returnedType.getReturnedType().isAssignableFrom(returnedType.getDomainType())) {
return returnedType.getDomainType();
}
// Slight deviation from R2DBC: Allow direct mapping into DTOs
return returnedType.isProjecting() && returnedType.getReturnedType().isInterface() ? returnedType.getDomainType()
: returnedType.getReturnedType();
}
private <T> JdbcQueryExecution<T> getQueryExecution(ResultSetExtractor<T> resultSetExtractor) { private <T> JdbcQueryExecution<T> getQueryExecution(ResultSetExtractor<T> resultSetExtractor) {
return (query, parameters) -> operations.query(query, parameters, resultSetExtractor); return (query, parameters) -> operations.query(query, parameters, resultSetExtractor);
} }
/**
* Factory to create a {@link RowMapper} for a given class.
*
* @since 2.3
*/
public interface RowMapperFactory {
RowMapper<Object> create(Class<?> result);
}
/**
* Delegating {@link RowMapper} that reads a row into {@code T} and converts it afterwards into {@code Object}.
*
* @param <T>
* @since 2.3
*/
protected static class ConvertingRowMapper<T> implements RowMapper<Object> {
private final RowMapper<T> delegate;
private final Converter<Object, Object> converter;
public ConvertingRowMapper(RowMapper<T> delegate, Converter<Object, Object> converter) {
this.delegate = delegate;
this.converter = converter;
}
@Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
T object = delegate.mapRow(rs, rowNum);
return converter.convert(object);
}
}
} }

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

@ -27,6 +27,7 @@ import org.springframework.data.relational.core.sql.SelectBuilder;
import org.springframework.data.relational.core.sql.Table; import org.springframework.data.relational.core.sql.Table;
import org.springframework.data.relational.repository.query.RelationalEntityMetadata; import org.springframework.data.relational.repository.query.RelationalEntityMetadata;
import org.springframework.data.relational.repository.query.RelationalParameterAccessor; import org.springframework.data.relational.repository.query.RelationalParameterAccessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.repository.query.parser.PartTree;
/** /**
@ -38,8 +39,9 @@ import org.springframework.data.repository.query.parser.PartTree;
class JdbcCountQueryCreator extends JdbcQueryCreator { class JdbcCountQueryCreator extends JdbcQueryCreator {
JdbcCountQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect, JdbcCountQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect,
RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor, boolean isSliceQuery) { RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor, boolean isSliceQuery,
super(context, tree, converter, dialect, entityMetadata, accessor, isSliceQuery); ReturnedType returnedType) {
super(context, tree, converter, dialect, entityMetadata, accessor, isSliceQuery, returnedType);
} }
@Override @Override

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

@ -44,6 +44,7 @@ import org.springframework.data.relational.repository.query.RelationalEntityMeta
import org.springframework.data.relational.repository.query.RelationalParameterAccessor; import org.springframework.data.relational.repository.query.RelationalParameterAccessor;
import org.springframework.data.relational.repository.query.RelationalQueryCreator; import org.springframework.data.relational.repository.query.RelationalQueryCreator;
import org.springframework.data.repository.query.Parameters; import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.Part; import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@ -67,6 +68,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
private final RelationalEntityMetadata<?> entityMetadata; private final RelationalEntityMetadata<?> entityMetadata;
private final RenderContextFactory renderContextFactory; private final RenderContextFactory renderContextFactory;
private final boolean isSliceQuery; private final boolean isSliceQuery;
private final ReturnedType returnedType;
/** /**
* Creates new instance of this class with the given {@link PartTree}, {@link JdbcConverter}, {@link Dialect}, * Creates new instance of this class with the given {@link PartTree}, {@link JdbcConverter}, {@link Dialect},
@ -79,14 +81,17 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
* @param entityMetadata relational entity metadata, must not be {@literal null}. * @param entityMetadata relational entity metadata, must not be {@literal null}.
* @param accessor parameter metadata provider, must not be {@literal null}. * @param accessor parameter metadata provider, must not be {@literal null}.
* @param isSliceQuery * @param isSliceQuery
* @param returnedType
*/ */
JdbcQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect, JdbcQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect,
RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor, boolean isSliceQuery) { RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor, boolean isSliceQuery,
ReturnedType returnedType) {
super(tree, accessor); super(tree, accessor);
Assert.notNull(converter, "JdbcConverter must not be null"); Assert.notNull(converter, "JdbcConverter must not be null");
Assert.notNull(dialect, "Dialect must not be null"); Assert.notNull(dialect, "Dialect must not be null");
Assert.notNull(entityMetadata, "Relational entity metadata must not be null"); Assert.notNull(entityMetadata, "Relational entity metadata must not be null");
Assert.notNull(returnedType, "ReturnedType must not be null");
this.context = context; this.context = context;
this.tree = tree; this.tree = tree;
@ -96,6 +101,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
this.queryMapper = new QueryMapper(dialect, converter); this.queryMapper = new QueryMapper(dialect, converter);
this.renderContextFactory = new RenderContextFactory(dialect); this.renderContextFactory = new RenderContextFactory(dialect);
this.isSliceQuery = isSliceQuery; this.isSliceQuery = isSliceQuery;
this.returnedType = returnedType;
} }
/** /**
@ -241,6 +247,13 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
joinTables.add(join); joinTables.add(join);
} }
if (returnedType.needsCustomConstruction()) {
if (!returnedType.getInputProperties()
.contains(extPath.getRequiredPersistentPropertyPath().getBaseProperty().getName())) {
continue;
}
}
Column column = getColumn(sqlContext, extPath); Column column = getColumn(sqlContext, extPath);
if (column != null) { if (column != null) {
columnExpressions.add(column); columnExpressions.add(column);

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

@ -15,8 +15,18 @@
*/ */
package org.springframework.data.jdbc.repository.query; package org.springframework.data.jdbc.repository.query;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.EntityInstantiators;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.relational.repository.query.DtoInstantiatingConverter;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.util.Lazy;
import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/** /**
* Interface specifying a query execution strategy. Implementations encapsulate information how to actually execute the * Interface specifying a query execution strategy. Implementations encapsulate information how to actually execute the
@ -37,4 +47,41 @@ interface JdbcQueryExecution<T> {
*/ */
@Nullable @Nullable
T execute(String query, SqlParameterSource parameter); T execute(String query, SqlParameterSource parameter);
/**
* A {@link Converter} to post-process all source objects using the given {@link ResultProcessor}.
*
* @author Mark Paluch
* @since 2.3
*/
class ResultProcessingConverter implements Converter<Object, Object> {
private final ResultProcessor processor;
private final Lazy<Converter<Object, Object>> converter;
ResultProcessingConverter(ResultProcessor processor,
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> mappingContext,
EntityInstantiators instantiators) {
this.processor = processor;
this.converter = Lazy.of(() -> new DtoInstantiatingConverter(processor.getReturnedType().getReturnedType(),
mappingContext, instantiators));
}
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public Object convert(Object source) {
ReturnedType returnedType = processor.getReturnedType();
if (ClassUtils.isPrimitiveOrWrapper(returnedType.getReturnedType())
|| returnedType.getReturnedType().isInstance(source)) {
return source;
}
return processor.processResult(source, converter.get());
}
}
} }

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

@ -15,12 +15,15 @@
*/ */
package org.springframework.data.jdbc.repository.query; package org.springframework.data.jdbc.repository.query;
import static org.springframework.data.jdbc.repository.query.JdbcQueryExecution.*;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.LongSupplier; import java.util.function.LongSupplier;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl; import org.springframework.data.domain.SliceImpl;
@ -32,6 +35,8 @@ import org.springframework.data.relational.repository.query.RelationalEntityMeta
import org.springframework.data.relational.repository.query.RelationalParameterAccessor; import org.springframework.data.relational.repository.query.RelationalParameterAccessor;
import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor; import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor;
import org.springframework.data.repository.query.Parameters; import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.data.support.PageableExecutionUtils; import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.ResultSetExtractor;
@ -53,9 +58,8 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
private final Parameters<?, ?> parameters; private final Parameters<?, ?> parameters;
private final Dialect dialect; private final Dialect dialect;
private final JdbcConverter converter; private final JdbcConverter converter;
private final RowMapperFactory rowMapperFactory;
private final PartTree tree; private final PartTree tree;
/** The execution for obtaining the bulk of the data. The execution may be decorated with further processing for handling sliced or paged queries */
private final JdbcQueryExecution<?> coreExecution;
/** /**
* Creates a new {@link PartTreeJdbcQuery}. * Creates a new {@link PartTreeJdbcQuery}.
@ -69,26 +73,40 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
*/ */
public PartTreeJdbcQuery(RelationalMappingContext context, JdbcQueryMethod queryMethod, Dialect dialect, public PartTreeJdbcQuery(RelationalMappingContext context, JdbcQueryMethod queryMethod, Dialect dialect,
JdbcConverter converter, NamedParameterJdbcOperations operations, RowMapper<Object> rowMapper) { JdbcConverter converter, NamedParameterJdbcOperations operations, RowMapper<Object> rowMapper) {
this(context, queryMethod, dialect, converter, operations, it -> rowMapper);
}
/**
* Creates a new {@link PartTreeJdbcQuery}.
*
* @param context must not be {@literal null}.
* @param queryMethod must not be {@literal null}.
* @param dialect must not be {@literal null}.
* @param converter must not be {@literal null}.
* @param operations must not be {@literal null}.
* @param rowMapperFactory must not be {@literal null}.
* @since 2.3
*/
public PartTreeJdbcQuery(RelationalMappingContext context, JdbcQueryMethod queryMethod, Dialect dialect,
JdbcConverter converter, NamedParameterJdbcOperations operations, RowMapperFactory rowMapperFactory) {
super(queryMethod, operations, rowMapper); super(queryMethod, operations);
Assert.notNull(context, "RelationalMappingContext must not be null"); Assert.notNull(context, "RelationalMappingContext must not be null");
Assert.notNull(queryMethod, "JdbcQueryMethod must not be null"); Assert.notNull(queryMethod, "JdbcQueryMethod must not be null");
Assert.notNull(dialect, "Dialect must not be null"); Assert.notNull(dialect, "Dialect must not be null");
Assert.notNull(converter, "JdbcConverter must not be null"); Assert.notNull(converter, "JdbcConverter must not be null");
Assert.notNull(rowMapperFactory, "RowMapperFactory must not be null");
this.context = context; this.context = context;
this.parameters = queryMethod.getParameters(); this.parameters = queryMethod.getParameters();
this.dialect = dialect; this.dialect = dialect;
this.converter = converter; this.converter = converter;
this.rowMapperFactory = rowMapperFactory;
this.tree = new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType()); this.tree = new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType());
JdbcQueryCreator.validate(this.tree, this.parameters, this.converter.getMappingContext()); JdbcQueryCreator.validate(this.tree, this.parameters, this.converter.getMappingContext());
ResultSetExtractor<Boolean> extractor = tree.isExistsProjection() ? (ResultSet::next) : null;
this.coreExecution = queryMethod.isPageQuery() || queryMethod.isSliceQuery() ? collectionQuery(rowMapper)
: getQueryExecution(queryMethod, extractor, rowMapper);
} }
private Sort getDynamicSort(RelationalParameterAccessor accessor) { private Sort getDynamicSort(RelationalParameterAccessor accessor) {
@ -104,30 +122,48 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
RelationalParametersParameterAccessor accessor = new RelationalParametersParameterAccessor(getQueryMethod(), RelationalParametersParameterAccessor accessor = new RelationalParametersParameterAccessor(getQueryMethod(),
values); values);
ParametrizedQuery query = createQuery(accessor);
JdbcQueryExecution<?> execution = getDecoratedExecution(accessor); ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor);
ParametrizedQuery query = createQuery(accessor, processor.getReturnedType());
JdbcQueryExecution<?> execution = getQueryExecution(processor, accessor);
return execution.execute(query.getQuery(), query.getParameterSource()); return execution.execute(query.getQuery(), query.getParameterSource());
} }
/** private JdbcQueryExecution<?> getQueryExecution(ResultProcessor processor,
* The decorated execution is the {@link #coreExecution} decorated with further processing for handling sliced or paged queries. RelationalParametersParameterAccessor accessor) {
*/
private JdbcQueryExecution<?> getDecoratedExecution(RelationalParametersParameterAccessor accessor) { ResultSetExtractor<Boolean> extractor = tree.isExistsProjection() ? (ResultSet::next) : null;
RowMapper<Object> rowMapper;
if (tree.isCountProjection() || tree.isExistsProjection()) {
rowMapper = rowMapperFactory.create(resolveTypeToRead(processor));
} else {
Converter<Object, Object> resultProcessingConverter = new ResultProcessingConverter(processor,
this.converter.getMappingContext(), this.converter.getEntityInstantiators());
rowMapper = new ConvertingRowMapper<>(rowMapperFactory.create(processor.getReturnedType().getDomainType()),
resultProcessingConverter);
}
JdbcQueryExecution<?> queryExecution = getQueryMethod().isPageQuery() || getQueryMethod().isSliceQuery()
? collectionQuery(rowMapper)
: getQueryExecution(getQueryMethod(), extractor, rowMapper);
if (getQueryMethod().isSliceQuery()) { if (getQueryMethod().isSliceQuery()) {
return new SliceQueryExecution<>((JdbcQueryExecution<Collection<Object>>) this.coreExecution, accessor.getPageable()); return new SliceQueryExecution<>((JdbcQueryExecution<Collection<Object>>) queryExecution, accessor.getPageable());
} }
if (getQueryMethod().isPageQuery()) { if (getQueryMethod().isPageQuery()) {
return new PageQueryExecution<>((JdbcQueryExecution<Collection<Object>>) this.coreExecution, accessor.getPageable(), return new PageQueryExecution<>((JdbcQueryExecution<Collection<Object>>) queryExecution, accessor.getPageable(),
() -> { () -> {
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation(); RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
JdbcCountQueryCreator queryCreator = new JdbcCountQueryCreator(context, tree, converter, dialect, JdbcCountQueryCreator queryCreator = new JdbcCountQueryCreator(context, tree, converter, dialect,
entityMetadata, accessor, false); entityMetadata, accessor, false, processor.getReturnedType());
ParametrizedQuery countQuery = queryCreator.createQuery(Sort.unsorted()); ParametrizedQuery countQuery = queryCreator.createQuery(Sort.unsorted());
Object count = singleObjectQuery((rs, i) -> rs.getLong(1)).execute(countQuery.getQuery(), Object count = singleObjectQuery((rs, i) -> rs.getLong(1)).execute(countQuery.getQuery(),
@ -137,15 +173,15 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
}); });
} }
return this.coreExecution; return queryExecution;
} }
protected ParametrizedQuery createQuery(RelationalParametersParameterAccessor accessor) { protected ParametrizedQuery createQuery(RelationalParametersParameterAccessor accessor, ReturnedType returnedType) {
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation(); RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
JdbcQueryCreator queryCreator = new JdbcQueryCreator(context, tree, converter, dialect, entityMetadata, accessor, JdbcQueryCreator queryCreator = new JdbcQueryCreator(context, tree, converter, dialect, entityMetadata, accessor,
getQueryMethod().isSliceQuery()); getQueryMethod().isSliceQuery(), returnedType);
return queryCreator.createQuery(getDynamicSort(accessor)); return queryCreator.createQuery(getDynamicSort(accessor));
} }

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

@ -15,18 +15,24 @@
*/ */
package org.springframework.data.jdbc.repository.query; package org.springframework.data.jdbc.repository.query;
import static org.springframework.data.jdbc.repository.query.JdbcQueryExecution.*;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.sql.JDBCType; import java.sql.JDBCType;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.jdbc.core.convert.JdbcColumnTypes; import org.springframework.data.jdbc.core.convert.JdbcColumnTypes;
import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.core.convert.JdbcValue; import org.springframework.data.jdbc.core.convert.JdbcValue;
import org.springframework.data.jdbc.support.JdbcUtil; import org.springframework.data.jdbc.support.JdbcUtil;
import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.repository.query.RelationalParameterAccessor;
import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor;
import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameter;
import org.springframework.data.util.Lazy; import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@ -53,8 +59,8 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
private static final String PARAMETER_NEEDS_TO_BE_NAMED = "For queries with named parameters you need to provide names for method parameters. Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters."; private static final String PARAMETER_NEEDS_TO_BE_NAMED = "For queries with named parameters you need to provide names for method parameters. Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters.";
private final JdbcQueryMethod queryMethod; private final JdbcQueryMethod queryMethod;
private final Lazy<JdbcQueryExecution<?>> executor;
private final JdbcConverter converter; private final JdbcConverter converter;
private final RowMapperFactory rowMapperFactory;
private BeanFactory beanFactory; private BeanFactory beanFactory;
/** /**
@ -67,11 +73,28 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
*/ */
public StringBasedJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations, public StringBasedJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
@Nullable RowMapper<?> defaultRowMapper, JdbcConverter converter) { @Nullable RowMapper<?> defaultRowMapper, JdbcConverter converter) {
this(queryMethod, operations, result -> (RowMapper<Object>) defaultRowMapper, converter);
}
super(queryMethod, operations, defaultRowMapper); /**
* Creates a new {@link StringBasedJdbcQuery} for the given {@link JdbcQueryMethod}, {@link RelationalMappingContext}
* and {@link RowMapperFactory}.
*
* @param queryMethod must not be {@literal null}.
* @param operations must not be {@literal null}.
* @param rowMapperFactory must not be {@literal null}.
* @since 2.3
*/
public StringBasedJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
RowMapperFactory rowMapperFactory, JdbcConverter converter) {
super(queryMethod, operations);
Assert.notNull(rowMapperFactory, "RowMapperFactory must not be null");
this.queryMethod = queryMethod; this.queryMethod = queryMethod;
this.converter = converter; this.converter = converter;
this.rowMapperFactory = rowMapperFactory;
if (queryMethod.isSliceQuery()) { if (queryMethod.isSliceQuery()) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
@ -82,14 +105,6 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Page queries are not supported using string-based queries. Offending method: " + queryMethod); "Page queries are not supported using string-based queries. Offending method: " + queryMethod);
} }
executor = Lazy.of(() -> {
RowMapper<Object> rowMapper = determineRowMapper(defaultRowMapper);
return getQueryExecution( //
queryMethod, //
determineResultSetExtractor(rowMapper), //
rowMapper //
);});
} }
/* /*
@ -98,7 +113,21 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
*/ */
@Override @Override
public Object execute(Object[] objects) { public Object execute(Object[] objects) {
return executor.get().execute(determineQuery(), this.bindParameters(objects));
RelationalParameterAccessor accessor = new RelationalParametersParameterAccessor(getQueryMethod(), objects);
ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor);
ResultProcessingConverter converter = new ResultProcessingConverter(processor, this.converter.getMappingContext(),
this.converter.getEntityInstantiators());
RowMapper<Object> rowMapper = determineRowMapper(rowMapperFactory.create(resolveTypeToRead(processor)), converter,
accessor.findDynamicProjection() != null);
JdbcQueryExecution<?> queryExecution = getQueryExecution(//
queryMethod, //
determineResultSetExtractor(rowMapper), //
rowMapper);
return queryExecution.execute(determineQuery(), this.bindParameters(accessor));
} }
/* /*
@ -110,12 +139,15 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
return queryMethod; return queryMethod;
} }
private MapSqlParameterSource bindParameters(Object[] objects) { private MapSqlParameterSource bindParameters(RelationalParameterAccessor accessor) {
MapSqlParameterSource parameters = new MapSqlParameterSource(); MapSqlParameterSource parameters = new MapSqlParameterSource();
queryMethod.getParameters().getBindableParameters() Parameters<?, ?> bindableParameters = accessor.getBindableParameters();
.forEach(p -> convertAndAddParameter(parameters, p, objects[p.getIndex()]));
for (Parameter bindableParameter : bindableParameters) {
convertAndAddParameter(parameters, bindableParameter, accessor.getBindableValue(bindableParameter.getIndex()));
}
return parameters; return parameters;
} }
@ -179,6 +211,19 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
return BeanUtils.instantiateClass(resultSetExtractorClass); return BeanUtils.instantiateClass(resultSetExtractorClass);
} }
@Nullable
RowMapper<Object> determineRowMapper(@Nullable RowMapper<?> defaultMapper,
Converter<Object, Object> resultProcessingConverter, boolean hasDynamicProjection) {
RowMapper<Object> rowMapperToUse = determineRowMapper(defaultMapper);
if ((hasDynamicProjection || rowMapperToUse == defaultMapper) && rowMapperToUse != null) {
return new ConvertingRowMapper<>(rowMapperToUse, resultProcessingConverter);
}
return rowMapperToUse;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
RowMapper<Object> determineRowMapper(@Nullable RowMapper<?> defaultMapper) { RowMapper<Object> determineRowMapper(@Nullable RowMapper<?> defaultMapper) {

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

@ -103,12 +103,11 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
try { try {
if (namedQueries.hasQuery(queryMethod.getNamedQueryName()) || queryMethod.hasAnnotatedQuery()) { if (namedQueries.hasQuery(queryMethod.getNamedQueryName()) || queryMethod.hasAnnotatedQuery()) {
RowMapper<?> mapper = queryMethod.isModifyingQuery() ? null : createMapper(queryMethod); StringBasedJdbcQuery query = new StringBasedJdbcQuery(queryMethod, operations, this::createMapper, converter);
StringBasedJdbcQuery query = new StringBasedJdbcQuery(queryMethod, operations, mapper, converter);
query.setBeanFactory(beanfactory); query.setBeanFactory(beanfactory);
return query; return query;
} else { } else {
return new PartTreeJdbcQuery(context, queryMethod, dialect, converter, operations, createMapper(queryMethod)); return new PartTreeJdbcQuery(context, queryMethod, dialect, converter, operations, this::createMapper);
} }
} catch (Exception e) { } catch (Exception e) {
throw QueryCreationException.create(queryMethod, e); throw QueryCreationException.create(queryMethod, e);
@ -116,9 +115,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private RowMapper<Object> createMapper(JdbcQueryMethod queryMethod) { private RowMapper<Object> createMapper(Class<?> returnedObjectType) {
Class<?> returnedObjectType = queryMethod.getReturnedObjectType();
RelationalPersistentEntity<?> persistentEntity = context.getPersistentEntity(returnedObjectType); RelationalPersistentEntity<?> persistentEntity = context.getPersistentEntity(returnedObjectType);
@ -126,19 +123,18 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
return (RowMapper<Object>) SingleColumnRowMapper.newInstance(returnedObjectType, converter.getConversionService()); return (RowMapper<Object>) SingleColumnRowMapper.newInstance(returnedObjectType, converter.getConversionService());
} }
return (RowMapper<Object>) determineDefaultMapper(queryMethod); return (RowMapper<Object>) determineDefaultMapper(returnedObjectType);
} }
private RowMapper<?> determineDefaultMapper(JdbcQueryMethod queryMethod) { private RowMapper<?> determineDefaultMapper(Class<?> returnedObjectType) {
Class<?> domainType = queryMethod.getReturnedObjectType(); RowMapper<?> configuredQueryMapper = queryMappingConfiguration.getRowMapper(returnedObjectType);
RowMapper<?> configuredQueryMapper = queryMappingConfiguration.getRowMapper(domainType);
if (configuredQueryMapper != null) if (configuredQueryMapper != null)
return configuredQueryMapper; return configuredQueryMapper;
EntityRowMapper<?> defaultEntityRowMapper = new EntityRowMapper<>( // EntityRowMapper<?> defaultEntityRowMapper = new EntityRowMapper<>( //
context.getRequiredPersistentEntity(domainType), // context.getRequiredPersistentEntity(returnedObjectType), //
converter // converter //
); );

63
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java

@ -22,6 +22,7 @@ import static org.springframework.test.context.TestExecutionListeners.MergeMode.
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Value;
import java.io.IOException; import java.io.IOException;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -441,6 +442,50 @@ public class JdbcRepositoryIntegrationTests {
assertThat(slice.hasNext()).isTrue(); assertThat(slice.hasNext()).isTrue();
} }
@Test // #971
public void stringQueryProjectionShouldReturnProjectedEntities() {
repository.save(createDummyEntity());
List<DummyProjection> result = repository.findProjectedWithSql(DummyProjection.class);
assertThat(result).hasSize(1);
assertThat(result.get(0).getName()).isEqualTo("Entity Name");
}
@Test // #971
public void stringQueryProjectionShouldReturnDtoProjectedEntities() {
repository.save(createDummyEntity());
List<DtoProjection> result = repository.findProjectedWithSql(DtoProjection.class);
assertThat(result).hasSize(1);
assertThat(result.get(0).getName()).isEqualTo("Entity Name");
}
@Test // #971
public void partTreeQueryProjectionShouldReturnProjectedEntities() {
repository.save(createDummyEntity());
List<DummyProjection> result = repository.findProjectedByName("Entity Name");
assertThat(result).hasSize(1);
assertThat(result.get(0).getName()).isEqualTo("Entity Name");
}
@Test // #971
public void pageQueryProjectionShouldReturnProjectedEntities() {
repository.save(createDummyEntity());
Page<DummyProjection> result = repository.findPageProjectionByName("Entity Name", PageRequest.ofSize(10));
assertThat(result).hasSize(1);
assertThat(result.getContent().get(0).getName()).isEqualTo("Entity Name");
}
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> { interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {
List<DummyEntity> findAllByNamedQuery(); List<DummyEntity> findAllByNamedQuery();
@ -450,6 +495,11 @@ public class JdbcRepositoryIntegrationTests {
@Query("SELECT * FROM DUMMY_ENTITY") @Query("SELECT * FROM DUMMY_ENTITY")
List<DummyEntity> findAllWithSql(); List<DummyEntity> findAllWithSql();
@Query("SELECT * FROM DUMMY_ENTITY")
<T> List<T> findProjectedWithSql(Class<T> targetType);
List<DummyProjection> findProjectedByName(String name);
@Query(value = "SELECT * FROM DUMMY_ENTITY", rowMapperClass = CustomRowMapper.class) @Query(value = "SELECT * FROM DUMMY_ENTITY", rowMapperClass = CustomRowMapper.class)
List<DummyEntity> findAllWithCustomMapper(); List<DummyEntity> findAllWithCustomMapper();
@ -472,6 +522,8 @@ public class JdbcRepositoryIntegrationTests {
Page<DummyEntity> findPageByNameContains(String name, Pageable pageable); Page<DummyEntity> findPageByNameContains(String name, Pageable pageable);
Page<DummyProjection> findPageProjectionByName(String name, Pageable pageable);
Slice<DummyEntity> findSliceByNameContains(String name, Pageable pageable); Slice<DummyEntity> findSliceByNameContains(String name, Pageable pageable);
} }
@ -528,6 +580,17 @@ public class JdbcRepositoryIntegrationTests {
} }
} }
interface DummyProjection {
String getName();
}
@Value
static class DtoProjection {
String name;
}
static class CustomRowMapper implements RowMapper<DummyEntity> { static class CustomRowMapper implements RowMapper<DummyEntity> {
@Override @Override

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

@ -30,6 +30,7 @@ import java.util.Properties;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter; import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.JdbcConverter;
@ -46,6 +47,7 @@ import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries; import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@ -67,6 +69,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcMappingContext mappingContext = new JdbcMappingContext(); JdbcMappingContext mappingContext = new JdbcMappingContext();
JdbcConverter converter = new BasicJdbcConverter(mappingContext, mock(RelationResolver.class)); JdbcConverter converter = new BasicJdbcConverter(mappingContext, mock(RelationResolver.class));
ReturnedType returnedType = mock(ReturnedType.class);
@Test // DATAJDBC-318 @Test // DATAJDBC-318
public void shouldFailForQueryByReference() throws Exception { public void shouldFailForQueryByReference() throws Exception {
@ -108,17 +111,31 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "John" })); ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "John" }), returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name");
} }
@Test // #971
public void createsQueryToFindAllEntitiesByProjectionAttribute() throws Exception {
when(returnedType.needsCustomConstruction()).thenReturn(true);
when(returnedType.getInputProperties()).thenReturn(Collections.singletonList("firstName"));
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "John" }), returnedType);
assertThat(query.getQuery()).isEqualTo("SELECT " + TABLE + ".\"FIRST_NAME\" AS \"FIRST_NAME\" " + JOIN_CLAUSE
+ " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name");
}
@Test // DATAJDBC-318 @Test // DATAJDBC-318
public void createsQueryWithIsNullCondition() throws Exception { public void createsQueryWithIsNullCondition() throws Exception {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
ParametrizedQuery query = jdbcQuery.createQuery((getAccessor(queryMethod, new Object[] { null }))); ParametrizedQuery query = jdbcQuery.createQuery((getAccessor(queryMethod, new Object[] { null })), returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" IS NULL"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" IS NULL");
} }
@ -128,7 +145,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("existsByFirstName", String.class); JdbcQueryMethod queryMethod = getQueryMethod("existsByFirstName", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
ParametrizedQuery query = jdbcQuery.createQuery((getAccessor(queryMethod, new Object[] { "John" }))); ParametrizedQuery query = jdbcQuery.createQuery((getAccessor(queryMethod, new Object[] { "John" })), returnedType);
assertThat(query.getQuery()).isEqualTo( assertThat(query.getQuery()).isEqualTo(
"SELECT " + TABLE + ".\"ID\" FROM " + TABLE + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name LIMIT 1"); "SELECT " + TABLE + ".\"ID\" FROM " + TABLE + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name LIMIT 1");
@ -139,7 +156,8 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameAndFirstName", String.class, String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameAndFirstName", String.class, String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "Doe", "John" })); ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "Doe", "John" }),
returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"LAST_NAME\" = :last_name AND (" + TABLE assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"LAST_NAME\" = :last_name AND (" + TABLE
+ ".\"FIRST_NAME\" = :first_name)"); + ".\"FIRST_NAME\" = :first_name)");
@ -150,7 +168,8 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameOrFirstName", String.class, String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameOrFirstName", String.class, String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "Doe", "John" })); ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "Doe", "John" }),
returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"LAST_NAME\" = :last_name OR (" + TABLE assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"LAST_NAME\" = :last_name OR (" + TABLE
+ ".\"FIRST_NAME\" = :first_name)"); + ".\"FIRST_NAME\" = :first_name)");
@ -164,7 +183,7 @@ public class PartTreeJdbcQueryUnitTests {
Date from = new Date(); Date from = new Date();
Date to = new Date(); Date to = new Date();
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { from, to }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { from, to });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()) assertThat(query.getQuery())
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"DATE_OF_BIRTH\" BETWEEN :date_of_birth AND :date_of_birth1"); .isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"DATE_OF_BIRTH\" BETWEEN :date_of_birth AND :date_of_birth1");
@ -179,7 +198,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeLessThan", Integer.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeLessThan", Integer.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" < :age"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" < :age");
} }
@ -190,7 +209,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeLessThanEqual", Integer.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeLessThanEqual", Integer.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" <= :age"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" <= :age");
} }
@ -201,7 +220,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeGreaterThan", Integer.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeGreaterThan", Integer.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" > :age"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" > :age");
} }
@ -212,7 +231,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeGreaterThanEqual", Integer.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeGreaterThanEqual", Integer.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" >= :age"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" >= :age");
} }
@ -223,7 +242,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByDateOfBirthAfter", Date.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByDateOfBirthAfter", Date.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { new Date() }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { new Date() });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"DATE_OF_BIRTH\" > :date_of_birth"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"DATE_OF_BIRTH\" > :date_of_birth");
} }
@ -233,7 +252,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByDateOfBirthBefore", Date.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByDateOfBirthBefore", Date.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { new Date() }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { new Date() });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"DATE_OF_BIRTH\" < :date_of_birth"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"DATE_OF_BIRTH\" < :date_of_birth");
} }
@ -244,7 +263,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeIsNull"); JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeIsNull");
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" IS NULL"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" IS NULL");
} }
@ -255,7 +274,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeIsNotNull"); JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeIsNotNull");
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" IS NOT NULL"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" IS NOT NULL");
} }
@ -266,7 +285,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameLike", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameLike", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "%John%" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "%John%" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
} }
@ -277,7 +296,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameNotLike", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameNotLike", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "%John%" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "%John%" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" NOT LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" NOT LIKE :first_name");
} }
@ -288,7 +307,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameStartingWith", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameStartingWith", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Jo" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Jo" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
} }
@ -299,7 +318,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameStartingWith", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameStartingWith", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Jo" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Jo" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("Jo%"); assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("Jo%");
@ -311,7 +330,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameEndingWith", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameEndingWith", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "hn" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "hn" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
} }
@ -322,7 +341,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameEndingWith", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameEndingWith", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "hn" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "hn" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%hn"); assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%hn");
@ -334,7 +353,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameContaining", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameContaining", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
} }
@ -345,7 +364,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameContaining", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameContaining", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%oh%"); assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%oh%");
@ -357,7 +376,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameNotContaining", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameNotContaining", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" NOT LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" NOT LIKE :first_name");
} }
@ -368,7 +387,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameNotContaining", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameNotContaining", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" NOT LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" NOT LIKE :first_name");
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%oh%"); assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%oh%");
@ -380,7 +399,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeOrderByLastNameDesc", Integer.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeOrderByLastNameDesc", Integer.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 123 }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 123 });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()) assertThat(query.getQuery())
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" = :age ORDER BY \"LAST_NAME\" DESC"); .isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" = :age ORDER BY \"LAST_NAME\" DESC");
@ -391,7 +410,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeOrderByLastNameAsc", Integer.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByAgeOrderByLastNameAsc", Integer.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 123 }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 123 });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()) assertThat(query.getQuery())
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" = :age ORDER BY \"LAST_NAME\" ASC"); .isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" = :age ORDER BY \"LAST_NAME\" ASC");
@ -402,7 +421,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameNot", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameNot", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Doe" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Doe" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"LAST_NAME\" != :last_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"LAST_NAME\" != :last_name");
} }
@ -414,7 +433,7 @@ public class PartTreeJdbcQueryUnitTests {
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, RelationalParametersParameterAccessor accessor = getAccessor(queryMethod,
new Object[] { Collections.singleton(25) }); new Object[] { Collections.singleton(25) });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" IN (:age)"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" IN (:age)");
} }
@ -425,7 +444,7 @@ public class PartTreeJdbcQueryUnitTests {
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, RelationalParametersParameterAccessor accessor = getAccessor(queryMethod,
new Object[] { Collections.singleton(25) }); new Object[] { Collections.singleton(25) });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" NOT IN (:age)"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"AGE\" NOT IN (:age)");
} }
@ -436,7 +455,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByActiveTrue"); JdbcQueryMethod queryMethod = getQueryMethod("findAllByActiveTrue");
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"ACTIVE\" = TRUE"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"ACTIVE\" = TRUE");
} }
@ -447,7 +466,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByActiveFalse"); JdbcQueryMethod queryMethod = getQueryMethod("findAllByActiveFalse");
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"ACTIVE\" = FALSE"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"ACTIVE\" = FALSE");
} }
@ -458,7 +477,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameIgnoreCase", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameIgnoreCase", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()) assertThat(query.getQuery())
.isEqualTo(BASE_SELECT + " WHERE UPPER(" + TABLE + ".\"FIRST_NAME\") = UPPER(:first_name)"); .isEqualTo(BASE_SELECT + " WHERE UPPER(" + TABLE + ".\"FIRST_NAME\") = UPPER(:first_name)");
@ -471,7 +490,7 @@ public class PartTreeJdbcQueryUnitTests {
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
assertThatIllegalStateException() assertThatIllegalStateException()
.isThrownBy(() -> jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { 1L }))); .isThrownBy(() -> jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { 1L }), returnedType));
} }
@Test // DATAJDBC-318 @Test // DATAJDBC-318
@ -481,7 +500,7 @@ public class PartTreeJdbcQueryUnitTests {
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> jdbcQuery.createQuery(getAccessor(queryMethod, new Object[0]))); .isThrownBy(() -> jdbcQuery.createQuery(getAccessor(queryMethod, new Object[0]), returnedType));
} }
@Test // DATAJDBC-318 @Test // DATAJDBC-318
@ -491,7 +510,7 @@ public class PartTreeJdbcQueryUnitTests {
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> jdbcQuery.createQuery(getAccessor(queryMethod, new Object[0]))); .isThrownBy(() -> jdbcQuery.createQuery(getAccessor(queryMethod, new Object[0]), returnedType));
} }
@Test // DATAJDBC-318 @Test // DATAJDBC-318
@ -500,7 +519,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findTop3ByFirstName", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findTop3ByFirstName", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
String expectedSql = BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name LIMIT 3"; String expectedSql = BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name LIMIT 3";
assertThat(query.getQuery()).isEqualTo(expectedSql); assertThat(query.getQuery()).isEqualTo(expectedSql);
@ -512,7 +531,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findFirstByFirstName", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findFirstByFirstName", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
String expectedSql = BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name LIMIT 1"; String expectedSql = BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name LIMIT 1";
assertThat(query.getQuery()).isEqualTo(expectedSql); assertThat(query.getQuery()).isEqualTo(expectedSql);
@ -525,7 +544,7 @@ public class PartTreeJdbcQueryUnitTests {
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, RelationalParametersParameterAccessor accessor = getAccessor(queryMethod,
new Object[] { new Address("Hello", "World") }); new Object[] { new Address("Hello", "World") });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
String expectedSql = BASE_SELECT + " WHERE (" + TABLE + ".\"USER_STREET\" = :user_street AND " + TABLE String expectedSql = BASE_SELECT + " WHERE (" + TABLE + ".\"USER_STREET\" = :user_street AND " + TABLE
+ ".\"USER_CITY\" = :user_city)"; + ".\"USER_CITY\" = :user_city)";
@ -541,7 +560,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("findByAddressStreet", String.class); JdbcQueryMethod queryMethod = getQueryMethod("findByAddressStreet", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Hello" }); RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Hello" });
ParametrizedQuery query = jdbcQuery.createQuery(accessor); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
String expectedSql = BASE_SELECT + " WHERE " + TABLE + ".\"USER_STREET\" = :user_street"; String expectedSql = BASE_SELECT + " WHERE " + TABLE + ".\"USER_STREET\" = :user_street";
@ -554,7 +573,7 @@ public class PartTreeJdbcQueryUnitTests {
JdbcQueryMethod queryMethod = getQueryMethod("countByFirstName", String.class); JdbcQueryMethod queryMethod = getQueryMethod("countByFirstName", String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod); PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
ParametrizedQuery query = jdbcQuery.createQuery((getAccessor(queryMethod, new Object[] { "John" }))); ParametrizedQuery query = jdbcQuery.createQuery((getAccessor(queryMethod, new Object[] { "John" })), returnedType);
assertThat(query.getQuery()) assertThat(query.getQuery())
.isEqualTo("SELECT COUNT(*) FROM " + TABLE + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name"); .isEqualTo("SELECT COUNT(*) FROM " + TABLE + " WHERE " + TABLE + ".\"FIRST_NAME\" = :first_name");

5
spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/BasicRelationalConverter.java

@ -199,6 +199,11 @@ public class BasicRelationalConverter implements RelationalConverter {
return conversionService.convert(value, type.getType()); return conversionService.convert(value, type.getType());
} }
@Override
public EntityInstantiators getEntityInstantiators() {
return this.entityInstantiators;
}
/** /**
* Checks whether we have a custom conversion registered for the given value into an arbitrary simple JDBC type. * Checks whether we have a custom conversion registered for the given value into an arbitrary simple JDBC type.
* Returns the converted value if so. If not, we perform special enum handling or simply return the value as is. * Returns the converted value if so. If not, we perform special enum handling or simply return the value as is.

9
spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/RelationalConverter.java

@ -22,6 +22,7 @@ import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.PreferredConstructor.Parameter; import org.springframework.data.mapping.PreferredConstructor.Parameter;
import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.EntityInstantiators;
import org.springframework.data.mapping.model.ParameterValueProvider; import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
@ -92,4 +93,12 @@ public interface RelationalConverter {
*/ */
@Nullable @Nullable
Object writeValue(@Nullable Object value, TypeInformation<?> type); Object writeValue(@Nullable Object value, TypeInformation<?> type);
/**
* Return the underlying {@link EntityInstantiators}.
*
* @return
* @since 2.3
*/
EntityInstantiators getEntityInstantiators();
} }

4
src/main/asciidoc/jdbc.adoc

@ -1,7 +1,7 @@
[[jdbc.repositories]] [[jdbc.repositories]]
= JDBC Repositories = JDBC Repositories
This chapter points out the specialties for repository support for JDBC. This builds on the core repository support explained in <<repositories>>. This chapter points out the specialties for repository support for JDBC.This builds on the core repository support explained in <<repositories>>.
You should have a sound understanding of the basic concepts explained there. You should have a sound understanding of the basic concepts explained there.
[[jdbc.why]] [[jdbc.why]]
@ -696,6 +696,8 @@ You can specify the following return types:
* `int` (updated record count) * `int` (updated record count)
* `boolean`(whether a record was updated) * `boolean`(whether a record was updated)
include::{spring-data-commons-docs}/repository-projections.adoc[leveloffset=+2]
[[jdbc.mybatis]] [[jdbc.mybatis]]
== MyBatis Integration == MyBatis Integration

Loading…
Cancel
Save