Browse Source

DATAJDBC-400 - Remove Identifier from callbacks.

Retrieval of the Identifier has been shown to cost significant performance.

Original pull request: #164.
pull/165/head
Jens Schauder 6 years ago committed by Mark Paluch
parent
commit
2289195e8a
  1. 12
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java
  2. 4
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java
  3. 2
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
  4. 14
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQuery.java
  5. 22
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateUnitTests.java
  6. 2
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java
  7. 11
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java
  8. 4
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java
  9. 54
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQueryUnitTests.java
  10. 3
      spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/AfterDeleteCallback.java
  11. 3
      spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/AfterLoadCallback.java
  12. 3
      spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/AfterSaveCallback.java
  13. 3
      spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/BeforeConvertCallback.java
  14. 3
      spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/BeforeDeleteCallback.java
  15. 3
      spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/BeforeSaveCallback.java
  16. 4
      spring-data-relational/src/main/java/org/springframework/data/relational/domain/support/RelationalAuditingCallback.java

12
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java

@ -380,14 +380,14 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
publisher.publishEvent(new AfterLoadEvent(identifier, entity)); publisher.publishEvent(new AfterLoadEvent(identifier, entity));
return entityCallbacks.callback(AfterLoadCallback.class, entity, identifier); return entityCallbacks.callback(AfterLoadCallback.class, entity);
} }
private <T> T triggerBeforeConvert(T aggregateRoot, @Nullable Object id) { private <T> T triggerBeforeConvert(T aggregateRoot, @Nullable Object id) {
Identifier identifier = Identifier.ofNullable(id); Identifier identifier = Identifier.ofNullable(id);
return entityCallbacks.callback(BeforeConvertCallback.class, aggregateRoot, identifier); return entityCallbacks.callback(BeforeConvertCallback.class, aggregateRoot);
} }
private <T> T triggerBeforeSave(T aggregateRoot, @Nullable Object id, AggregateChange<T> change) { private <T> T triggerBeforeSave(T aggregateRoot, @Nullable Object id, AggregateChange<T> change) {
@ -400,7 +400,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
change // change //
)); ));
return entityCallbacks.callback(BeforeSaveCallback.class, aggregateRoot, identifier, change); return entityCallbacks.callback(BeforeSaveCallback.class, aggregateRoot, change);
} }
private <T> T triggerAfterSave(T aggregateRoot, Object id, AggregateChange<T> change) { private <T> T triggerAfterSave(T aggregateRoot, Object id, AggregateChange<T> change) {
@ -413,7 +413,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
change // change //
)); ));
return entityCallbacks.callback(AfterSaveCallback.class, aggregateRoot, identifier); return entityCallbacks.callback(AfterSaveCallback.class, aggregateRoot);
} }
private <T> void triggerAfterDelete(@Nullable T aggregateRoot, Object id, AggregateChange<?> change) { private <T> void triggerAfterDelete(@Nullable T aggregateRoot, Object id, AggregateChange<?> change) {
@ -423,7 +423,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
publisher.publishEvent(new AfterDeleteEvent(identifier, Optional.ofNullable(aggregateRoot), change)); publisher.publishEvent(new AfterDeleteEvent(identifier, Optional.ofNullable(aggregateRoot), change));
if (aggregateRoot != null) { if (aggregateRoot != null) {
entityCallbacks.callback(AfterDeleteCallback.class, aggregateRoot, identifier); entityCallbacks.callback(AfterDeleteCallback.class, aggregateRoot);
} }
} }
@ -435,7 +435,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
publisher.publishEvent(new BeforeDeleteEvent(identifier, Optional.ofNullable(aggregateRoot), change)); publisher.publishEvent(new BeforeDeleteEvent(identifier, Optional.ofNullable(aggregateRoot), change));
if (aggregateRoot != null) { if (aggregateRoot != null) {
return entityCallbacks.callback(BeforeDeleteCallback.class, aggregateRoot, identifier, change); return entityCallbacks.callback(BeforeDeleteCallback.class, aggregateRoot, change);
} }
return null; return null;

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

@ -23,6 +23,7 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.jdbc.core.convert.EntityRowMapper; import org.springframework.data.jdbc.core.convert.EntityRowMapper;
import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.repository.QueryMappingConfiguration; import org.springframework.data.jdbc.repository.QueryMappingConfiguration;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
@ -47,6 +48,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
class JdbcQueryLookupStrategy implements QueryLookupStrategy { class JdbcQueryLookupStrategy implements QueryLookupStrategy {
private final ApplicationEventPublisher publisher; private final ApplicationEventPublisher publisher;
private final EntityCallbacks callbacks;
private final RelationalMappingContext context; private final RelationalMappingContext context;
private final JdbcConverter converter; private final JdbcConverter converter;
private final QueryMappingConfiguration queryMappingConfiguration; private final QueryMappingConfiguration queryMappingConfiguration;
@ -64,7 +66,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
RowMapper<?> mapper = queryMethod.isModifyingQuery() ? null : createMapper(queryMethod); RowMapper<?> mapper = queryMethod.isModifyingQuery() ? null : createMapper(queryMethod);
return new JdbcRepositoryQuery(publisher, context, queryMethod, operations, mapper); return new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations, mapper);
} }
private RowMapper<?> createMapper(JdbcQueryMethod queryMethod) { private RowMapper<?> createMapper(JdbcQueryMethod queryMethod) {

2
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java

@ -149,7 +149,7 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
if (key == null || key == QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND if (key == null || key == QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND
|| key == QueryLookupStrategy.Key.USE_DECLARED_QUERY) { || key == QueryLookupStrategy.Key.USE_DECLARED_QUERY) {
JdbcQueryLookupStrategy strategy = new JdbcQueryLookupStrategy(publisher, context, converter, JdbcQueryLookupStrategy strategy = new JdbcQueryLookupStrategy(publisher, entityCallbacks, context, converter,
queryMappingConfiguration, operations); queryMappingConfiguration, operations);
return Optional.of(strategy); return Optional.of(strategy);
} }

14
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQuery.java

@ -21,8 +21,10 @@ import java.util.List;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.event.AfterLoadCallback;
import org.springframework.data.relational.core.mapping.event.AfterLoadEvent; import org.springframework.data.relational.core.mapping.event.AfterLoadEvent;
import org.springframework.data.relational.core.mapping.event.Identifier; import org.springframework.data.relational.core.mapping.event.Identifier;
import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.query.RepositoryQuery;
@ -49,6 +51,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 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 ApplicationEventPublisher publisher; private final ApplicationEventPublisher publisher;
private final EntityCallbacks callbacks;
private final RelationalMappingContext context; private final RelationalMappingContext context;
private final JdbcQueryMethod queryMethod; private final JdbcQueryMethod queryMethod;
private final NamedParameterJdbcOperations operations; private final NamedParameterJdbcOperations operations;
@ -64,8 +67,9 @@ class JdbcRepositoryQuery implements RepositoryQuery {
* @param operations must not be {@literal null}. * @param operations must not be {@literal null}.
* @param defaultRowMapper can be {@literal null} (only in case of a modifying query). * @param defaultRowMapper can be {@literal null} (only in case of a modifying query).
*/ */
JdbcRepositoryQuery(ApplicationEventPublisher publisher, RelationalMappingContext context, JdbcRepositoryQuery(ApplicationEventPublisher publisher, @Nullable EntityCallbacks callbacks,
JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations, RowMapper<?> defaultRowMapper) { RelationalMappingContext context, JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
RowMapper<?> defaultRowMapper) {
Assert.notNull(publisher, "Publisher must not be null!"); Assert.notNull(publisher, "Publisher must not be null!");
Assert.notNull(context, "Context must not be null!"); Assert.notNull(context, "Context must not be null!");
@ -77,6 +81,7 @@ class JdbcRepositoryQuery implements RepositoryQuery {
} }
this.publisher = publisher; this.publisher = publisher;
this.callbacks = callbacks == null ? EntityCallbacks.create() : callbacks;
this.context = context; this.context = context;
this.queryMethod = queryMethod; this.queryMethod = queryMethod;
this.operations = operations; this.operations = operations;
@ -214,7 +219,8 @@ class JdbcRepositoryQuery implements RepositoryQuery {
@Nullable @Nullable
private ResultSetExtractor determineResultSetExtractor(@Nullable RowMapper<?> rowMapper) { private ResultSetExtractor determineResultSetExtractor(@Nullable RowMapper<?> rowMapper) {
Class<? extends ResultSetExtractor> resultSetExtractorClass = (Class<? extends ResultSetExtractor>) queryMethod.getResultSetExtractorClass(); Class<? extends ResultSetExtractor> resultSetExtractorClass = (Class<? extends ResultSetExtractor>) queryMethod
.getResultSetExtractorClass();
if (isUnconfigured(resultSetExtractorClass, ResultSetExtractor.class)) { if (isUnconfigured(resultSetExtractorClass, ResultSetExtractor.class)) {
return null; return null;
@ -262,6 +268,8 @@ class JdbcRepositoryQuery implements RepositoryQuery {
if (identifier != null) { if (identifier != null) {
publisher.publishEvent(new AfterLoadEvent(Identifier.of(identifier), entity)); publisher.publishEvent(new AfterLoadEvent(Identifier.of(identifier), entity));
} }
callbacks.callback(AfterLoadCallback.class, entity);
} }
} }

22
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateUnitTests.java

@ -27,7 +27,9 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter; import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
@ -45,7 +47,6 @@ import org.springframework.data.relational.core.mapping.event.AfterSaveCallback;
import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback; import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback;
import org.springframework.data.relational.core.mapping.event.BeforeDeleteCallback; import org.springframework.data.relational.core.mapping.event.BeforeDeleteCallback;
import org.springframework.data.relational.core.mapping.event.BeforeSaveCallback; import org.springframework.data.relational.core.mapping.event.BeforeSaveCallback;
import org.springframework.data.relational.core.mapping.event.Identifier;
/** /**
* Unit tests for {@link JdbcAggregateTemplate}. * Unit tests for {@link JdbcAggregateTemplate}.
@ -71,6 +72,7 @@ public class JdbcAggregateTemplateUnitTests {
template = new JdbcAggregateTemplate(eventPublisher, mappingContext, converter, dataAccessStrategy); template = new JdbcAggregateTemplate(eventPublisher, mappingContext, converter, dataAccessStrategy);
((JdbcAggregateTemplate) template).setEntityCallbacks(callbacks); ((JdbcAggregateTemplate) template).setEntityCallbacks(callbacks);
} }
@Test // DATAJDBC-378 @Test // DATAJDBC-378
@ -101,10 +103,9 @@ public class JdbcAggregateTemplateUnitTests {
SampleEntity last = template.save(first); SampleEntity last = template.save(first);
verify(callbacks).callback(BeforeConvertCallback.class, first, Identifier.ofNullable(null)); verify(callbacks).callback(BeforeConvertCallback.class, first);
verify(callbacks).callback(eq(BeforeSaveCallback.class), eq(second), eq(Identifier.ofNullable(23L)), verify(callbacks).callback(eq(BeforeSaveCallback.class), eq(second), any(AggregateChange.class));
any(AggregateChange.class)); verify(callbacks).callback(AfterSaveCallback.class, third);
verify(callbacks).callback(AfterSaveCallback.class, third, Identifier.of(23L));
assertThat(last).isEqualTo(third); assertThat(last).isEqualTo(third);
} }
@ -114,13 +115,12 @@ public class JdbcAggregateTemplateUnitTests {
SampleEntity first = new SampleEntity(23L, "Alfred"); SampleEntity first = new SampleEntity(23L, "Alfred");
SampleEntity second = new SampleEntity(23L, "Alfred E."); SampleEntity second = new SampleEntity(23L, "Alfred E.");
when(callbacks.callback(any(Class.class), any(), any(), any())).thenReturn(second); when(callbacks.callback(any(Class.class), any(), any())).thenReturn(second);
template.delete(first, SampleEntity.class); template.delete(first, SampleEntity.class);
verify(callbacks).callback(eq(BeforeDeleteCallback.class), eq(first), eq(Identifier.of(23L)), verify(callbacks).callback(eq(BeforeDeleteCallback.class), eq(first), any(AggregateChange.class));
any(AggregateChange.class)); verify(callbacks).callback(AfterDeleteCallback.class, second);
verify(callbacks).callback(AfterDeleteCallback.class, second, Identifier.of(23L));
} }
@Test // DATAJDBC-393 @Test // DATAJDBC-393
@ -139,8 +139,8 @@ public class JdbcAggregateTemplateUnitTests {
Iterable<SampleEntity> all = template.findAll(SampleEntity.class); Iterable<SampleEntity> all = template.findAll(SampleEntity.class);
verify(callbacks).callback(AfterLoadCallback.class, alfred1, Identifier.of(23L)); verify(callbacks).callback(AfterLoadCallback.class, alfred1);
verify(callbacks).callback(AfterLoadCallback.class, neumann1, Identifier.of(42L)); verify(callbacks).callback(AfterLoadCallback.class, neumann1);
assertThat(all).containsExactly(alfred2, neumann2); assertThat(all).containsExactly(alfred2, neumann2);
} }

2
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java

@ -173,7 +173,7 @@ public class JdbcRepositoryIdGenerationIntegrationTests {
@Bean @Bean
BeforeConvertCallback<ImmutableWithManualIdEntity> idGenerator() { BeforeConvertCallback<ImmutableWithManualIdEntity> idGenerator() {
return (e, __) -> e.withId(lastId.incrementAndGet()); return e -> e.withId(lastId.incrementAndGet());
} }
} }
} }

11
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java

@ -44,7 +44,6 @@ import org.springframework.data.domain.AuditorAware;
import org.springframework.data.relational.core.mapping.NamingStrategy; import org.springframework.data.relational.core.mapping.NamingStrategy;
import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback; import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback;
import org.springframework.data.relational.core.mapping.event.BeforeSaveEvent; import org.springframework.data.relational.core.mapping.event.BeforeSaveEvent;
import org.springframework.data.relational.core.mapping.event.Identifier;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
@ -191,12 +190,12 @@ public class EnableJdbcAuditingHsqlIntegrationTests {
OrderAssertingEventListener.class, // OrderAssertingEventListener.class, //
OrderAssertingCallback.class // OrderAssertingCallback.class //
) // ) //
.accept(repository -> { .accept(repository -> {
AuditingAnnotatedDummyEntity entity = repository.save(new AuditingAnnotatedDummyEntity()); AuditingAnnotatedDummyEntity entity = repository.save(new AuditingAnnotatedDummyEntity());
assertThat(entity.id).isNotNull(); assertThat(entity.id).isNotNull();
}); });
} }
/** /**
@ -344,7 +343,7 @@ public class EnableJdbcAuditingHsqlIntegrationTests {
static class OrderAssertingCallback implements BeforeConvertCallback { static class OrderAssertingCallback implements BeforeConvertCallback {
@Override @Override
public Object onBeforeConvert(Object entity, Identifier id) { public Object onBeforeConvert(Object entity) {
assertThat(entity).isInstanceOf(AuditingAnnotatedDummyEntity.class); assertThat(entity).isInstanceOf(AuditingAnnotatedDummyEntity.class);
assertThat(((AuditingAnnotatedDummyEntity) entity).createdDate).isNotNull(); assertThat(((AuditingAnnotatedDummyEntity) entity).createdDate).isNotNull();

4
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategyUnitTests.java

@ -30,6 +30,7 @@ import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.repository.QueryMappingConfiguration; import org.springframework.data.jdbc.repository.QueryMappingConfiguration;
import org.springframework.data.jdbc.repository.config.DefaultQueryMappingConfiguration; import org.springframework.data.jdbc.repository.config.DefaultQueryMappingConfiguration;
import org.springframework.data.jdbc.repository.query.Query; import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.repository.core.NamedQueries; import org.springframework.data.repository.core.NamedQueries;
@ -52,6 +53,7 @@ import org.springframework.util.ReflectionUtils;
public class JdbcQueryLookupStrategyUnitTests { public class JdbcQueryLookupStrategyUnitTests {
ApplicationEventPublisher publisher = mock(ApplicationEventPublisher.class); ApplicationEventPublisher publisher = mock(ApplicationEventPublisher.class);
EntityCallbacks callbacks = mock(EntityCallbacks.class);
RelationalMappingContext mappingContext = mock(RelationalMappingContext.class, RETURNS_DEEP_STUBS); RelationalMappingContext mappingContext = mock(RelationalMappingContext.class, RETURNS_DEEP_STUBS);
JdbcConverter converter = mock(JdbcConverter.class); JdbcConverter converter = mock(JdbcConverter.class);
DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class); DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class);
@ -85,7 +87,7 @@ public class JdbcQueryLookupStrategyUnitTests {
private RepositoryQuery getRepositoryQuery(String name, QueryMappingConfiguration mappingConfiguration) { private RepositoryQuery getRepositoryQuery(String name, QueryMappingConfiguration mappingConfiguration) {
JdbcQueryLookupStrategy queryLookupStrategy = new JdbcQueryLookupStrategy(publisher, mappingContext, converter, JdbcQueryLookupStrategy queryLookupStrategy = new JdbcQueryLookupStrategy(publisher, callbacks, mappingContext, converter,
mappingConfiguration, operations); mappingConfiguration, operations);
Method method = ReflectionUtils.findMethod(MyRepository.class, name); Method method = ReflectionUtils.findMethod(MyRepository.class, name);

54
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQueryUnitTests.java

@ -16,10 +16,7 @@
package org.springframework.data.jdbc.repository.support; package org.springframework.data.jdbc.repository.support;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -31,7 +28,9 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.mapping.event.AfterLoadCallback;
import org.springframework.data.relational.core.mapping.event.AfterLoadEvent; import org.springframework.data.relational.core.mapping.event.AfterLoadEvent;
import org.springframework.data.repository.query.DefaultParameters; import org.springframework.data.repository.query.DefaultParameters;
import org.springframework.data.repository.query.Parameters; import org.springframework.data.repository.query.Parameters;
@ -57,6 +56,7 @@ public class JdbcRepositoryQueryUnitTests {
ResultSetExtractor<?> defaultResultSetExtractor; ResultSetExtractor<?> defaultResultSetExtractor;
NamedParameterJdbcOperations operations; NamedParameterJdbcOperations operations;
ApplicationEventPublisher publisher; ApplicationEventPublisher publisher;
EntityCallbacks callbacks;
RelationalMappingContext context; RelationalMappingContext context;
@Before @Before
@ -71,6 +71,7 @@ public class JdbcRepositoryQueryUnitTests {
this.defaultRowMapper = mock(RowMapper.class); this.defaultRowMapper = mock(RowMapper.class);
this.operations = mock(NamedParameterJdbcOperations.class); this.operations = mock(NamedParameterJdbcOperations.class);
this.publisher = mock(ApplicationEventPublisher.class); this.publisher = mock(ApplicationEventPublisher.class);
this.callbacks = mock(EntityCallbacks.class);
this.context = mock(RelationalMappingContext.class, RETURNS_DEEP_STUBS); this.context = mock(RelationalMappingContext.class, RETURNS_DEEP_STUBS);
} }
@ -80,8 +81,9 @@ public class JdbcRepositoryQueryUnitTests {
doReturn(null).when(queryMethod).getAnnotatedQuery(); doReturn(null).when(queryMethod).getAnnotatedQuery();
Assertions.assertThatExceptionOfType(IllegalStateException.class) // Assertions.assertThatExceptionOfType(IllegalStateException.class) //
.isThrownBy(() -> new JdbcRepositoryQuery(publisher, context, queryMethod, operations, defaultRowMapper) .isThrownBy(
.execute(new Object[] {})); () -> new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations, defaultRowMapper)
.execute(new Object[] {}));
} }
@Test // DATAJDBC-165 @Test // DATAJDBC-165
@ -89,7 +91,8 @@ public class JdbcRepositoryQueryUnitTests {
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery(); doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
doReturn(RowMapper.class).when(queryMethod).getRowMapperClass(); doReturn(RowMapper.class).when(queryMethod).getRowMapperClass();
JdbcRepositoryQuery query = new JdbcRepositoryQuery(publisher, context, queryMethod, operations, defaultRowMapper); JdbcRepositoryQuery query = new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations,
defaultRowMapper);
query.execute(new Object[] {}); query.execute(new Object[] {});
@ -100,7 +103,8 @@ public class JdbcRepositoryQueryUnitTests {
public void defaultRowMapperIsUsedForNull() { public void defaultRowMapperIsUsedForNull() {
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery(); doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
JdbcRepositoryQuery query = new JdbcRepositoryQuery(publisher, context, queryMethod, operations, defaultRowMapper); JdbcRepositoryQuery query = new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations,
defaultRowMapper);
query.execute(new Object[] {}); query.execute(new Object[] {});
@ -113,7 +117,8 @@ public class JdbcRepositoryQueryUnitTests {
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery(); doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
doReturn(CustomRowMapper.class).when(queryMethod).getRowMapperClass(); doReturn(CustomRowMapper.class).when(queryMethod).getRowMapperClass();
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, defaultRowMapper).execute(new Object[] {}); new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations, defaultRowMapper)
.execute(new Object[] {});
verify(operations) // verify(operations) //
.queryForObject(anyString(), any(SqlParameterSource.class), isA(CustomRowMapper.class)); .queryForObject(anyString(), any(SqlParameterSource.class), isA(CustomRowMapper.class));
@ -125,7 +130,8 @@ public class JdbcRepositoryQueryUnitTests {
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery(); doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
doReturn(CustomResultSetExtractor.class).when(queryMethod).getResultSetExtractorClass(); doReturn(CustomResultSetExtractor.class).when(queryMethod).getResultSetExtractorClass();
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, defaultRowMapper).execute(new Object[] {}); new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations, defaultRowMapper)
.execute(new Object[] {});
ArgumentCaptor<CustomResultSetExtractor> captor = ArgumentCaptor.forClass(CustomResultSetExtractor.class); ArgumentCaptor<CustomResultSetExtractor> captor = ArgumentCaptor.forClass(CustomResultSetExtractor.class);
@ -143,7 +149,8 @@ public class JdbcRepositoryQueryUnitTests {
doReturn(CustomResultSetExtractor.class).when(queryMethod).getResultSetExtractorClass(); doReturn(CustomResultSetExtractor.class).when(queryMethod).getResultSetExtractorClass();
doReturn(CustomRowMapper.class).when(queryMethod).getRowMapperClass(); doReturn(CustomRowMapper.class).when(queryMethod).getRowMapperClass();
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, defaultRowMapper).execute(new Object[] {}); new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations, defaultRowMapper)
.execute(new Object[] {});
ArgumentCaptor<CustomResultSetExtractor> captor = ArgumentCaptor.forClass(CustomResultSetExtractor.class); ArgumentCaptor<CustomResultSetExtractor> captor = ArgumentCaptor.forClass(CustomResultSetExtractor.class);
@ -165,7 +172,8 @@ public class JdbcRepositoryQueryUnitTests {
when(context.getRequiredPersistentEntity(DummyEntity.class).getIdentifierAccessor(any()).getIdentifier()) when(context.getRequiredPersistentEntity(DummyEntity.class).getIdentifierAccessor(any()).getIdentifier())
.thenReturn("some identifier"); .thenReturn("some identifier");
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, defaultRowMapper).execute(new Object[] {}); new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations, defaultRowMapper)
.execute(new Object[] {});
verify(publisher).publishEvent(any(AfterLoadEvent.class)); verify(publisher).publishEvent(any(AfterLoadEvent.class));
} }
@ -181,11 +189,31 @@ public class JdbcRepositoryQueryUnitTests {
when(context.getRequiredPersistentEntity(DummyEntity.class).getIdentifierAccessor(any()).getIdentifier()) when(context.getRequiredPersistentEntity(DummyEntity.class).getIdentifierAccessor(any()).getIdentifier())
.thenReturn("some identifier"); .thenReturn("some identifier");
new JdbcRepositoryQuery(publisher, context, queryMethod, operations, defaultRowMapper).execute(new Object[] {}); new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations, defaultRowMapper)
.execute(new Object[] {});
verify(publisher, times(2)).publishEvent(any(AfterLoadEvent.class)); verify(publisher, times(2)).publishEvent(any(AfterLoadEvent.class));
} }
@Test // DATAJDBC-400
public void publishesCallbacks() {
doReturn("some sql statement").when(queryMethod).getAnnotatedQuery();
doReturn(false).when(queryMethod).isCollectionQuery();
DummyEntity dummyEntity = new DummyEntity(1L);
doReturn(dummyEntity).when(operations).queryForObject(anyString(), any(SqlParameterSource.class),
any(RowMapper.class));
doReturn(true).when(context).hasPersistentEntityFor(DummyEntity.class);
when(context.getRequiredPersistentEntity(DummyEntity.class).getIdentifierAccessor(any()).getIdentifier())
.thenReturn("some identifier");
new JdbcRepositoryQuery(publisher, callbacks, context, queryMethod, operations, defaultRowMapper).execute(new Object[] {});
verify(publisher).publishEvent(any(AfterLoadEvent.class));
verify(callbacks).callback(AfterLoadCallback.class, dummyEntity);
}
/** /**
* The whole purpose of this method is to easily generate a {@link DefaultParameters} instance during test setup. * The whole purpose of this method is to easily generate a {@link DefaultParameters} instance during test setup.
*/ */

3
spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/AfterDeleteCallback.java

@ -34,8 +34,7 @@ public interface AfterDeleteCallback<T> extends EntityCallback<T> {
* instance of the aggregate object. * instance of the aggregate object.
* *
* @param aggregate the aggregate that was deleted. * @param aggregate the aggregate that was deleted.
* @param id identifier.
* @return the aggregate that was deleted. * @return the aggregate that was deleted.
*/ */
T onAfterDelete(T aggregate, Identifier id); T onAfterDelete(T aggregate);
} }

3
spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/AfterLoadCallback.java

@ -32,8 +32,7 @@ public interface AfterLoadCallback<T> extends EntityCallback<T> {
* instance of the domain object. * instance of the domain object.
* *
* @param aggregate the loaded aggregate. * @param aggregate the loaded aggregate.
* @param id identifier.
* @return the loaded aggregate. * @return the loaded aggregate.
*/ */
T onAfterLoad(T aggregate, Identifier.Specified id); T onAfterLoad(T aggregate);
} }

3
spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/AfterSaveCallback.java

@ -32,8 +32,7 @@ public interface AfterSaveCallback<T> extends EntityCallback<T> {
* instance of the aggregate. * instance of the aggregate.
* *
* @param aggregate the saved aggregate. * @param aggregate the saved aggregate.
* @param id identifier.
* @return the saved aggregate. * @return the saved aggregate.
*/ */
T onAfterSave(T aggregate, Identifier.Specified id); T onAfterSave(T aggregate);
} }

3
spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/BeforeConvertCallback.java

@ -33,8 +33,7 @@ public interface BeforeConvertCallback<T> extends EntityCallback<T> {
* a modified instance of the aggregate. * a modified instance of the aggregate.
* *
* @param aggregate the saved aggregate. * @param aggregate the saved aggregate.
* @param id identifier.
* @return the aggregate to be persisted. * @return the aggregate to be persisted.
*/ */
T onBeforeConvert(T aggregate, Identifier id); T onBeforeConvert(T aggregate);
} }

3
spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/BeforeDeleteCallback.java

@ -36,9 +36,8 @@ public interface BeforeDeleteCallback<T> extends EntityCallback<T> {
* Only transient fields of the entity should be changed in this callback. * Only transient fields of the entity should be changed in this callback.
* *
* @param aggregate the aggregate. * @param aggregate the aggregate.
* @param id identifier.
* @param aggregateChange the associated {@link AggregateChange}. * @param aggregateChange the associated {@link AggregateChange}.
* @return the aggregate to be deleted. * @return the aggregate to be deleted.
*/ */
T onBeforeDelete(T aggregate, Identifier id, AggregateChange<T> aggregateChange); T onBeforeDelete(T aggregate, AggregateChange<T> aggregateChange);
} }

3
spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/event/BeforeSaveCallback.java

@ -37,9 +37,8 @@ public interface BeforeSaveCallback<T> extends EntityCallback<T> {
* converted, use the {@link BeforeConvertCallback}. * converted, use the {@link BeforeConvertCallback}.
* *
* @param aggregate the aggregate. * @param aggregate the aggregate.
* @param id identifier.
* @param aggregateChange the associated {@link AggregateChange}. * @param aggregateChange the associated {@link AggregateChange}.
* @return the aggregate object to be persisted. * @return the aggregate object to be persisted.
*/ */
T onBeforeSave(T aggregate, Identifier id, AggregateChange<T> aggregateChange); T onBeforeSave(T aggregate, AggregateChange<T> aggregateChange);
} }

4
spring-data-relational/src/main/java/org/springframework/data/relational/domain/support/RelationalAuditingCallback.java

@ -57,10 +57,10 @@ public class RelationalAuditingCallback implements BeforeConvertCallback<Object>
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.relational.core.mapping.event.BeforeConvertCallback#onBeforeConvert(java.lang.Object, org.springframework.data.relational.core.mapping.event.Identifier) * @see org.springframework.data.relational.core.mapping.event.BeforeConvertCallback#onBeforeConvert(java.lang.Object)
*/ */
@Override @Override
public Object onBeforeConvert(Object entity, Identifier id) { public Object onBeforeConvert(Object entity) {
return handler.markAudited(entity); return handler.markAudited(entity);
} }
} }

Loading…
Cancel
Save