diff --git a/src/main/java/org/springframework/data/jdbc/core/EventPublishingEntityRowMapper.java b/src/main/java/org/springframework/data/jdbc/core/EventPublishingEntityRowMapper.java deleted file mode 100644 index 6d128bd5..00000000 --- a/src/main/java/org/springframework/data/jdbc/core/EventPublishingEntityRowMapper.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.core; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; - -import java.sql.ResultSet; -import java.sql.SQLException; - -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.data.jdbc.mapping.event.AfterCreation; -import org.springframework.data.jdbc.mapping.event.Identifier; -import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntityInformation; -import org.springframework.jdbc.core.RowMapper; - -/** - * A {@link RowMapper} that publishes events after a delegate, did the actual work of mapping a {@link ResultSet} to an - * entityInformation. - * - * @author Jens Schauder - * @since 2.0 - */ -@RequiredArgsConstructor -public class EventPublishingEntityRowMapper implements RowMapper { - - private final @NonNull RowMapper delegate; - private final @NonNull JdbcPersistentEntityInformation entityInformation; - private final @NonNull ApplicationEventPublisher publisher; - - /* - * (non-Javadoc) - * @see org.springframework.jdbc.core.RowMapper#mapRow(java.sql.ResultSet, int) - */ - @Override - public T mapRow(ResultSet resultSet, int i) throws SQLException { - - T instance = delegate.mapRow(resultSet, i); - - publisher.publishEvent(new AfterCreation(Identifier.of(entityInformation.getRequiredId(instance)), instance, null)); - - return instance; - } -} diff --git a/src/main/java/org/springframework/data/jdbc/core/JdbcEntityTemplate.java b/src/main/java/org/springframework/data/jdbc/core/JdbcEntityTemplate.java index b00d022b..7a3c1d8a 100644 --- a/src/main/java/org/springframework/data/jdbc/core/JdbcEntityTemplate.java +++ b/src/main/java/org/springframework/data/jdbc/core/JdbcEntityTemplate.java @@ -23,6 +23,7 @@ import org.springframework.data.jdbc.core.conversion.AggregateChange.Kind; import org.springframework.data.jdbc.core.conversion.Interpreter; import org.springframework.data.jdbc.core.conversion.JdbcEntityDeleteWriter; import org.springframework.data.jdbc.core.conversion.JdbcEntityWriter; +import org.springframework.data.jdbc.mapping.event.AfterCreation; import org.springframework.data.jdbc.mapping.event.AfterDelete; import org.springframework.data.jdbc.mapping.event.AfterSave; import org.springframework.data.jdbc.mapping.event.BeforeDelete; @@ -90,7 +91,12 @@ public class JdbcEntityTemplate implements JdbcEntityOperations { @Override public T findById(Object id, Class domainType) { - return accessStrategy.findById(id, domainType); + + T entity = accessStrategy.findById(id, domainType); + if (entity != null) { + publishAfterCreation(id, entity); + } + return entity; } @Override @@ -100,12 +106,18 @@ public class JdbcEntityTemplate implements JdbcEntityOperations { @Override public Iterable findAll(Class domainType) { - return accessStrategy.findAll(domainType); + + Iterable all = accessStrategy.findAll(domainType); + publishAfterCreation(all); + return all; } @Override public Iterable findAllById(Iterable ids, Class domainType) { - return accessStrategy.findAllById(ids, domainType); + + Iterable allById = accessStrategy.findAllById(ids, domainType); + publishAfterCreation(allById); + return allById; } @Override @@ -161,4 +173,15 @@ public class JdbcEntityTemplate implements JdbcEntityOperations { jdbcEntityDeleteWriter.write(null, aggregateChange); return aggregateChange; } + + private void publishAfterCreation(Iterable all) { + + all.forEach(e -> { + publishAfterCreation(context.getRequiredPersistentEntityInformation((Class) e.getClass()).getRequiredId(e), e); + }); + } + + private void publishAfterCreation(Object id, T entity) { + publisher.publishEvent(new AfterCreation(Identifier.of(id), entity)); + } } diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterCreation.java b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterCreation.java index 6b2cd29a..a8e6a6f1 100644 --- a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterCreation.java +++ b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterCreation.java @@ -15,7 +15,6 @@ */ package org.springframework.data.jdbc.mapping.event; -import org.springframework.data.jdbc.core.conversion.AggregateChange; import org.springframework.data.jdbc.mapping.event.Identifier.Specified; /** @@ -32,9 +31,8 @@ public class AfterCreation extends JdbcEventWithIdAndEntity { /** * @param id of the entity * @param entity the newly instantiated entity. - * @param change */ - public AfterCreation(Specified id, Object entity, AggregateChange change) { - super(id, entity, change); + public AfterCreation(Specified id, Object entity) { + super(id, entity, null); } } diff --git a/src/test/java/org/springframework/data/jdbc/core/EventPublishingEntityRowMapperUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/EventPublishingEntityRowMapperUnitTests.java deleted file mode 100644 index 2abe30e2..00000000 --- a/src/test/java/org/springframework/data/jdbc/core/EventPublishingEntityRowMapperUnitTests.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.core; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.*; - -import lombok.Value; - -import java.sql.ResultSet; -import java.sql.SQLException; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.data.annotation.Id; -import org.springframework.data.jdbc.mapping.event.AfterCreation; -import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntityInformation; -import org.springframework.jdbc.core.RowMapper; - -/** - * Unit tests for {@link EventPublishingEntityRowMapper}. - * - * @author Jens Schauder - * @author Oliver Gierke - */ -@RunWith(MockitoJUnitRunner.class) -public class EventPublishingEntityRowMapperUnitTests { - - @Mock RowMapper rowMapperDelegate; - @Mock JdbcPersistentEntityInformation entityInformation; - @Mock ApplicationEventPublisher publisher; - - @Test // DATAJDBC-99 - public void eventGetsPublishedAfterInstantiation() throws SQLException { - - when(rowMapperDelegate.mapRow(any(ResultSet.class), anyInt())).thenReturn(new DummyEntity(1L)); - when(entityInformation.getRequiredId(any())).thenReturn(1L); - - EventPublishingEntityRowMapper rowMapper = new EventPublishingEntityRowMapper<>(rowMapperDelegate, - entityInformation, publisher); - - ResultSet resultSet = mock(ResultSet.class); - rowMapper.mapRow(resultSet, 1); - - verify(publisher).publishEvent(isA(AfterCreation.class)); - } - - @Value - static class DummyEntity { - @Id Long Id; - } -} diff --git a/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java b/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java index a8dec253..306722fe 100644 --- a/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java +++ b/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java @@ -21,6 +21,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.core.DefaultDataAccessStrategy; import org.springframework.data.jdbc.core.SqlGeneratorSource; +import org.springframework.data.jdbc.mapping.event.AfterCreation; import org.springframework.data.jdbc.mapping.event.AfterDelete; import org.springframework.data.jdbc.mapping.event.AfterSave; import org.springframework.data.jdbc.mapping.event.BeforeDelete; @@ -42,18 +43,22 @@ public class SimpleJdbcRepositoryEventsUnitTests { FakePublisher publisher = new FakePublisher(); DummyEntityRepository repository; + DefaultDataAccessStrategy dataAccessStrategy; @Before public void before() { final JdbcMappingContext context = new JdbcMappingContext(createIdGeneratingOperations()); + + dataAccessStrategy = spy(new DefaultDataAccessStrategy( // + new SqlGeneratorSource(context), // + context // + )); + JdbcRepositoryFactory factory = new JdbcRepositoryFactory( // publisher, // context, // - new DefaultDataAccessStrategy( // - new SqlGeneratorSource(context), // - context // - ) // + dataAccessStrategy // ); repository = factory.getRepository(DummyEntityRepository.class); @@ -122,6 +127,57 @@ public class SimpleJdbcRepositoryEventsUnitTests { ); } + @Test // DATAJDBC-197 + public void publishesEventsOnFindAll() { + + DummyEntity entity1 = new DummyEntity(42L); + DummyEntity entity2 = new DummyEntity(23L); + + doReturn(asList(entity1, entity2)).when(dataAccessStrategy).findAll(any(Class.class)); + + repository.findAll(); + + assertThat(publisher.events) // + .extracting(e -> (Class) e.getClass()) // + .containsExactly( // + AfterCreation.class, // + AfterCreation.class // + ); + } + + @Test // DATAJDBC-197 + 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)); + + repository.findAllById(asList(42L, 23L)); + + assertThat(publisher.events) // + .extracting(e -> (Class) e.getClass()) // + .containsExactly( // + AfterCreation.class, // + AfterCreation.class // + ); + } + + @Test // DATAJDBC-197 + public void publishesEventsOnFindById() { + + DummyEntity entity1 = new DummyEntity(23L); + doReturn(entity1).when(dataAccessStrategy).findById(eq(23L), any(Class.class)); + + repository.findById(23L); + + assertThat(publisher.events) // + .extracting(e -> (Class) e.getClass()) // + .containsExactly( // + AfterCreation.class // + ); + } + private static NamedParameterJdbcOperations createIdGeneratingOperations() { Answer setIdInKeyHolder = invocation -> {