DATAJDBC-137 - Cleanups in the repository and repository.support packages.
This commit is contained in:
@@ -100,7 +100,7 @@ public class CascadingDataAccessStrategy implements DataAccessStrategy {
|
||||
}
|
||||
|
||||
private <T> T collect(Function<DataAccessStrategy, T> function) {
|
||||
return strategies.stream().collect(new FunctionCollector<>(function));
|
||||
return strategies.stream().collect(new FunctionCollector<T>(function));
|
||||
}
|
||||
|
||||
private void collectVoid(Consumer<DataAccessStrategy> consumer) {
|
||||
|
||||
@@ -30,6 +30,10 @@ public interface RowMapperMap {
|
||||
*/
|
||||
RowMapperMap EMPTY = new RowMapperMap() {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.repository.RowMapperMap#rowMapperFor(java.lang.Class)
|
||||
*/
|
||||
public <T> RowMapper<? extends T> rowMapperFor(Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -15,34 +15,27 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.jdbc.core.JdbcEntityOperations;
|
||||
import org.springframework.data.jdbc.core.JdbcEntityTemplate;
|
||||
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntityInformation;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Jens Schauder
|
||||
* @author Oliver Gierke
|
||||
* @since 1.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
|
||||
|
||||
private final JdbcPersistentEntityInformation<T, ID> entityInformation;
|
||||
|
||||
private final JdbcEntityOperations entityOperations;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleJdbcRepository}.
|
||||
*/
|
||||
public SimpleJdbcRepository(JdbcEntityTemplate entityOperations,
|
||||
JdbcPersistentEntityInformation<T, ID> entityInformation) {
|
||||
|
||||
this.entityOperations = entityOperations;
|
||||
this.entityInformation = entityInformation;
|
||||
}
|
||||
private final @NonNull JdbcEntityOperations entityOperations;
|
||||
private final @NonNull JdbcPersistentEntityInformation<T, ID> entityInformation;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -136,12 +129,9 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
|
||||
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void deleteAll(Iterable<? extends T> entities) {
|
||||
|
||||
for (T entity : entities) {
|
||||
entityOperations.delete(entity, (Class<T>) entity.getClass());
|
||||
|
||||
}
|
||||
entities.forEach(it -> entityOperations.delete(it, (Class<T>) it.getClass()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,16 +26,17 @@ import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.SingleColumnRowMapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link QueryLookupStrategy} for JDBC repositories. Currently only supports annotated queries.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Kazuki Shimizu
|
||||
* @author Oliver Gierke
|
||||
* @since 1.0
|
||||
*/
|
||||
class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
@@ -45,8 +46,19 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
private final RowMapperMap rowMapperMap;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
JdbcQueryLookupStrategy(QueryMethodEvaluationContextProvider evaluationContextProvider, JdbcMappingContext context,
|
||||
DataAccessStrategy accessStrategy, RowMapperMap rowMapperMap) {
|
||||
/**
|
||||
* Creates a new {@link JdbcQueryLookupStrategy} for the given {@link JdbcMappingContext}, {@link DataAccessStrategy}
|
||||
* and {@link RowMapperMap}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param accessStrategy must not be {@literal null}.
|
||||
* @param rowMapperMap must not be {@literal null}.
|
||||
*/
|
||||
JdbcQueryLookupStrategy(JdbcMappingContext context, DataAccessStrategy accessStrategy, RowMapperMap rowMapperMap) {
|
||||
|
||||
Assert.notNull(context, "JdbcMappingContext must not be null!");
|
||||
Assert.notNull(accessStrategy, "DataAccessStrategy must not be null!");
|
||||
Assert.notNull(rowMapperMap, "RowMapperMap must not be null!");
|
||||
|
||||
this.context = context;
|
||||
this.accessStrategy = accessStrategy;
|
||||
@@ -54,6 +66,10 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
this.conversionService = context.getConversions();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries)
|
||||
*/
|
||||
@Override
|
||||
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata repositoryMetadata,
|
||||
ProjectionFactory projectionFactory, NamedQueries namedQueries) {
|
||||
@@ -78,7 +94,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
|
||||
Class<?> domainType = queryMethod.getReturnedObjectType();
|
||||
|
||||
RowMapper typeMappedRowMapper = rowMapperMap.rowMapperFor(domainType);
|
||||
RowMapper<?> typeMappedRowMapper = rowMapperMap.rowMapperFor(domainType);
|
||||
|
||||
return typeMappedRowMapper == null //
|
||||
? new EntityRowMapper<>( //
|
||||
|
||||
@@ -45,38 +45,73 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
|
||||
private final JdbcMappingContext context;
|
||||
private final ApplicationEventPublisher publisher;
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
|
||||
private RowMapperMap rowMapperMap = RowMapperMap.EMPTY;
|
||||
|
||||
public JdbcRepositoryFactory(ApplicationEventPublisher publisher, JdbcMappingContext context,
|
||||
DataAccessStrategy dataAccessStrategy) {
|
||||
/**
|
||||
* Creates a new {@link JdbcRepositoryFactory} for the given {@link DataAccessStrategy}, {@link JdbcMappingContext}
|
||||
* and {@link ApplicationEventPublisher}.
|
||||
*
|
||||
* @param dataAccessStrategy must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
* @param publisher must not be {@literal null}.
|
||||
*/
|
||||
public JdbcRepositoryFactory(DataAccessStrategy dataAccessStrategy, JdbcMappingContext context,
|
||||
ApplicationEventPublisher publisher) {
|
||||
|
||||
Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null!");
|
||||
Assert.notNull(context, "JdbcMappingContext must not be null!");
|
||||
Assert.notNull(publisher, "ApplicationEventPublisher must not be null!");
|
||||
|
||||
this.publisher = publisher;
|
||||
this.context = context;
|
||||
this.accessStrategy = dataAccessStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rowMapperMap must not be {@literal null} consider {@link RowMapperMap#EMPTY} instead.
|
||||
*/
|
||||
public void setRowMapperMap(RowMapperMap rowMapperMap) {
|
||||
|
||||
Assert.notNull(rowMapperMap, "RowMapperMap must not be null!");
|
||||
|
||||
this.rowMapperMap = rowMapperMap;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> aClass) {
|
||||
return (EntityInformation<T, ID>) context.getRequiredPersistentEntityInformation(aClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryInformation)
|
||||
*/
|
||||
@Override
|
||||
protected Object getTargetRepository(RepositoryInformation repositoryInformation) {
|
||||
|
||||
JdbcPersistentEntityInformation persistentEntityInformation = context
|
||||
JdbcPersistentEntityInformation<?, ?> persistentEntityInformation = context
|
||||
.getRequiredPersistentEntityInformation(repositoryInformation.getDomainType());
|
||||
|
||||
JdbcEntityTemplate template = new JdbcEntityTemplate(publisher, context, accessStrategy);
|
||||
|
||||
return new SimpleJdbcRepository<>(template, persistentEntityInformation);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryBaseClass(org.springframework.data.repository.core.RepositoryMetadata)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata repositoryMetadata) {
|
||||
return SimpleJdbcRepository.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key, org.springframework.data.repository.query.EvaluationContextProvider)
|
||||
*/
|
||||
@Override
|
||||
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(QueryLookupStrategy.Key key,
|
||||
QueryMethodEvaluationContextProvider evaluationContextProvider) {
|
||||
@@ -88,15 +123,6 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
|
||||
throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key));
|
||||
}
|
||||
|
||||
return Optional.of(new JdbcQueryLookupStrategy(evaluationContextProvider, context, accessStrategy, rowMapperMap));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rowMapperMap must not be {@literal null} consider {@link RowMapperMap#EMPTY} instead.
|
||||
*/
|
||||
public void setRowMapperMap(RowMapperMap rowMapperMap) {
|
||||
|
||||
Assert.notNull(rowMapperMap, "RowMapperMap must not be null!");
|
||||
this.rowMapperMap = rowMapperMap;
|
||||
return Optional.of(new JdbcQueryLookupStrategy(context, accessStrategy, rowMapperMap));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.util.Assert;
|
||||
* @author Jens Schauder
|
||||
* @author Greg Turnquist
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.0
|
||||
*/
|
||||
public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> //
|
||||
@@ -47,14 +48,24 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
private DataAccessStrategy dataAccessStrategy;
|
||||
private RowMapperMap rowMapperMap = RowMapperMap.EMPTY;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JdbcRepositoryFactoryBean} for the given repository interface.
|
||||
*
|
||||
* @param repositoryInterface must not be {@literal null}.
|
||||
*/
|
||||
JdbcRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
|
||||
super(repositoryInterface);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
|
||||
|
||||
super.setApplicationEventPublisher(publisher);
|
||||
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
@@ -66,8 +77,8 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
@Override
|
||||
protected RepositoryFactorySupport doCreateRepositoryFactory() {
|
||||
|
||||
JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(publisher, mappingContext,
|
||||
dataAccessStrategy);
|
||||
JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(dataAccessStrategy, mappingContext,
|
||||
publisher);
|
||||
jdbcRepositoryFactory.setRowMapperMap(rowMapperMap);
|
||||
|
||||
return jdbcRepositoryFactory;
|
||||
@@ -97,6 +108,10 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
this.rowMapperMap = rowMapperMap;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
@@ -104,13 +119,12 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
|
||||
if (dataAccessStrategy == null) {
|
||||
|
||||
dataAccessStrategy = new DefaultDataAccessStrategy( //
|
||||
new SqlGeneratorSource(mappingContext), //
|
||||
mappingContext);
|
||||
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(mappingContext);
|
||||
this.dataAccessStrategy = new DefaultDataAccessStrategy(sqlGeneratorSource, mappingContext);
|
||||
}
|
||||
|
||||
if (rowMapperMap == null) {
|
||||
rowMapperMap = RowMapperMap.EMPTY;
|
||||
this.rowMapperMap = RowMapperMap.EMPTY;
|
||||
}
|
||||
|
||||
super.afterPropertiesSet();
|
||||
|
||||
@@ -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.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -29,6 +30,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Kazuki Shimizu
|
||||
* @author Oliver Gierke
|
||||
* @since 1.0
|
||||
*/
|
||||
class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
@@ -39,26 +41,36 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
private final JdbcMappingContext context;
|
||||
private final RowMapper<?> rowMapper;
|
||||
|
||||
JdbcRepositoryQuery(JdbcQueryMethod queryMethod, JdbcMappingContext context, RowMapper defaultRowMapper) {
|
||||
/**
|
||||
* Creates a new {@link JdbcRepositoryQuery} for the given {@link JdbcQueryMethod}, {@link JdbcMappingContext} and
|
||||
* {@link RowMapper}.
|
||||
*
|
||||
* @param queryMethod must not be {@literal null}.
|
||||
* @param context 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) {
|
||||
|
||||
Assert.notNull(queryMethod, "Query method must not be null!");
|
||||
Assert.notNull(context, "JdbcMappingContext must not be null!");
|
||||
|
||||
if (!queryMethod.isModifyingQuery()) {
|
||||
Assert.notNull(defaultRowMapper, "RowMapper must not be null!");
|
||||
}
|
||||
|
||||
this.queryMethod = queryMethod;
|
||||
this.context = context;
|
||||
this.rowMapper = createRowMapper(queryMethod, defaultRowMapper);
|
||||
}
|
||||
|
||||
private static RowMapper<?> createRowMapper(JdbcQueryMethod queryMethod, RowMapper defaultRowMapper) {
|
||||
|
||||
Class<?> rowMapperClass = queryMethod.getRowMapperClass();
|
||||
|
||||
return rowMapperClass == null || rowMapperClass == RowMapper.class ? defaultRowMapper
|
||||
: (RowMapper<?>) BeanUtils.instantiateClass(rowMapperClass);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public Object execute(Object[] objects) {
|
||||
|
||||
String query = determineQuery();
|
||||
|
||||
MapSqlParameterSource parameters = bindParameters(objects);
|
||||
|
||||
if (queryMethod.isModifyingQuery()) {
|
||||
@@ -80,6 +92,10 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod()
|
||||
*/
|
||||
@Override
|
||||
public JdbcQueryMethod getQueryMethod() {
|
||||
return queryMethod;
|
||||
@@ -92,17 +108,29 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
if (StringUtils.isEmpty(query)) {
|
||||
throw new IllegalStateException(String.format("No query specified on %s", queryMethod.getName()));
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private MapSqlParameterSource bindParameters(Object[] objects) {
|
||||
|
||||
MapSqlParameterSource parameters = new MapSqlParameterSource();
|
||||
|
||||
queryMethod.getParameters().getBindableParameters().forEach(p -> {
|
||||
|
||||
String parameterName = p.getName().orElseThrow(() -> new IllegalStateException(PARAMETER_NEEDS_TO_BE_NAMED));
|
||||
parameters.addValue(parameterName, objects[p.getIndex()]);
|
||||
});
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private static RowMapper<?> createRowMapper(JdbcQueryMethod queryMethod, RowMapper<?> defaultRowMapper) {
|
||||
|
||||
Class<?> rowMapperClass = queryMethod.getRowMapperClass();
|
||||
|
||||
return rowMapperClass == null || rowMapperClass == RowMapper.class //
|
||||
? defaultRowMapper //
|
||||
: (RowMapper<?>) BeanUtils.instantiateClass(rowMapperClass);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static java.util.Arrays.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import lombok.Data;
|
||||
@@ -80,7 +80,7 @@ public class JdbcRepositoryManipulateDbActionsIntegrationTests {
|
||||
entity.id, //
|
||||
entity.name, //
|
||||
true) //
|
||||
);
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -103,14 +103,14 @@ public class JdbcRepositoryManipulateDbActionsIntegrationTests {
|
||||
one.id, //
|
||||
one.name, //
|
||||
true) //
|
||||
);
|
||||
);
|
||||
|
||||
assertThat(repository.findById(two.id)) //
|
||||
.contains(new DummyEntity( //
|
||||
two.id, //
|
||||
two.name, //
|
||||
true) //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-120
|
||||
@@ -203,7 +203,7 @@ public class JdbcRepositoryManipulateDbActionsIntegrationTests {
|
||||
DummyEntity entity = (DummyEntity) event.getOptionalEntity().orElseThrow(AssertionFailedError::new);
|
||||
entity.deleted = true;
|
||||
|
||||
List<DbAction> actions = event.getChange().getActions();
|
||||
List<DbAction<?>> actions = event.getChange().getActions();
|
||||
actions.clear();
|
||||
actions.add(DbAction.update(entity, null, null));
|
||||
};
|
||||
@@ -222,8 +222,7 @@ public class JdbcRepositoryManipulateDbActionsIntegrationTests {
|
||||
log.entity = entity;
|
||||
log.text = entity.name + " saved";
|
||||
|
||||
|
||||
List<DbAction> actions = event.getChange().getActions();
|
||||
List<DbAction<?>> actions = event.getChange().getActions();
|
||||
actions.add(DbAction.insert(log, null, null));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -76,7 +75,7 @@ public class JdbcRepositoryPropertyConversionIntegrationTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
ApplicationListener applicationListener() {
|
||||
ApplicationListener<?> applicationListener() {
|
||||
return (ApplicationListener<BeforeSaveEvent>) beforeInsert -> ((EntityWithColumnsRequiringConversions) beforeInsert
|
||||
.getEntity()).setIdTimestamp(getNow());
|
||||
}
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
/*
|
||||
* Copyright 2017-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
@@ -42,6 +55,7 @@ import org.springframework.jdbc.support.KeyHolder;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
|
||||
@@ -61,15 +75,15 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
));
|
||||
|
||||
JdbcRepositoryFactory factory = new JdbcRepositoryFactory( //
|
||||
publisher, //
|
||||
dataAccessStrategy, //
|
||||
context, //
|
||||
dataAccessStrategy //
|
||||
);
|
||||
publisher);
|
||||
|
||||
repository = factory.getRepository(DummyEntityRepository.class);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-99
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void publishesEventsOnSave() {
|
||||
|
||||
DummyEntity entity = new DummyEntity(23L);
|
||||
@@ -81,10 +95,11 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
.containsExactly( //
|
||||
BeforeSaveEvent.class, //
|
||||
AfterSaveEvent.class //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-99
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void publishesEventsOnSaveMany() {
|
||||
|
||||
DummyEntity entity1 = new DummyEntity(null);
|
||||
@@ -99,7 +114,7 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
AfterSaveEvent.class, //
|
||||
BeforeSaveEvent.class, //
|
||||
AfterSaveEvent.class //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-99
|
||||
@@ -120,6 +135,7 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-99
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void publishesEventsOnDeleteById() {
|
||||
|
||||
repository.deleteById(23L);
|
||||
@@ -129,16 +145,17 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
.containsExactly( //
|
||||
BeforeDeleteEvent.class, //
|
||||
AfterDeleteEvent.class //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-197
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void publishesEventsOnFindAll() {
|
||||
|
||||
DummyEntity entity1 = new DummyEntity(42L);
|
||||
DummyEntity entity2 = new DummyEntity(23L);
|
||||
|
||||
doReturn(asList(entity1, entity2)).when(dataAccessStrategy).findAll(any(Class.class));
|
||||
doReturn(asList(entity1, entity2)).when(dataAccessStrategy).findAll(any());
|
||||
|
||||
repository.findAll();
|
||||
|
||||
@@ -147,16 +164,17 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
.containsExactly( //
|
||||
AfterLoadEvent.class, //
|
||||
AfterLoadEvent.class //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-197
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void publishesEventsOnFindAllById() {
|
||||
|
||||
DummyEntity entity1 = new DummyEntity(42L);
|
||||
DummyEntity entity2 = new DummyEntity(23L);
|
||||
|
||||
doReturn(asList(entity1, entity2)).when(dataAccessStrategy).findAllById(any(Iterable.class), any(Class.class));
|
||||
doReturn(asList(entity1, entity2)).when(dataAccessStrategy).findAllById(any(), any());
|
||||
|
||||
repository.findAllById(asList(42L, 23L));
|
||||
|
||||
@@ -165,14 +183,16 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
.containsExactly( //
|
||||
AfterLoadEvent.class, //
|
||||
AfterLoadEvent.class //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-197
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void publishesEventsOnFindById() {
|
||||
|
||||
DummyEntity entity1 = new DummyEntity(23L);
|
||||
doReturn(entity1).when(dataAccessStrategy).findById(eq(23L), any(Class.class));
|
||||
|
||||
doReturn(entity1).when(dataAccessStrategy).findById(eq(23L), any());
|
||||
|
||||
repository.findById(23L);
|
||||
|
||||
@@ -180,7 +200,7 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
.extracting(e -> (Class) e.getClass()) //
|
||||
.containsExactly( //
|
||||
AfterLoadEvent.class //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
private static NamedParameterJdbcOperations createIdGeneratingOperations() {
|
||||
|
||||
@@ -31,7 +31,6 @@ import org.springframework.data.jdbc.repository.query.Query;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
@@ -40,10 +39,10 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
* Unit tests for {@link JdbcQueryLookupStrategy}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class JdbcQueryLookupStrategyUnitTests {
|
||||
|
||||
QueryMethodEvaluationContextProvider evaluationContextProvider = mock(QueryMethodEvaluationContextProvider.class);
|
||||
JdbcMappingContext mappingContext = mock(JdbcMappingContext.class, RETURNS_DEEP_STUBS);
|
||||
DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class);
|
||||
ProjectionFactory projectionFactory = mock(ProjectionFactory.class);
|
||||
@@ -53,24 +52,17 @@ public class JdbcQueryLookupStrategyUnitTests {
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
metadata = mock(RepositoryMetadata.class);
|
||||
when(metadata.getReturnedDomainClass(any(Method.class))).thenReturn((Class) NumberFormat.class);
|
||||
this.metadata = mock(RepositoryMetadata.class);
|
||||
|
||||
}
|
||||
doReturn(NumberFormat.class).when(metadata).getReturnedDomainClass(any(Method.class));
|
||||
|
||||
private Method getMethod(String name) {
|
||||
|
||||
try {
|
||||
return this.getClass().getDeclaredMethod(name);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-166
|
||||
@SuppressWarnings("unchecked")
|
||||
public void typeBasedRowMapperGetsUsedForQuery() {
|
||||
|
||||
RowMapper numberFormatMapper = mock(RowMapper.class);
|
||||
RowMapper<? extends NumberFormat> numberFormatMapper = mock(RowMapper.class);
|
||||
RowMapperMap rowMapperMap = new ConfigurableRowMapperMap().register(NumberFormat.class, numberFormatMapper);
|
||||
|
||||
RepositoryQuery repositoryQuery = getRepositoryQuery("returningNumberFormat", rowMapperMap);
|
||||
@@ -83,8 +75,8 @@ public class JdbcQueryLookupStrategyUnitTests {
|
||||
|
||||
private RepositoryQuery getRepositoryQuery(String name, RowMapperMap rowMapperMap) {
|
||||
|
||||
JdbcQueryLookupStrategy queryLookupStrategy = new JdbcQueryLookupStrategy(evaluationContextProvider, mappingContext,
|
||||
accessStrategy, rowMapperMap);
|
||||
JdbcQueryLookupStrategy queryLookupStrategy = new JdbcQueryLookupStrategy(mappingContext, accessStrategy,
|
||||
rowMapperMap);
|
||||
|
||||
return queryLookupStrategy.resolveQuery(getMethod(name), metadata, projectionFactory, namedQueries);
|
||||
}
|
||||
@@ -95,4 +87,13 @@ public class JdbcQueryLookupStrategyUnitTests {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Method getMethod(String name) {
|
||||
|
||||
try {
|
||||
return JdbcQueryLookupStrategyUnitTests.class.getDeclaredMethod(name);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.jdbc.repository.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -31,6 +32,7 @@ import org.springframework.jdbc.core.RowMapper;
|
||||
* Unit tests for {@link JdbcQueryMethod}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class JdbcQueryMethodUnitTests {
|
||||
|
||||
@@ -40,7 +42,8 @@ public class JdbcQueryMethodUnitTests {
|
||||
public void returnsSqlStatement() throws NoSuchMethodException {
|
||||
|
||||
RepositoryMetadata metadata = mock(RepositoryMetadata.class);
|
||||
when(metadata.getReturnedDomainClass(any(Method.class))).thenReturn((Class) String.class);
|
||||
|
||||
doReturn(String.class).when(metadata).getReturnedDomainClass(any(Method.class));
|
||||
|
||||
JdbcQueryMethod queryMethod = new JdbcQueryMethod(JdbcQueryMethodUnitTests.class.getDeclaredMethod("queryMethod"),
|
||||
metadata, mock(ProjectionFactory.class));
|
||||
@@ -52,7 +55,8 @@ public class JdbcQueryMethodUnitTests {
|
||||
public void returnsSpecifiedRowMapperClass() throws NoSuchMethodException {
|
||||
|
||||
RepositoryMetadata metadata = mock(RepositoryMetadata.class);
|
||||
when(metadata.getReturnedDomainClass(any(Method.class))).thenReturn((Class) String.class);
|
||||
|
||||
doReturn(String.class).when(metadata).getReturnedDomainClass(any(Method.class));
|
||||
|
||||
JdbcQueryMethod queryMethod = new JdbcQueryMethod(JdbcQueryMethodUnitTests.class.getDeclaredMethod("queryMethod"),
|
||||
metadata, mock(ProjectionFactory.class));
|
||||
@@ -63,7 +67,7 @@ public class JdbcQueryMethodUnitTests {
|
||||
@Query(value = DUMMY_SELECT, rowMapperClass = CustomRowMapper.class)
|
||||
private void queryMethod() {}
|
||||
|
||||
private class CustomRowMapper implements RowMapper {
|
||||
private class CustomRowMapper implements RowMapper<Object> {
|
||||
|
||||
@Override
|
||||
public Object mapRow(ResultSet rs, int rowNum) {
|
||||
|
||||
@@ -24,12 +24,14 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.DataAccessStrategy;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -38,6 +40,7 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
* @author Jens Schauder
|
||||
* @author Greg Turnquist
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class JdbcRepositoryFactoryBeanUnitTests {
|
||||
@@ -45,11 +48,15 @@ public class JdbcRepositoryFactoryBeanUnitTests {
|
||||
JdbcRepositoryFactoryBean<DummyEntityRepository, DummyEntity, Long> factoryBean;
|
||||
|
||||
@Mock DataAccessStrategy dataAccessStrategy;
|
||||
@Mock JdbcMappingContext mappingContext;
|
||||
@Mock ApplicationEventPublisher publisher;
|
||||
|
||||
JdbcMappingContext mappingContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.mappingContext = new JdbcMappingContext(mock(NamedParameterJdbcOperations.class));
|
||||
|
||||
// Setup standard configuration
|
||||
factoryBean = new JdbcRepositoryFactoryBean<>(DummyEntityRepository.class);
|
||||
}
|
||||
@@ -59,6 +66,7 @@ public class JdbcRepositoryFactoryBeanUnitTests {
|
||||
|
||||
factoryBean.setDataAccessStrategy(dataAccessStrategy);
|
||||
factoryBean.setMappingContext(mappingContext);
|
||||
factoryBean.setApplicationEventPublisher(publisher);
|
||||
factoryBean.afterPropertiesSet();
|
||||
|
||||
assertThat(factoryBean.getObject()).isNotNull();
|
||||
@@ -74,6 +82,7 @@ public class JdbcRepositoryFactoryBeanUnitTests {
|
||||
public void afterPropertiesThowsExceptionWhenNoMappingContextSet() {
|
||||
|
||||
factoryBean.setMappingContext(null);
|
||||
factoryBean.setApplicationEventPublisher(publisher);
|
||||
factoryBean.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@@ -81,6 +90,7 @@ public class JdbcRepositoryFactoryBeanUnitTests {
|
||||
public void afterPropertiesSetDefaultsNullablePropertiesCorrectly() {
|
||||
|
||||
factoryBean.setMappingContext(mappingContext);
|
||||
factoryBean.setApplicationEventPublisher(publisher);
|
||||
factoryBean.afterPropertiesSet();
|
||||
|
||||
assertThat(factoryBean.getObject()).isNotNull();
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository.support;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -24,51 +29,50 @@ import org.springframework.data.repository.query.Parameters;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link JdbcRepositoryQuery}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class JdbcRepositoryQueryUnitTests {
|
||||
|
||||
JdbcQueryMethod queryMethod;
|
||||
JdbcMappingContext context;
|
||||
RowMapper defaultRowMapper;
|
||||
RowMapper<?> defaultRowMapper;
|
||||
JdbcRepositoryQuery query;
|
||||
|
||||
@Before
|
||||
public void setup() throws NoSuchMethodException {
|
||||
|
||||
Parameters parameters = new DefaultParameters(JdbcRepositoryQueryUnitTests.class.getDeclaredMethod("dummyMethod"));
|
||||
queryMethod = mock(JdbcQueryMethod.class);
|
||||
when(queryMethod.getParameters()).thenReturn(parameters);
|
||||
this.queryMethod = mock(JdbcQueryMethod.class);
|
||||
|
||||
context = mock(JdbcMappingContext.class, RETURNS_DEEP_STUBS);
|
||||
defaultRowMapper = mock(RowMapper.class);
|
||||
Parameters<?, ?> parameters = new DefaultParameters(
|
||||
JdbcRepositoryQueryUnitTests.class.getDeclaredMethod("dummyMethod"));
|
||||
doReturn(parameters).when(queryMethod).getParameters();
|
||||
|
||||
this.context = mock(JdbcMappingContext.class, RETURNS_DEEP_STUBS);
|
||||
this.defaultRowMapper = mock(RowMapper.class);
|
||||
|
||||
this.query = new JdbcRepositoryQuery(queryMethod, context, defaultRowMapper);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-165
|
||||
public void emptyQueryThrowsException() {
|
||||
|
||||
when(queryMethod.getAnnotatedQuery()).thenReturn(null);
|
||||
query = new JdbcRepositoryQuery(queryMethod, context, defaultRowMapper);
|
||||
doReturn(null).when(queryMethod).getAnnotatedQuery();
|
||||
|
||||
Assertions.assertThatExceptionOfType(IllegalStateException.class) //
|
||||
.isThrownBy(() -> query.execute(new Object[]{}));
|
||||
.isThrownBy(() -> query.execute(new Object[] {}));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-165
|
||||
public void defaultRowMapperIsUsedByDefault() {
|
||||
|
||||
when(queryMethod.getAnnotatedQuery()).thenReturn("some sql statement");
|
||||
when(queryMethod.getRowMapperClass()).thenReturn((Class) RowMapper.class);
|
||||
query = new JdbcRepositoryQuery(queryMethod, context, defaultRowMapper);
|
||||
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
|
||||
doReturn(RowMapper.class).when(queryMethod).getRowMapperClass();
|
||||
|
||||
query.execute(new Object[]{});
|
||||
query.execute(new Object[] {});
|
||||
|
||||
verify(context.getTemplate()).queryForObject(anyString(), any(SqlParameterSource.class), eq(defaultRowMapper));
|
||||
}
|
||||
@@ -76,10 +80,9 @@ public class JdbcRepositoryQueryUnitTests {
|
||||
@Test // DATAJDBC-165
|
||||
public void defaultRowMapperIsUsedForNull() {
|
||||
|
||||
when(queryMethod.getAnnotatedQuery()).thenReturn("some sql statement");
|
||||
query = new JdbcRepositoryQuery(queryMethod, context, defaultRowMapper);
|
||||
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
|
||||
|
||||
query.execute(new Object[]{});
|
||||
query.execute(new Object[] {});
|
||||
|
||||
verify(context.getTemplate()).queryForObject(anyString(), any(SqlParameterSource.class), eq(defaultRowMapper));
|
||||
}
|
||||
@@ -87,22 +90,23 @@ public class JdbcRepositoryQueryUnitTests {
|
||||
@Test // DATAJDBC-165
|
||||
public void customRowMapperIsUsedWhenSpecified() {
|
||||
|
||||
when(queryMethod.getAnnotatedQuery()).thenReturn("some sql statement");
|
||||
when(queryMethod.getRowMapperClass()).thenReturn((Class) CustomRowMapper.class);
|
||||
query = new JdbcRepositoryQuery(queryMethod, context, defaultRowMapper);
|
||||
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
|
||||
doReturn(CustomRowMapper.class).when(queryMethod).getRowMapperClass();
|
||||
|
||||
query.execute(new Object[]{});
|
||||
new JdbcRepositoryQuery(queryMethod, context, defaultRowMapper).execute(new Object[] {});
|
||||
|
||||
verify(context.getTemplate()).queryForObject(anyString(), any(SqlParameterSource.class), isA(CustomRowMapper.class));
|
||||
verify(context.getTemplate()) //
|
||||
.queryForObject(anyString(), any(SqlParameterSource.class), isA(CustomRowMapper.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* The whole purpose of this method is to easily generate a {@link DefaultParameters} instance during test setup.
|
||||
*/
|
||||
private void dummyMethod() {
|
||||
}
|
||||
@SuppressWarnings("unused")
|
||||
private void dummyMethod() {}
|
||||
|
||||
private static class CustomRowMapper implements RowMapper<Object> {
|
||||
|
||||
private static class CustomRowMapper implements RowMapper {
|
||||
@Override
|
||||
public Object mapRow(ResultSet rs, int rowNum) {
|
||||
return null;
|
||||
|
||||
@@ -59,10 +59,9 @@ public class TestConfiguration {
|
||||
final JdbcMappingContext context = new JdbcMappingContext(NamingStrategy.INSTANCE, jdbcTemplate, __ -> {});
|
||||
|
||||
return new JdbcRepositoryFactory( //
|
||||
publisher, //
|
||||
dataAccessStrategy, //
|
||||
context, //
|
||||
dataAccessStrategy //
|
||||
);
|
||||
publisher);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
Reference in New Issue
Block a user