DATAJDBC-137 - Polishing.

Moved the dependency to NamedParameterJdbcOperations out of JdbcMappingContext. This revealed that despite the DataAccessStrategy abstraction, there are a couple of places in the query execution subsystem that work with a plain NamedParameterJdbcOperations instance, so that we now have to carry that around all the way from the repository factory bean. Improving that is subject for further changes.

A bit of JavaDoc and generics polish here and there.
This commit is contained in:
Oliver Gierke
2018-05-18 15:11:27 +02:00
parent fbc271a83a
commit d0a8af21a3
34 changed files with 254 additions and 253 deletions

View File

@@ -21,7 +21,8 @@ import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
import org.springframework.data.mapping.PropertyPath;
/**
* Abstraction for accesses to the database that should be implementable with a single SQL statement and relates to a single entity as opposed to {@link JdbcEntityOperations} which provides interactions related to complete aggregates.
* Abstraction for accesses to the database that should be implementable with a single SQL statement and relates to a
* single entity as opposed to {@link JdbcEntityOperations} which provides interactions related to complete aggregates.
*
* @author Jens Schauder
* @since 1.0
@@ -68,5 +69,4 @@ public interface DataAccessStrategy {
<T> Iterable<T> findAllByProperty(Object rootId, JdbcPersistentProperty property);
<T> boolean existsById(Object id, Class<T> domainType);
}

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.data.jdbc.core;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@@ -46,34 +49,27 @@ import org.springframework.util.Assert;
* @author Jens Schauder
* @since 1.0
*/
@RequiredArgsConstructor
public class DefaultDataAccessStrategy implements DataAccessStrategy {
private static final String ENTITY_NEW_AFTER_INSERT = "Entity [%s] still 'new' after insert. Please set either"
+ " the id property in a BeforeInsert event handler, or ensure the database creates a value and your "
+ "JDBC driver returns it.";
private final SqlGeneratorSource sqlGeneratorSource;
private final NamedParameterJdbcOperations operations;
private final JdbcMappingContext context;
private final DataAccessStrategy accessStrategy;
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, JdbcMappingContext context,
DataAccessStrategy accessStrategy) {
this.sqlGeneratorSource = sqlGeneratorSource;
this.operations = context.getTemplate();
this.context = context;
this.accessStrategy = accessStrategy;
}
private final @NonNull SqlGeneratorSource sqlGeneratorSource;
private final @NonNull JdbcMappingContext context;
private final @NonNull DataAccessStrategy accessStrategy;
private final @NonNull NamedParameterJdbcOperations operations;
/**
* Creates a {@link DefaultDataAccessStrategy} which references it self for resolution of recursive data accesses.
* Only suitable if this is the only access strategy in use.
*/
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, JdbcMappingContext context) {
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, JdbcMappingContext context,
NamedParameterJdbcOperations operations) {
this.sqlGeneratorSource = sqlGeneratorSource;
this.operations = context.getTemplate();
this.operations = operations;
this.context = context;
this.accessStrategy = this;
}
@@ -110,9 +106,12 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
if (idProperty != null && idValue == null && entityInformation.isNew(instance)) {
throw new IllegalStateException(String.format(ENTITY_NEW_AFTER_INSERT, persistentEntity));
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#update(java.lang.Object, java.lang.Class)
*/
@Override
public <S> void update(S instance, Class<S> domainType) {
@@ -121,6 +120,10 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
operations.update(sql(domainType).getUpdate(), getPropertyMap(instance, persistentEntity));
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#delete(java.lang.Object, java.lang.Class)
*/
@Override
public void delete(Object id, Class<?> domainType) {
@@ -130,6 +133,10 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
operations.update(deleteByIdSql, parameter);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#delete(java.lang.Object, org.springframework.data.mapping.PropertyPath)
*/
@Override
public void delete(Object rootId, PropertyPath propertyPath) {
@@ -145,27 +152,43 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
operations.update(format, parameters);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteAll(java.lang.Class)
*/
@Override
public <T> void deleteAll(Class<T> domainType) {
operations.getJdbcOperations().update(sql(domainType).createDeleteAllSql(null));
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteAll(org.springframework.data.mapping.PropertyPath)
*/
@Override
public <T> void deleteAll(PropertyPath propertyPath) {
operations.getJdbcOperations().update(sql(propertyPath.getOwningType().getType()).createDeleteAllSql(propertyPath));
}
@SuppressWarnings("ConstantConditions")
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#count(java.lang.Class)
*/
@Override
public long count(Class<?> domainType) {
return operations.getJdbcOperations().queryForObject(sql(domainType).getCount(), Long.class);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findById(java.lang.Object, java.lang.Class)
*/
@Override
public <T> T findById(Object id, Class<T> domainType) {
String findOneSql = sql(domainType).getFindOne();
MapSqlParameterSource parameter = createIdParameterSource(id, domainType);
try {
return operations.queryForObject(findOneSql, parameter, getEntityRowMapper(domainType));
} catch (EmptyResultDataAccessException e) {
@@ -173,11 +196,19 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findAll(java.lang.Class)
*/
@Override
public <T> Iterable<T> findAll(Class<T> domainType) {
return operations.query(sql(domainType).getFindAll(), getEntityRowMapper(domainType));
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findAllById(java.lang.Iterable, java.lang.Class)
*/
@Override
public <T> Iterable<T> findAllById(Iterable<?> ids, Class<T> domainType) {
@@ -194,15 +225,19 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
return operations.query(findAllInListSql, parameter, getEntityRowMapper(domainType));
}
@SuppressWarnings("unchecked")
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findAllByProperty(java.lang.Object, org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty)
*/
@Override
@SuppressWarnings("unchecked")
public <T> Iterable<T> findAllByProperty(Object rootId, JdbcPersistentProperty property) {
Assert.notNull(rootId, "rootId must not be null.");
Class<?> actualType = property.getActualType();
String findAllByProperty = sql(actualType).getFindAllByProperty(property.getReverseColumnName(),
property.getKeyColumn(), property.isOrdered());
String findAllByProperty = sql(actualType) //
.getFindAllByProperty(property.getReverseColumnName(), property.getKeyColumn(), property.isOrdered());
MapSqlParameterSource parameter = new MapSqlParameterSource(property.getReverseColumnName(), rootId);
@@ -211,11 +246,16 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
: getEntityRowMapper(actualType));
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.DataAccessStrategy#existsById(java.lang.Object, java.lang.Class)
*/
@Override
public <T> boolean existsById(Object id, Class<T> domainType) {
String existsSql = sql(domainType).getExists();
MapSqlParameterSource parameter = createIdParameterSource(id, domainType);
return operations.queryForObject(existsSql, parameter, Boolean.class);
}

View File

@@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
@@ -35,8 +36,6 @@ import org.springframework.data.mapping.PreferredConstructor.Parameter;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Maps a ResultSet to an entity of type {@code T}, including entities referenced.
@@ -47,7 +46,7 @@ import org.springframework.util.Assert;
*/
public class EntityRowMapper<T> implements RowMapper<T> {
private static final Converter ITERABLE_OF_ENTRY_TO_MAP_CONVERTER = new IterableOfEntryToMapConverter();
private static final Converter<Iterable<?>, Map<?, ?>> ITERABLE_OF_ENTRY_TO_MAP_CONVERTER = new IterableOfEntryToMapConverter();
private final JdbcPersistentEntity<T> entity;
private final EntityInstantiator instantiator = new ClassGeneratingEntityInstantiator();
@@ -101,14 +100,12 @@ public class EntityRowMapper<T> implements RowMapper<T> {
return instantiator.createInstance(entity, new ResultSetParameterValueProvider(rs, entity, conversions, ""));
}
/**
* Read a single value or a complete Entity from the {@link ResultSet} passed as an argument.
*
* @param resultSet the {@link ResultSet} to extract the value from. Must not be {@code null}.
* @param property the {@link JdbcPersistentProperty} for which the value is intended. Must not be {@code null}.
* @param prefix to be used for all column names accessed by this method. Must not be {@code null}.
*
* @return the value read from the {@link ResultSet}. May be {@code null}.
*/
private Object readFrom(ResultSet resultSet, JdbcPersistentProperty property, String prefix) {

View File

@@ -15,27 +15,27 @@
*/
package org.springframework.data.jdbc.core;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalConverter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* A converter for creating a {@link Map} from an {@link Iterable<Map.Entry>}.
*
* @author Jens Schauder
* @since 1.0
*/
class IterableOfEntryToMapConverter implements ConditionalConverter, Converter<Iterable, Map> {
class IterableOfEntryToMapConverter implements ConditionalConverter, Converter<Iterable<?>, Map<?, ?>> {
@Nullable
@Override
public Map convert(Iterable source) {
public Map<?, ?> convert(Iterable<?> source) {
Map result = new HashMap();

View File

@@ -40,5 +40,4 @@ public interface JdbcEntityOperations {
<T> Iterable<T> findAll(Class<T> domainType);
<T> boolean existsById(Object id, Class<T> domainType);
}

View File

@@ -23,5 +23,7 @@ import org.springframework.core.convert.support.GenericConversionService;
*/
public interface ConversionCustomizer {
public static ConversionCustomizer NONE = __ -> {};
void customize(GenericConversionService conversions);
}

View File

@@ -37,7 +37,7 @@ import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.Assert;
/**
* {@link MappingContext} implementation for JDBC.
@@ -45,6 +45,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
* @author Jens Schauder
* @author Greg Turnquist
* @author Kazuki Shimizu
* @author Oliver Gierke
* @since 1.0
*/
public class JdbcMappingContext extends AbstractMappingContext<JdbcPersistentEntity<?>, JdbcPersistentProperty> {
@@ -56,24 +57,37 @@ public class JdbcMappingContext extends AbstractMappingContext<JdbcPersistentEnt
));
@Getter private final NamingStrategy namingStrategy;
@Getter private final NamedParameterJdbcOperations template;
@Getter private SimpleTypeHolder simpleTypeHolder;
private GenericConversionService conversions = getDefaultConversionService();
public JdbcMappingContext(NamingStrategy namingStrategy, NamedParameterJdbcOperations template,
ConversionCustomizer customizer) {
/**
* Creates a new {@link JdbcMappingContext}.
*/
public JdbcMappingContext() {
this(NamingStrategy.INSTANCE, ConversionCustomizer.NONE);
}
public JdbcMappingContext(NamingStrategy namingStrategy) {
this(namingStrategy, ConversionCustomizer.NONE);
}
/**
* Creates a new {@link JdbcMappingContext} using the given {@link NamingStrategy} and {@link ConversionCustomizer}.
*
* @param namingStrategy must not be {@literal null}.
* @param customizer must not be {@literal null}.
*/
public JdbcMappingContext(NamingStrategy namingStrategy, ConversionCustomizer customizer) {
Assert.notNull(namingStrategy, "NamingStrategy must not be null!");
Assert.notNull(customizer, "ConversionCustomizer must not be null!");
this.namingStrategy = namingStrategy;
this.template = template;
customizer.customize(conversions);
setSimpleTypeHolder(new SimpleTypeHolder(CUSTOM_SIMPLE_TYPES, true));
}
public JdbcMappingContext(NamedParameterJdbcOperations template) {
this(NamingStrategy.INSTANCE, template, __ -> {});
}
@Override
public void setSimpleTypeHolder(SimpleTypeHolder simpleTypes) {
super.setSimpleTypeHolder(simpleTypes);

View File

@@ -30,6 +30,7 @@ import org.springframework.data.jdbc.core.SqlGeneratorSource;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.Assert;
/**
@@ -43,6 +44,7 @@ import org.springframework.util.Assert;
*
* @author Jens Schauder
* @author Kazuki Shimizu
* @author Oliver Gierke
* @since 1.0
*/
public class MyBatisDataAccessStrategy implements DataAccessStrategy {
@@ -54,16 +56,17 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
* Create a {@link DataAccessStrategy} that first checks for queries defined by MyBatis and if it doesn't find one
* uses a {@link DefaultDataAccessStrategy}
*/
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context, SqlSession sqlSession) {
return createCombinedAccessStrategy(context, sqlSession, NamespaceStrategy.DEFAULT_INSTANCE);
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context,
NamedParameterJdbcOperations operations, SqlSession sqlSession) {
return createCombinedAccessStrategy(context, operations, sqlSession, NamespaceStrategy.DEFAULT_INSTANCE);
}
/**
* Create a {@link DataAccessStrategy} that first checks for queries defined by MyBatis and if it doesn't find one
* uses a {@link DefaultDataAccessStrategy}
*/
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context, SqlSession sqlSession,
NamespaceStrategy namespaceStrategy) {
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context,
NamedParameterJdbcOperations operations, SqlSession sqlSession, NamespaceStrategy namespaceStrategy) {
// the DefaultDataAccessStrategy needs a reference to the returned DataAccessStrategy. This creates a dependency
// cycle. In order to create it, we need something that allows to defer closing the cycle until all the elements are
@@ -75,10 +78,9 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
CascadingDataAccessStrategy cascadingDataAccessStrategy = new CascadingDataAccessStrategy(
asList(myBatisDataAccessStrategy, delegatingDataAccessStrategy));
DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy( //
new SqlGeneratorSource(context), //
context, //
cascadingDataAccessStrategy);
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context);
DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy(sqlGeneratorSource, context,
cascadingDataAccessStrategy, operations);
delegatingDataAccessStrategy.setDelegate(defaultDataAccessStrategy);
@@ -152,12 +154,12 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
@Override
public <T> void deleteAll(PropertyPath propertyPath) {
Class baseType = propertyPath.getOwningType().getType();
Class leaveType = propertyPath.getLeafProperty().getTypeInformation().getType();
Class<?> baseType = propertyPath.getOwningType().getType();
Class<?> leafType = propertyPath.getLeafProperty().getTypeInformation().getType();
sqlSession().delete( //
namespace(baseType) + ".deleteAll-" + toDashPath(propertyPath), //
new MyBatisContext(null, null, leaveType, Collections.emptyMap()) //
new MyBatisContext(null, null, leafType, Collections.emptyMap()) //
);
}

View File

@@ -22,8 +22,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.data.jdbc.mapping.model.ConversionCustomizer;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
/**
* Beans that must be registered for Spring Data JDBC to work.
@@ -36,10 +34,10 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
public class JdbcConfiguration {
@Bean
JdbcMappingContext jdbcMappingContext(NamedParameterJdbcOperations template, Optional<NamingStrategy> namingStrategy,
JdbcMappingContext jdbcMappingContext(Optional<NamingStrategy> namingStrategy,
Optional<ConversionCustomizer> conversionCustomizer) {
return new JdbcMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE), template,
conversionCustomizer.orElse(conversionService -> {}));
return new JdbcMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE),
conversionCustomizer.orElse(ConversionCustomizer.NONE));
}
}

View File

@@ -29,6 +29,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SingleColumnRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.Assert;
/**
@@ -45,6 +46,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
private final DataAccessStrategy accessStrategy;
private final RowMapperMap rowMapperMap;
private final ConversionService conversionService;
private final NamedParameterJdbcOperations operations;
/**
* Creates a new {@link JdbcQueryLookupStrategy} for the given {@link JdbcMappingContext}, {@link DataAccessStrategy}
@@ -54,7 +56,8 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
* @param accessStrategy must not be {@literal null}.
* @param rowMapperMap must not be {@literal null}.
*/
JdbcQueryLookupStrategy(JdbcMappingContext context, DataAccessStrategy accessStrategy, RowMapperMap rowMapperMap) {
JdbcQueryLookupStrategy(JdbcMappingContext context, DataAccessStrategy accessStrategy, RowMapperMap rowMapperMap,
NamedParameterJdbcOperations operations) {
Assert.notNull(context, "JdbcMappingContext must not be null!");
Assert.notNull(accessStrategy, "DataAccessStrategy must not be null!");
@@ -64,6 +67,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
this.accessStrategy = accessStrategy;
this.rowMapperMap = rowMapperMap;
this.conversionService = context.getConversions();
this.operations = operations;
}
/*
@@ -78,7 +82,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
RowMapper<?> rowMapper = queryMethod.isModifyingQuery() ? null : createRowMapper(queryMethod);
return new JdbcRepositoryQuery(queryMethod, context, rowMapper);
return new JdbcRepositoryQuery(queryMethod, operations, rowMapper);
}
private RowMapper<?> createRowMapper(JdbcQueryMethod queryMethod) {

View File

@@ -30,6 +30,7 @@ import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.Assert;
/**
@@ -45,6 +46,7 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
private final JdbcMappingContext context;
private final ApplicationEventPublisher publisher;
private final DataAccessStrategy accessStrategy;
private final NamedParameterJdbcOperations operations;
private RowMapperMap rowMapperMap = RowMapperMap.EMPTY;
@@ -55,9 +57,10 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
* @param dataAccessStrategy must not be {@literal null}.
* @param context must not be {@literal null}.
* @param publisher must not be {@literal null}.
* @param operations must not be {@literal null}.
*/
public JdbcRepositoryFactory(DataAccessStrategy dataAccessStrategy, JdbcMappingContext context,
ApplicationEventPublisher publisher) {
ApplicationEventPublisher publisher, NamedParameterJdbcOperations operations) {
Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null!");
Assert.notNull(context, "JdbcMappingContext must not be null!");
@@ -66,6 +69,7 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
this.publisher = publisher;
this.context = context;
this.accessStrategy = dataAccessStrategy;
this.operations = operations;
}
/**
@@ -123,6 +127,6 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key));
}
return Optional.of(new JdbcQueryLookupStrategy(context, accessStrategy, rowMapperMap));
return Optional.of(new JdbcQueryLookupStrategy(context, accessStrategy, rowMapperMap, operations));
}
}

View File

@@ -28,6 +28,7 @@ import org.springframework.data.jdbc.repository.RowMapperMap;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.Assert;
/**
@@ -47,6 +48,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
private JdbcMappingContext mappingContext;
private DataAccessStrategy dataAccessStrategy;
private RowMapperMap rowMapperMap = RowMapperMap.EMPTY;
private NamedParameterJdbcOperations operations;
/**
* Creates a new {@link JdbcRepositoryFactoryBean} for the given repository interface.
@@ -78,7 +80,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
protected RepositoryFactorySupport doCreateRepositoryFactory() {
JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(dataAccessStrategy, mappingContext,
publisher);
publisher, operations);
jdbcRepositoryFactory.setRowMapperMap(rowMapperMap);
return jdbcRepositoryFactory;
@@ -108,6 +110,11 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
this.rowMapperMap = rowMapperMap;
}
@Autowired
public void setJdbcOperations(NamedParameterJdbcOperations operations) {
this.operations = operations;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#afterPropertiesSet()
@@ -120,7 +127,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
if (dataAccessStrategy == null) {
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(mappingContext);
this.dataAccessStrategy = new DefaultDataAccessStrategy(sqlGeneratorSource, mappingContext);
this.dataAccessStrategy = new DefaultDataAccessStrategy(sqlGeneratorSource, mappingContext, operations);
}
if (rowMapperMap == null) {

View File

@@ -21,6 +21,7 @@ import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -38,7 +39,7 @@ class JdbcRepositoryQuery implements RepositoryQuery {
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 JdbcMappingContext context;
private final NamedParameterJdbcOperations operations;
private final RowMapper<?> rowMapper;
/**
@@ -46,20 +47,21 @@ class JdbcRepositoryQuery implements RepositoryQuery {
* {@link RowMapper}.
*
* @param queryMethod must not be {@literal null}.
* @param context 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).
*/
JdbcRepositoryQuery(JdbcQueryMethod queryMethod, JdbcMappingContext context, RowMapper<?> defaultRowMapper) {
JdbcRepositoryQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
RowMapper<?> defaultRowMapper) {
Assert.notNull(queryMethod, "Query method must not be null!");
Assert.notNull(context, "JdbcMappingContext must not be null!");
Assert.notNull(operations, "NamedParameterJdbcOperations must not be null!");
if (!queryMethod.isModifyingQuery()) {
Assert.notNull(defaultRowMapper, "RowMapper must not be null!");
}
this.queryMethod = queryMethod;
this.context = context;
this.operations = operations;
this.rowMapper = createRowMapper(queryMethod, defaultRowMapper);
}
@@ -75,18 +77,18 @@ class JdbcRepositoryQuery implements RepositoryQuery {
if (queryMethod.isModifyingQuery()) {
int updatedCount = context.getTemplate().update(query, parameters);
int updatedCount = operations.update(query, parameters);
Class<?> returnedObjectType = queryMethod.getReturnedObjectType();
return (returnedObjectType == boolean.class || returnedObjectType == Boolean.class) ? updatedCount != 0
: updatedCount;
}
if (queryMethod.isCollectionQuery() || queryMethod.isStreamQuery()) {
return context.getTemplate().query(query, parameters, rowMapper);
return operations.query(query, parameters, rowMapper);
}
try {
return context.getTemplate().queryForObject(query, parameters, rowMapper);
return operations.queryForObject(query, parameters, rowMapper);
} catch (EmptyResultDataAccessException e) {
return null;
}

View File

@@ -16,6 +16,7 @@
package org.springframework.data.jdbc.core;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import lombok.RequiredArgsConstructor;
@@ -26,7 +27,6 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.KeyHolder;
@@ -42,14 +42,12 @@ public class DefaultDataAccessStrategyUnitTests {
public static final long ORIGINAL_ID = 4711L;
NamedParameterJdbcOperations jdbcOperations = mock(NamedParameterJdbcOperations.class);
JdbcMappingContext context = new JdbcMappingContext(NamingStrategy.INSTANCE, jdbcOperations, __ -> {});
JdbcMappingContext context = new JdbcMappingContext();
HashMap<String, Object> additionalParameters = new HashMap<>();
ArgumentCaptor<SqlParameterSource> paramSourceCaptor = ArgumentCaptor.forClass(SqlParameterSource.class);
DefaultDataAccessStrategy accessStrategy = new DefaultDataAccessStrategy( //
new SqlGeneratorSource(context), //
context //
);
DefaultDataAccessStrategy accessStrategy = new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context,
jdbcOperations);
@Test // DATAJDBC-146
public void additionalParameterForIdDoesNotLeadToDuplicateParameters() {

View File

@@ -16,6 +16,7 @@
package org.springframework.data.jdbc.core;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.util.AbstractMap.SimpleEntry;
@@ -30,7 +31,6 @@ import org.springframework.data.jdbc.core.conversion.JdbcPropertyPath;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests for {@link DefaultJdbcInterpreter}
@@ -47,7 +47,7 @@ public class DefaultJdbcInterpreterUnitTests {
public String getReverseColumnName(JdbcPersistentProperty property) {
return BACK_REFERENCE;
}
}, mock(NamedParameterJdbcOperations.class), __ -> {});
});
DataAccessStrategy dataAccessStrategy = mock(DataAccessStrategy.class);
DefaultJdbcInterpreter interpreter = new DefaultJdbcInterpreter(context, dataAccessStrategy);

View File

@@ -17,6 +17,7 @@ package org.springframework.data.jdbc.core;
import static java.util.Arrays.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import lombok.RequiredArgsConstructor;
@@ -44,7 +45,6 @@ import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.Assert;
/**
@@ -175,11 +175,7 @@ public class EntityRowMapperUnitTests {
private <T> EntityRowMapper<T> createRowMapper(Class<T> type, NamingStrategy namingStrategy) {
JdbcMappingContext context = new JdbcMappingContext( //
namingStrategy, //
mock(NamedParameterJdbcOperations.class), //
__ -> {} //
);
JdbcMappingContext context = new JdbcMappingContext(namingStrategy);
DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class);
@@ -188,13 +184,13 @@ public class EntityRowMapperUnitTests {
.findAllByProperty(eq(ID_FOR_ENTITY_NOT_REFERENCING_MAP), any(JdbcPersistentProperty.class));
doReturn(new HashSet<>(asList( //
new SimpleEntry("one", new Trivial()), //
new SimpleEntry("two", new Trivial()) //
new SimpleEntry<>("one", new Trivial()), //
new SimpleEntry<>("two", new Trivial()) //
))).when(accessStrategy).findAllByProperty(eq(ID_FOR_ENTITY_REFERENCING_MAP), any(JdbcPersistentProperty.class));
doReturn(new HashSet<>(asList( //
new SimpleEntry(1, new Trivial()), //
new SimpleEntry(2, new Trivial()) //
new SimpleEntry<>(1, new Trivial()), //
new SimpleEntry<>(2, new Trivial()) //
))).when(accessStrategy).findAllByProperty(eq(ID_FOR_ENTITY_REFERENCING_LIST), any(JdbcPersistentProperty.class));
GenericConversionService conversionService = new GenericConversionService();
@@ -215,7 +211,7 @@ public class EntityRowMapperUnitTests {
"Number of values [%d] must be a multiple of the number of columns [%d]", //
values.length, //
columns.size() //
) //
) //
);
List<Map<String, Object>> result = convertValues(columns, values);

View File

@@ -16,7 +16,6 @@
package org.springframework.data.jdbc.core;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -29,7 +28,6 @@ import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests to verify a contextual {@link NamingStrategy} implementation that customizes using a user-centric
@@ -96,11 +94,9 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref.further", DummyEntity.class));
assertThat(sql).isEqualTo(
"DELETE FROM " + user + ".SecondLevelReferencedEntity " +
"WHERE " + user + ".ReferencedEntity IN " +
"(SELECT l1id FROM " + user + ".ReferencedEntity " +
"WHERE " + user + ".DummyEntity = :rootId)");
assertThat(sql)
.isEqualTo("DELETE FROM " + user + ".SecondLevelReferencedEntity " + "WHERE " + user + ".ReferencedEntity IN "
+ "(SELECT l1id FROM " + user + ".ReferencedEntity " + "WHERE " + user + ".DummyEntity = :rootId)");
});
}
@@ -126,8 +122,7 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref", DummyEntity.class));
assertThat(sql).isEqualTo(
"DELETE FROM " + user + ".ReferencedEntity WHERE " + user + ".DummyEntity IS NOT NULL");
assertThat(sql).isEqualTo("DELETE FROM " + user + ".ReferencedEntity WHERE " + user + ".DummyEntity IS NOT NULL");
});
}
@@ -140,11 +135,9 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref.further", DummyEntity.class));
assertThat(sql).isEqualTo(
"DELETE FROM " + user + ".SecondLevelReferencedEntity " +
"WHERE " + user + ".ReferencedEntity IN " +
"(SELECT l1id FROM " + user + ".ReferencedEntity " +
"WHERE " + user + ".DummyEntity IS NOT NULL)");
assertThat(sql)
.isEqualTo("DELETE FROM " + user + ".SecondLevelReferencedEntity " + "WHERE " + user + ".ReferencedEntity IN "
+ "(SELECT l1id FROM " + user + ".ReferencedEntity " + "WHERE " + user + ".DummyEntity IS NOT NULL)");
});
}
@@ -166,8 +159,8 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
}
/**
* Inside a {@link Runnable}, fetch the {@link ThreadLocal}-based username and execute the provided
* set of assertions. Then signal through the provided {@link CountDownLatch}.
* Inside a {@link Runnable}, fetch the {@link ThreadLocal}-based username and execute the provided set of assertions.
* Then signal through the provided {@link CountDownLatch}.
*/
private void threadedTest(String user, CountDownLatch latch, Consumer<String> testAssertions) {
@@ -185,7 +178,7 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
*/
private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) {
JdbcMappingContext context = new JdbcMappingContext(namingStrategy, mock(NamedParameterJdbcOperations.class), __ -> {});
JdbcMappingContext context = new JdbcMappingContext(namingStrategy);
JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
return new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));

View File

@@ -16,7 +16,6 @@
package org.springframework.data.jdbc.core;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.assertj.core.api.SoftAssertions;
import org.junit.Test;
@@ -26,7 +25,6 @@ import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests the {@link SqlGenerator} with a fixed {@link NamingStrategy} implementation containing a hard wired
@@ -170,10 +168,10 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
String sql = sqlGenerator.getDeleteByList();
assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_DummyEntity WHERE FixedCustomPropertyPrefix_id IN (:ids)");
assertThat(sql).isEqualTo(
"DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_DummyEntity WHERE FixedCustomPropertyPrefix_id IN (:ids)");
}
/**
* Plug in a custom {@link NamingStrategy} for this test case.
*
@@ -181,7 +179,7 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
*/
private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) {
JdbcMappingContext context = new JdbcMappingContext(namingStrategy, mock(NamedParameterJdbcOperations.class), __ -> {});
JdbcMappingContext context = new JdbcMappingContext(namingStrategy);
JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
return new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));
}

View File

@@ -16,7 +16,6 @@
package org.springframework.data.jdbc.core;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.Map;
import java.util.Set;
@@ -30,7 +29,6 @@ import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests for the {@link SqlGenerator}.
@@ -46,7 +44,7 @@ public class SqlGeneratorUnitTests {
public void setUp() {
NamingStrategy namingStrategy = new PrefixingNamingStrategy();
JdbcMappingContext context = new JdbcMappingContext(namingStrategy, mock(NamedParameterJdbcOperations.class), __ -> {});
JdbcMappingContext context = new JdbcMappingContext(namingStrategy);
JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
this.sqlGenerator = new SqlGenerator(context, persistentEntity, new SqlGeneratorSource(context));
}
@@ -135,7 +133,7 @@ public class SqlGeneratorUnitTests {
+ "WHERE back-ref = :back-ref");
}
@Test (expected = IllegalArgumentException.class) // DATAJDBC-130
@Test(expected = IllegalArgumentException.class) // DATAJDBC-130
public void findAllByPropertyOrderedWithoutKey() {
String sql = sqlGenerator.getFindAllByProperty("back-ref", null, true);
}
@@ -150,9 +148,7 @@ public class SqlGeneratorUnitTests {
+ "ref.x_l1id AS ref_x_l1id, ref.x_content AS ref_x_content, ref.x_further AS ref_x_further, "
+ "DummyEntity.key-column AS key-column "
+ "FROM DummyEntity LEFT OUTER JOIN ReferencedEntity AS ref ON ref.DummyEntity = DummyEntity.x_id "
+ "WHERE back-ref = :back-ref "
+ "ORDER BY key-column"
);
+ "WHERE back-ref = :back-ref " + "ORDER BY key-column");
}
@SuppressWarnings("unused")

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.jdbc.core.conversion;
import static org.mockito.Mockito.*;
import lombok.Data;
import org.assertj.core.api.Assertions;
@@ -28,7 +26,6 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.conversion.AggregateChange.Kind;
import org.springframework.data.jdbc.core.conversion.DbAction.Delete;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests for the {@link JdbcEntityDeleteWriter}
@@ -38,14 +35,14 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@RunWith(MockitoJUnitRunner.class)
public class JdbcEntityDeleteWriterUnitTests {
JdbcEntityDeleteWriter converter = new JdbcEntityDeleteWriter(new JdbcMappingContext(mock(NamedParameterJdbcOperations.class)));
JdbcEntityDeleteWriter converter = new JdbcEntityDeleteWriter(new JdbcMappingContext());
@Test
public void deleteDeletesTheEntityAndReferencedEntities() {
SomeEntity entity = new SomeEntity(23L);
AggregateChange<SomeEntity> aggregateChange = new AggregateChange(Kind.DELETE, SomeEntity.class, entity);
AggregateChange<SomeEntity> aggregateChange = new AggregateChange<>(Kind.DELETE, SomeEntity.class, entity);
converter.write(entity, aggregateChange);
@@ -54,7 +51,7 @@ public class JdbcEntityDeleteWriterUnitTests {
Tuple.tuple(Delete.class, YetAnother.class), //
Tuple.tuple(Delete.class, OtherEntity.class), //
Tuple.tuple(Delete.class, SomeEntity.class) //
);
);
}
@Data

View File

@@ -16,7 +16,6 @@
package org.springframework.data.jdbc.core.conversion;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import lombok.RequiredArgsConstructor;
@@ -36,7 +35,6 @@ import org.springframework.data.jdbc.core.conversion.DbAction.Delete;
import org.springframework.data.jdbc.core.conversion.DbAction.Insert;
import org.springframework.data.jdbc.core.conversion.DbAction.Update;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests for the {@link JdbcEntityWriter}
@@ -47,7 +45,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
public class JdbcEntityWriterUnitTests {
public static final long SOME_ENTITY_ID = 23L;
JdbcEntityWriter converter = new JdbcEntityWriter(new JdbcMappingContext(mock(NamedParameterJdbcOperations.class)));
JdbcEntityWriter converter = new JdbcEntityWriter(new JdbcMappingContext());
@Test // DATAJDBC-112
public void newEntityGetsConvertedToOneInsert() {
@@ -62,7 +60,7 @@ public class JdbcEntityWriterUnitTests {
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
.containsExactly( //
tuple(Insert.class, SingleReferenceEntity.class, "") //
);
);
}
@Test // DATAJDBC-112
@@ -79,7 +77,7 @@ public class JdbcEntityWriterUnitTests {
.containsExactly( //
tuple(Delete.class, Element.class, "other"), //
tuple(Update.class, SingleReferenceEntity.class, "") //
);
);
}
@Test // DATAJDBC-112
@@ -99,7 +97,7 @@ public class JdbcEntityWriterUnitTests {
tuple(Delete.class, Element.class, "other"), //
tuple(Update.class, SingleReferenceEntity.class, ""), //
tuple(Insert.class, Element.class, "other") //
);
);
}
@Test // DATAJDBC-113
@@ -131,7 +129,7 @@ public class JdbcEntityWriterUnitTests {
tuple(Insert.class, SetContainer.class, ""), //
tuple(Insert.class, Element.class, "elements"), //
tuple(Insert.class, Element.class, "elements") //
);
);
}
@Test // DATAJDBC-113
@@ -162,7 +160,7 @@ public class JdbcEntityWriterUnitTests {
tuple(Insert.class, CascadingReferenceMiddleElement.class, "other"), //
tuple(Insert.class, Element.class, "other.element"), //
tuple(Insert.class, Element.class, "other.element") //
);
);
}
@Test // DATAJDBC-131
@@ -195,12 +193,12 @@ public class JdbcEntityWriterUnitTests {
tuple(Insert.class, Element.class, "one", "elements"), //
tuple(Insert.class, Element.class, "two", "elements") //
).containsSubsequence( // container comes before the elements
tuple(Insert.class, MapContainer.class, null, ""), //
tuple(Insert.class, Element.class, "two", "elements") //
).containsSubsequence( // container comes before the elements
tuple(Insert.class, MapContainer.class, null, ""), //
tuple(Insert.class, Element.class, "one", "elements") //
);
tuple(Insert.class, MapContainer.class, null, ""), //
tuple(Insert.class, Element.class, "two", "elements") //
).containsSubsequence( // container comes before the elements
tuple(Insert.class, MapContainer.class, null, ""), //
tuple(Insert.class, Element.class, "one", "elements") //
);
}
@Test // DATAJDBC-183
@@ -259,8 +257,8 @@ public class JdbcEntityWriterUnitTests {
public void newEntityWithListResultsInAdditionalInsertPerElement() {
ListContainer entity = new ListContainer(null);
entity.elements.add( new Element(null));
entity.elements.add( new Element(null));
entity.elements.add(new Element(null));
entity.elements.add(new Element(null));
AggregateChange<ListContainer> aggregateChange = new AggregateChange(Kind.SAVE, ListContainer.class, entity);
converter.write(entity, aggregateChange);
@@ -272,12 +270,12 @@ public class JdbcEntityWriterUnitTests {
tuple(Insert.class, Element.class, 0, "elements"), //
tuple(Insert.class, Element.class, 1, "elements") //
).containsSubsequence( // container comes before the elements
tuple(Insert.class, ListContainer.class, null, ""), //
tuple(Insert.class, Element.class, 1, "elements") //
).containsSubsequence( // container comes before the elements
tuple(Insert.class, ListContainer.class, null, ""), //
tuple(Insert.class, Element.class, 0, "elements") //
);
tuple(Insert.class, ListContainer.class, null, ""), //
tuple(Insert.class, Element.class, 1, "elements") //
).containsSubsequence( // container comes before the elements
tuple(Insert.class, ListContainer.class, null, ""), //
tuple(Insert.class, Element.class, 0, "elements") //
);
}
@Test // DATAJDBC-131
@@ -303,7 +301,7 @@ public class JdbcEntityWriterUnitTests {
public void listTriggersDeletePlusInsert() {
ListContainer entity = new ListContainer(SOME_ENTITY_ID);
entity.elements.add( new Element(null));
entity.elements.add(new Element(null));
AggregateChange<ListContainer> aggregateChange = new AggregateChange(Kind.SAVE, ListContainer.class, entity);
@@ -379,7 +377,7 @@ public class JdbcEntityWriterUnitTests {
private static class ListContainer {
@Id final Long id;
List< Element> elements = new ArrayList<>();
List<Element> elements = new ArrayList<>();
}
@RequiredArgsConstructor

View File

@@ -16,23 +16,21 @@
package org.springframework.data.jdbc.mapping.model;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Persistable;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.lang.Nullable;
/**
* Unit tests for {@link BasicJdbcPersistentEntityInformation}.
*
* @author Jens Schauder
* @author Oliver Gierke
*/
public class BasicJdbcPersistentEntityInformationUnitTests {
JdbcMappingContext context = new JdbcMappingContext( //
NamingStrategy.INSTANCE, //
mock(NamedParameterJdbcOperations.class), //
cs -> {});
JdbcMappingContext context = new JdbcMappingContext();
private DummyEntity dummyEntity = new DummyEntity();
private PersistableDummyEntity persistableDummyEntity = new PersistableDummyEntity();

View File

@@ -16,7 +16,6 @@
package org.springframework.data.jdbc.mapping.model;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import lombok.Data;
@@ -26,16 +25,16 @@ import java.util.Date;
import org.junit.Test;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests for the {@link BasicJdbcPersistentProperty}.
*
* @author Jens Schauder
* @author Oliver Gierke
*/
public class BasicJdbcPersistentPropertyUnitTests {
JdbcMappingContext context = new JdbcMappingContext(mock(NamedParameterJdbcOperations.class));
JdbcMappingContext context = new JdbcMappingContext();
@Test // DATAJDBC-104
public void enumGetsStoredAsString() {

View File

@@ -15,42 +15,38 @@
*/
package org.springframework.data.jdbc.mapping.model;
import static org.assertj.core.api.Assertions.*;
import lombok.Data;
import org.junit.Test;
import org.springframework.data.annotation.Id;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import java.time.LocalDateTime;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.Test;
import org.springframework.data.annotation.Id;
/**
* Unit tests for the {@link DelimiterNamingStrategy}.
*
* @author Kazuki Shimizu
* @author Oliver Gierke
*/
public class DelimiterNamingStrategyUnitTests {
private final DelimiterNamingStrategy target = new DelimiterNamingStrategy();
DelimiterNamingStrategy target = new DelimiterNamingStrategy();
private final JdbcPersistentEntity<?> persistentEntity =
new JdbcMappingContext(target, mock(NamedParameterJdbcOperations.class), mock(ConversionCustomizer.class))
.getRequiredPersistentEntity(DummyEntity.class);
JdbcPersistentEntity<?> persistentEntity = new JdbcMappingContext(target)
.getRequiredPersistentEntity(DummyEntity.class);
@Test // DATAJDBC-184
public void getTableName() {
assertThat(target.getTableName(persistentEntity.getType()))
.isEqualTo("dummy_entity");
assertThat(target.getTableName(persistentEntity.getType())).isEqualTo("dummy_entity");
}
@Test // DATAJDBC-184
public void getColumnName() {
assertThat(target.getColumnName(persistentEntity.getPersistentProperty("id")))
.isEqualTo("id");
assertThat(target.getColumnName(persistentEntity.getPersistentProperty("createdAt")))
.isEqualTo("created_at");
assertThat(target.getColumnName(persistentEntity.getPersistentProperty("id"))).isEqualTo("id");
assertThat(target.getColumnName(persistentEntity.getPersistentProperty("createdAt"))).isEqualTo("created_at");
assertThat(target.getColumnName(persistentEntity.getPersistentProperty("dummySubEntities")))
.isEqualTo("dummy_sub_entities");
}
@@ -69,28 +65,24 @@ public class DelimiterNamingStrategyUnitTests {
@Test // DATAJDBC-184
public void getSchema() {
assertThat(target.getSchema())
.isEmpty();
assertThat(target.getSchema()).isEmpty();
}
@Test // DATAJDBC-184
public void getQualifiedTableName() {
assertThat(target.getQualifiedTableName(persistentEntity.getType()))
.isEqualTo("dummy_entity");
assertThat(target.getQualifiedTableName(persistentEntity.getType())).isEqualTo("dummy_entity");
}
@Data
private static class DummyEntity {
@Id
private int id;
@Id private int id;
private LocalDateTime createdAt;
private List<DummySubEntity> dummySubEntities;
}
@Data
private static class DummySubEntity {
@Id
private int id;
@Id private int id;
private LocalDateTime createdAt;
}

View File

@@ -16,55 +16,42 @@
package org.springframework.data.jdbc.mapping.model;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.List;
import org.junit.Test;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests for {@link JdbcMappingContext}.
*
* @author Jens Schauder
* @author Oliver Gierke
*/
public class JdbcMappingContextUnitTests {
NamingStrategy namingStrategy = NamingStrategy.INSTANCE;
NamedParameterJdbcOperations jdbcTemplate = mock(NamedParameterJdbcOperations.class);
ConversionCustomizer customizer = mock(ConversionCustomizer.class);
@Test // DATAJDBC-142
public void referencedEntitiesGetFound() {
JdbcMappingContext mappingContext = new JdbcMappingContext(namingStrategy, jdbcTemplate, customizer);
JdbcMappingContext mappingContext = new JdbcMappingContext();
List<PropertyPath> propertyPaths = mappingContext.referencedEntities(DummyEntity.class, null);
assertThat(propertyPaths) //
.extracting(PropertyPath::toDotPath) //
.containsExactly( //
"one.two", //
"one" //
);
.containsExactly("one.two", "one");
}
@Test // DATAJDBC-142
public void propertyPathDoesNotDependOnNamingStrategy() {
namingStrategy = mock(NamingStrategy.class);
JdbcMappingContext mappingContext = new JdbcMappingContext(namingStrategy, jdbcTemplate, customizer);
JdbcMappingContext mappingContext = new JdbcMappingContext();
List<PropertyPath> propertyPaths = mappingContext.referencedEntities(DummyEntity.class, null);
assertThat(propertyPaths) //
.extracting(PropertyPath::toDotPath) //
.containsExactly( //
"one.two", //
"one" //
);
.containsExactly("one.two", "one");
}
static class DummyEntity {

View File

@@ -16,10 +16,8 @@
package org.springframework.data.jdbc.mapping.model;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests for {@link JdbcPersistentEntityImpl}.
@@ -29,7 +27,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
*/
public class JdbcPersistentEntityImplUnitTests {
JdbcMappingContext mappingContext = new JdbcMappingContext(mock(NamedParameterJdbcOperations.class));
JdbcMappingContext mappingContext = new JdbcMappingContext();
@Test // DATAJDBC-106
public void discoversAnnotatedTableName() {

View File

@@ -16,7 +16,6 @@
package org.springframework.data.jdbc.mapping.model;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.time.LocalDateTime;
import java.util.List;
@@ -24,7 +23,6 @@ import java.util.List;
import org.junit.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntityImplUnitTests.DummySubEntity;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* Unit tests for the {@link NamingStrategy}.
@@ -35,8 +33,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
public class NamingStrategyUnitTests {
private final NamingStrategy target = NamingStrategy.INSTANCE;
private final JdbcMappingContext context = new JdbcMappingContext(target, mock(NamedParameterJdbcOperations.class),
mock(ConversionCustomizer.class));
private final JdbcMappingContext context = new JdbcMappingContext(target);
private final JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(DummyEntity.class);
@Test

View File

@@ -35,6 +35,7 @@ import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
import org.springframework.data.jdbc.testing.TestConfiguration;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
@@ -85,8 +86,9 @@ public class MyBatisHsqlIntegrationTests {
}
@Bean
DataAccessStrategy dataAccessStrategy(JdbcMappingContext context, SqlSession sqlSession) {
return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, sqlSession);
DataAccessStrategy dataAccessStrategy(JdbcMappingContext context, SqlSession sqlSession, EmbeddedDatabase db) {
return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, new NamedParameterJdbcTemplate(db),
sqlSession);
}
}

View File

@@ -20,8 +20,6 @@ import static org.assertj.core.api.Assertions.*;
import lombok.Data;
import lombok.Value;
import javax.sql.DataSource;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
@@ -140,10 +138,5 @@ public class JdbcRepositoryIdGenerationIntegrationTests {
}
};
}
@Bean
NamedParameterJdbcTemplate template(DataSource db) {
return new NamedParameterJdbcTemplate(db);
}
}
}

View File

@@ -67,19 +67,16 @@ public class SimpleJdbcRepositoryEventsUnitTests {
@Before
public void before() {
JdbcMappingContext context = new JdbcMappingContext(createIdGeneratingOperations());
JdbcMappingContext context = new JdbcMappingContext();
dataAccessStrategy = spy(new DefaultDataAccessStrategy( //
new SqlGeneratorSource(context), //
context //
));
NamedParameterJdbcOperations operations = createIdGeneratingOperations();
SqlGeneratorSource generatorSource = new SqlGeneratorSource(context);
JdbcRepositoryFactory factory = new JdbcRepositoryFactory( //
dataAccessStrategy, //
context, //
publisher);
this.dataAccessStrategy = spy(new DefaultDataAccessStrategy(generatorSource, context, operations));
repository = factory.getRepository(DummyEntityRepository.class);
JdbcRepositoryFactory factory = new JdbcRepositoryFactory(dataAccessStrategy, context, publisher, operations);
this.repository = factory.getRepository(DummyEntityRepository.class);
}
@Test // DATAJDBC-99

View File

@@ -33,6 +33,7 @@ import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
/**
@@ -48,6 +49,7 @@ public class JdbcQueryLookupStrategyUnitTests {
ProjectionFactory projectionFactory = mock(ProjectionFactory.class);
RepositoryMetadata metadata;
NamedQueries namedQueries = mock(NamedQueries.class);
NamedParameterJdbcOperations operations = mock(NamedParameterJdbcOperations.class);
@Before
public void setup() {
@@ -69,14 +71,13 @@ public class JdbcQueryLookupStrategyUnitTests {
repositoryQuery.execute(new Object[] {});
verify(mappingContext.getTemplate()).queryForObject(anyString(), any(SqlParameterSource.class),
eq(numberFormatMapper));
verify(operations).queryForObject(anyString(), any(SqlParameterSource.class), eq(numberFormatMapper));
}
private RepositoryQuery getRepositoryQuery(String name, RowMapperMap rowMapperMap) {
JdbcQueryLookupStrategy queryLookupStrategy = new JdbcQueryLookupStrategy(mappingContext, accessStrategy,
rowMapperMap);
rowMapperMap, operations);
return queryLookupStrategy.resolveQuery(getMethod(name), metadata, projectionFactory, namedQueries);
}

View File

@@ -31,7 +31,6 @@ import org.springframework.data.jdbc.core.DefaultDataAccessStrategy;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.repository.RowMapperMap;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.test.util.ReflectionTestUtils;
/**
@@ -55,7 +54,7 @@ public class JdbcRepositoryFactoryBeanUnitTests {
@Before
public void setUp() {
this.mappingContext = new JdbcMappingContext(mock(NamedParameterJdbcOperations.class));
this.mappingContext = new JdbcMappingContext();
// Setup standard configuration
factoryBean = new JdbcRepositoryFactoryBean<>(DummyEntityRepository.class);

View File

@@ -23,10 +23,10 @@ import java.sql.ResultSet;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.repository.query.DefaultParameters;
import org.springframework.data.repository.query.Parameters;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
/**
@@ -38,9 +38,10 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
public class JdbcRepositoryQueryUnitTests {
JdbcQueryMethod queryMethod;
JdbcMappingContext context;
RowMapper<?> defaultRowMapper;
JdbcRepositoryQuery query;
NamedParameterJdbcOperations operations;
@Before
public void setup() throws NoSuchMethodException {
@@ -51,10 +52,10 @@ public class JdbcRepositoryQueryUnitTests {
JdbcRepositoryQueryUnitTests.class.getDeclaredMethod("dummyMethod"));
doReturn(parameters).when(queryMethod).getParameters();
this.context = mock(JdbcMappingContext.class, RETURNS_DEEP_STUBS);
this.defaultRowMapper = mock(RowMapper.class);
this.operations = mock(NamedParameterJdbcOperations.class);
this.query = new JdbcRepositoryQuery(queryMethod, context, defaultRowMapper);
this.query = new JdbcRepositoryQuery(queryMethod, operations, defaultRowMapper);
}
@Test // DATAJDBC-165
@@ -74,7 +75,7 @@ public class JdbcRepositoryQueryUnitTests {
query.execute(new Object[] {});
verify(context.getTemplate()).queryForObject(anyString(), any(SqlParameterSource.class), eq(defaultRowMapper));
verify(operations).queryForObject(anyString(), any(SqlParameterSource.class), eq(defaultRowMapper));
}
@Test // DATAJDBC-165
@@ -84,7 +85,7 @@ public class JdbcRepositoryQueryUnitTests {
query.execute(new Object[] {});
verify(context.getTemplate()).queryForObject(anyString(), any(SqlParameterSource.class), eq(defaultRowMapper));
verify(operations).queryForObject(anyString(), any(SqlParameterSource.class), eq(defaultRowMapper));
}
@Test // DATAJDBC-165
@@ -93,9 +94,9 @@ public class JdbcRepositoryQueryUnitTests {
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
doReturn(CustomRowMapper.class).when(queryMethod).getRowMapperClass();
new JdbcRepositoryQuery(queryMethod, context, defaultRowMapper).execute(new Object[] {});
new JdbcRepositoryQuery(queryMethod, operations, defaultRowMapper).execute(new Object[] {});
verify(context.getTemplate()) //
verify(operations) //
.queryForObject(anyString(), any(SqlParameterSource.class), isA(CustomRowMapper.class));
}

View File

@@ -54,14 +54,9 @@ public class TestConfiguration {
@Bean
JdbcRepositoryFactory jdbcRepositoryFactory(DataAccessStrategy dataAccessStrategy) {
NamedParameterJdbcOperations jdbcTemplate = namedParameterJdbcTemplate();
JdbcMappingContext context = new JdbcMappingContext(NamingStrategy.INSTANCE);
final JdbcMappingContext context = new JdbcMappingContext(NamingStrategy.INSTANCE, jdbcTemplate, __ -> {});
return new JdbcRepositoryFactory( //
dataAccessStrategy, //
context, //
publisher);
return new JdbcRepositoryFactory(dataAccessStrategy, context, publisher, namedParameterJdbcTemplate());
}
@Bean
@@ -76,17 +71,14 @@ public class TestConfiguration {
@Bean
DataAccessStrategy defaultDataAccessStrategy(JdbcMappingContext context) {
return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context);
return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context, namedParameterJdbcTemplate());
}
@Bean
JdbcMappingContext jdbcMappingContext(NamedParameterJdbcOperations template, Optional<NamingStrategy> namingStrategy,
Optional<ConversionCustomizer> conversionCustomizer) {
return new JdbcMappingContext( //
namingStrategy.orElse(NamingStrategy.INSTANCE), //
template, //
conversionCustomizer.orElse(conversionService -> {}) //
);
return new JdbcMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE),
conversionCustomizer.orElse(conversionService -> {}));
}
}