diff --git a/lombok.config b/lombok.config
new file mode 100644
index 000000000..e50c7ea43
--- /dev/null
+++ b/lombok.config
@@ -0,0 +1,2 @@
+lombok.nonNull.exceptionType = IllegalArgumentException
+lombok.log.fieldName = LOG
diff --git a/pom.xml b/pom.xml
index 4ada10172..cef9f3149 100644
--- a/pom.xml
+++ b/pom.xml
@@ -128,61 +128,6 @@
org.apache.maven.plugins
maven-surefire-plugin
2.12
-
-
- org.springframework
- spring-instrument
- ${spring}
- runtime
-
-
- org.hsqldb
- hsqldb
- ${hsqldb1}
- runtime
-
-
-
-
- default-test
-
-
- **/*
-
-
-
-
- unit-tests
-
- test
-
- test
-
-
- **/*UnitTests.java
-
-
-
-
- integration-tests
-
- test
-
- test
-
-
- **/*IntegrationTests.java
- **/*Tests.java
-
-
- **/*UnitTests.java
-\
-
- -javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco}/org.jacoco.agent-${jacoco}-runtime.jar=destfile=${jacoco.destfile}
-
-
-
-
org.apache.maven.plugins
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/context/JdbcMappingContext.java b/src/main/java/org/springframework/data/jdbc/mapping/context/JdbcMappingContext.java
index e9fd47d31..a2cb02078 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/context/JdbcMappingContext.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/context/JdbcMappingContext.java
@@ -17,6 +17,8 @@ package org.springframework.data.jdbc.mapping.context;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
+
+import org.springframework.data.jdbc.mapping.model.BasicJdbcPersistentProperty;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
import org.springframework.data.mapping.context.AbstractMappingContext;
@@ -25,17 +27,22 @@ import org.springframework.data.util.TypeInformation;
/**
* @author Jens Schauder
+ * @since 2.0
*/
public class JdbcMappingContext extends AbstractMappingContext, JdbcPersistentProperty> {
-
@Override
protected JdbcPersistentEntity createPersistentEntity(TypeInformation typeInformation) {
return new JdbcPersistentEntity(typeInformation);
}
@Override
- protected JdbcPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor, JdbcPersistentEntity owner, SimpleTypeHolder simpleTypeHolder) {
- return new JdbcPersistentProperty(field, descriptor, owner, simpleTypeHolder);
+ protected JdbcPersistentProperty createPersistentProperty( //
+ Field field, //
+ PropertyDescriptor descriptor, //
+ JdbcPersistentEntity owner, //
+ SimpleTypeHolder simpleTypeHolder //
+ ) {
+ return new BasicJdbcPersistentProperty(field, descriptor, owner, simpleTypeHolder);
}
}
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
new file mode 100644
index 000000000..9515ff80b
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterCreation.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
+
+/**
+ * Gets published after instantiation and setting of all the properties of an entity. This allows to do some postprocessing of entities.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public class AfterCreation extends JdbcEventWithIdAndEntity {
+
+ /**
+ * @param id of the entity
+ * @param entity the newly instantiated entity.
+ */
+ public AfterCreation(Specified id, Object entity) {
+ super(id, entity);
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterCreationEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterCreationEvent.java
deleted file mode 100644
index 1e96c4406..000000000
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterCreationEvent.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2017 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.mapping.event;
-
-import java.util.function.Function;
-
-/**
- * gets published after instantiation and setting of all the properties of an entity. This allows to do some
- * postprocessing of entities.
- *
- * @author Jens Schauder
- */
-public class AfterCreationEvent extends JdbcEvent{
-
- /**
- * @param instance the newly instantiated entity.
- * @param idProvider a function providing the id, for the instance.
- * @param type of the entity and the argument of the {@code idProvider}
- */
- public AfterCreationEvent(T instance, Function idProvider) {
- super(instance, idProvider);
- }
-}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterDelete.java b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterDelete.java
new file mode 100644
index 000000000..73c889b07
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterDelete.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+import java.util.Optional;
+
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
+
+/**
+ * Gets published after deletion of an entity. It will have a {@link Specified} identifier.
+ *
+ * If the entity is empty or not depends on the delete method used.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public class AfterDelete extends JdbcEventWithId{
+
+ /**
+ * @param id of the entity.
+ * @param instance the deleted entity if it is available.
+ */
+ public AfterDelete(Specified id, Optional instance) {
+ super(id, instance);
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterDeleteEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterDeleteEvent.java
deleted file mode 100644
index 982ebbc2a..000000000
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterDeleteEvent.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2017 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.mapping.event;
-
-import java.util.function.Function;
-
-/**
- * get published after deletion of an entity. The source might contain the Id or the actual entity, depending on the
- * {@code delete(...)} method used.
- *
- * @author Jens Schauder
- */
-public class AfterDeleteEvent extends JdbcEvent{
-
- /**
- * @param instance the deleted entity.
- * @param idProvider a function providing the id, for the instance.
- * @param type of the entity and the argument of the {@code idProvider}
- */
- public AfterDeleteEvent(T instance, Function idProvider) {
- super(instance, idProvider);
- }
-}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterInsertEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterInsert.java
similarity index 65%
rename from src/main/java/org/springframework/data/jdbc/mapping/event/AfterInsertEvent.java
rename to src/main/java/org/springframework/data/jdbc/mapping/event/AfterInsert.java
index aa733f910..9a6f4145d 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterInsertEvent.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterInsert.java
@@ -15,21 +15,21 @@
*/
package org.springframework.data.jdbc.mapping.event;
-import java.util.function.Function;
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
/**
- * gets published after an entity got inserted into the database.
+ * Gets published after an entity got inserted into the database.
*
* @author Jens Schauder
+ * @since 2.0
*/
-public class AfterInsertEvent extends AfterSaveEvent {
+public class AfterInsert extends AfterSave {
/**
+ * @param id identifier of the entity triggering the event.
* @param instance the newly inserted entity.
- * @param idProvider a function providing the id, for the instance.
- * @param type of the entity and the argument of the {@code idProvider}
*/
- public AfterInsertEvent(T instance, Function idProvider) {
- super(instance, idProvider);
+ public AfterInsert(Specified id, Object instance) {
+ super(id, instance);
}
}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterSaveEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterSave.java
similarity index 63%
rename from src/main/java/org/springframework/data/jdbc/mapping/event/AfterSaveEvent.java
rename to src/main/java/org/springframework/data/jdbc/mapping/event/AfterSave.java
index bf25700f6..e029e1aa5 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterSaveEvent.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterSave.java
@@ -15,20 +15,23 @@
*/
package org.springframework.data.jdbc.mapping.event;
-import java.util.function.Function;
+import java.util.Optional;
+
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
/**
- * subclasses of this get published after a new instance or a changed instance was saved in the database
+ * Subclasses of this get published after a new instance or a changed instance was saved in the database.
+ *
* @author Jens Schauder
+ * @since 2.0
*/
-public class AfterSaveEvent extends JdbcEvent{
+public class AfterSave extends JdbcEventWithIdAndEntity {
/**
+ * @param id identifier of
* @param instance the newly saved entity.
- * @param idProvider a function providing the id, for the instance.
- * @param type of the entity and the argument of the {@code idProvider}
*/
- AfterSaveEvent(T instance, Function idProvider) {
- super(instance, idProvider);
+ AfterSave(Specified id, Object instance) {
+ super(id, instance);
}
}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterUpdateEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterUpdate.java
similarity index 65%
rename from src/main/java/org/springframework/data/jdbc/mapping/event/AfterUpdateEvent.java
rename to src/main/java/org/springframework/data/jdbc/mapping/event/AfterUpdate.java
index 075fde2be..b95cd0930 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/AfterUpdateEvent.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/AfterUpdate.java
@@ -15,21 +15,21 @@
*/
package org.springframework.data.jdbc.mapping.event;
-import java.util.function.Function;
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
/**
- * gets published after an entity was updated in the database.
+ * Gets published after an entity was updated in the database.
*
* @author Jens Schauder
+ * @since 2.0
*/
-public class AfterUpdateEvent extends AfterSaveEvent {
+public class AfterUpdate extends AfterSave {
/**
+ * @param id of the entity
* @param instance the updated entity.
- * @param idProvider a function providing the id, for the instance.
- * @param type of the entity and the argument of the {@code idProvider}
*/
- public AfterUpdateEvent(T instance, Function idProvider) {
- super(instance, idProvider);
+ public AfterUpdate(Specified id, Object instance) {
+ super(id, instance);
}
}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeDelete.java b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeDelete.java
new file mode 100644
index 000000000..4d221b2ec
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeDelete.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+import java.util.Optional;
+
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
+
+/**
+ * Gets published when an entity is about to get deleted.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public class BeforeDelete extends JdbcEventWithId {
+
+ /**
+ * @param id the id of the entity
+ * @param entity the entity about to get deleted. Might be empty.
+ */
+ public BeforeDelete(Specified id, Optional entity) {
+ super(id, entity);
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeDeleteEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeDeleteEvent.java
deleted file mode 100644
index 1e9a78997..000000000
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeDeleteEvent.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2017 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.mapping.event;
-
-import java.util.function.Function;
-
-import org.springframework.context.ApplicationEvent;
-
-/**
- * gets published when an entity is about to get deleted. {@link ApplicationEvent#getSource()} might contain either the
- * entity or the id of the entity, depending on which delete method was used.
- *
- * @author Jens Schauder
- */
-public class BeforeDeleteEvent extends JdbcEvent {
-
- /**
- * @param instance the entity about to get deleted. Might be {@literal NULL}
- * @param idProvider a function providing the id, for the instance. Must provide a not {@literal NULL} id, when called with {@link #instance}
- * @param type of the entity and the argument of the {@code idProvider}
- */
- public BeforeDeleteEvent(T instance, Function idProvider) {
- super(instance, idProvider);
- }
-}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeInsertEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeInsert.java
similarity index 60%
rename from src/main/java/org/springframework/data/jdbc/mapping/event/BeforeInsertEvent.java
rename to src/main/java/org/springframework/data/jdbc/mapping/event/BeforeInsert.java
index 45ecba984..c290cd442 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeInsertEvent.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeInsert.java
@@ -15,23 +15,23 @@
*/
package org.springframework.data.jdbc.mapping.event;
-import java.util.function.Function;
+import org.springframework.data.jdbc.mapping.event.Identifier.Unset;
/**
- * gets published before an entity gets inserted into the database.
+ * Gets published before an entity gets inserted into the database. When the id-property of the entity must get set
+ * manually, an event listener for this event may do so.
*
- * When the id-property of the entity must get set manually, an event listener for this event may do so.
+ * The {@link Identifier} is {@link org.springframework.data.jdbc.mapping.event.Identifier.Unset#UNSET}
*
* @author Jens Schauder
+ * @since 2.0
*/
-public class BeforeInsertEvent extends BeforeSaveEvent {
+public class BeforeInsert extends BeforeSave {
/**
* @param instance the entity about to get inserted.
- * @param idProvider a function providing the id, for the instance.
- * @param type of the entity and the argument of the {@code idProvider}
*/
- public BeforeInsertEvent(T instance, Function idProvider) {
- super(instance, idProvider);
+ public BeforeInsert(Object instance) {
+ super(Unset.UNSET, instance);
}
}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeUpdateEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeSave.java
similarity index 65%
rename from src/main/java/org/springframework/data/jdbc/mapping/event/BeforeUpdateEvent.java
rename to src/main/java/org/springframework/data/jdbc/mapping/event/BeforeSave.java
index 543cbcd78..bf20430db 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeUpdateEvent.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeSave.java
@@ -15,21 +15,21 @@
*/
package org.springframework.data.jdbc.mapping.event;
-import java.util.function.Function;
+import java.util.Optional;
/**
- * gets published before an entity gets updated in the database.
+ * Subclasses of this get published before an entity gets saved to the database.
*
* @author Jens Schauder
+ * @since 2.0
*/
-public class BeforeUpdateEvent extends BeforeSaveEvent {
+public class BeforeSave extends JdbcEventWithEntity {
/**
+ * @param id of the entity to be saved.
* @param instance the entity about to get saved.
- * @param idProvider a function providing the id, for the instance.
- * @param type of the entity and the argument of the {@code idProvider}
*/
- public BeforeUpdateEvent(T instance, Function idProvider) {
- super(instance, idProvider);
+ BeforeSave(Identifier id, Object instance) {
+ super(id, instance);
}
}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeSaveEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeSaveEvent.java
deleted file mode 100644
index 626c6f038..000000000
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeSaveEvent.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2017 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.mapping.event;
-
-import java.util.function.Function;
-
-import org.springframework.context.ApplicationEvent;
-
-/**
- * subclasses of this get published before an entity gets saved to the database.
- *
- * @author Jens Schauder
- */
-public class BeforeSaveEvent extends JdbcEvent {
-
- /**
- * @param instance the entity about to get saved.
- * @param idProvider a function providing the id, for the instance.
- * @param type of the entity and the argument of the {@code idProvider}
- */
- BeforeSaveEvent(T instance, Function idProvider) {
- super(instance, idProvider);
- }
-}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeUpdate.java b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeUpdate.java
new file mode 100644
index 000000000..72ad695d5
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/BeforeUpdate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
+
+/**
+ * Gets published before an entity gets updated in the database.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public class BeforeUpdate extends BeforeSave implements WithId {
+
+ /**
+ * @param id of the entity about to get updated
+ * @param instance the entity about to get updated.
+ */
+ public BeforeUpdate(Specified id, Object instance) {
+ super(id, instance);
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/Identifier.java b/src/main/java/org/springframework/data/jdbc/mapping/event/Identifier.java
new file mode 100644
index 000000000..492cc1edc
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/Identifier.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+import lombok.Data;
+import lombok.NonNull;
+
+import java.util.Optional;
+
+/**
+ * Wrapper for an identifier of an entity. Might either be a {@link Specified} or {@link Unset#UNSET}
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public interface Identifier {
+
+ Optional getOptionalValue();
+
+ static Identifier fromNullable(Object value) {
+ return (value != null) ? new Specified(value) : Unset.UNSET;
+ }
+
+ /**
+ * An unset identifier. Always returns {@link Optional#empty()} as value.
+ */
+ enum Unset implements Identifier {
+ UNSET {
+ @Override
+ public Optional getOptionalValue() {
+ return Optional.empty();
+ }
+ }
+ }
+
+ /**
+ * An {@link Identifier} guaranteed to have a non empty value.
+ *
+ * Since it is guaranteed to exist the value can get access directly.
+ */
+ @Data
+ class Specified implements Identifier {
+
+ @NonNull
+ private final Object value;
+
+ @Override
+ public Optional getOptionalValue() {
+ return Optional.of(value);
+ }
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEvent.java b/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEvent.java
index ad0df42f2..59a1911d3 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEvent.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEvent.java
@@ -15,48 +15,43 @@
*/
package org.springframework.data.jdbc.mapping.event;
-import java.util.function.Function;
+import java.util.Optional;
import org.springframework.context.ApplicationEvent;
+import lombok.Getter;
+
/**
- * is the common superclass for all events published by JDBC repositories.
- *
- * It is recommendet not to use the {@link #getSource()} since it may contain the entity if it was available, when the
- * event was published, or in case of delete events only the Id.
- *
- * Use the dedicated methods {@link #getId()} or {@link #getInstance()} instead. Note that the later might be
- * {@literal NULL} in the cases mentioned above.
+ * The common superclass for all events published by JDBC repositories.
+ * {@link #getSource} contains the {@link Identifier} of the entity triggering the event.
*
* @author Jens Schauder
+ * @since 2.0
*/
+@Getter
public class JdbcEvent extends ApplicationEvent {
- private final Object id;
- private final Object instance;
-
- JdbcEvent(T instance, Function idProvider) {
-
- super(instance == null ? idProvider.apply(instance) : instance);
- this.instance = instance;
- this.id = idProvider.apply(instance);
- }
-
/**
- * the entity for which this event was publish. Might be {@literal NULL} in cases of delete events where only the id
+ * The optional entity for which this event was published. Might be empty in cases of delete events where only the identifier
* was provided to the delete method.
*
- * @return instance of the entity triggering this event.
+ * @return The entity triggering this event or empty.
*/
- public Object getInstance() {
- return instance;
+ private final Optional optionalEntity;
+
+ public JdbcEvent(Identifier id, Optional optionalEntity) {
+ super(id);
+ this.optionalEntity = optionalEntity;
}
/**
- * the id of the entity, triggering this event. Guaranteed not to be {@literal NULL}.
+ * The identifier of the entity, triggering this event. Also available via
+ * {@link #getSource()}.
+ *
* @return
*/
- public Object getId() {
- return id;
+ public Identifier getId() {
+ return (Identifier) getSource();
}
+
}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEventWithEntity.java b/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEventWithEntity.java
new file mode 100644
index 000000000..c103dd6e0
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEventWithEntity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+import java.util.Optional;
+
+/**
+ * A {@link JdbcEvent} which is guaranteed to have an entity.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public class JdbcEventWithEntity extends JdbcEvent implements WithEntity {
+
+ public JdbcEventWithEntity(Identifier id, Object entity) {
+ super(id, Optional.of(entity));
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEventWithId.java b/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEventWithId.java
new file mode 100644
index 000000000..fa0c61d65
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEventWithId.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+import java.util.Optional;
+
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
+
+/**
+ * A {@link JdbcEvent} guaranteed to have an identifier.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public class JdbcEventWithId extends JdbcEvent implements WithId{
+
+ public JdbcEventWithId(Specified id, Optional entity) {
+ super(id, entity);
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEventWithIdAndEntity.java b/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEventWithIdAndEntity.java
new file mode 100644
index 000000000..819ef8962
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/JdbcEventWithIdAndEntity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+import lombok.Getter;
+
+import java.util.Optional;
+
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
+
+/**
+ * A {@link JdbcEvent} which is guaranteed to have an identifier and an entity.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+@Getter
+public class JdbcEventWithIdAndEntity extends JdbcEvent implements WithId, WithEntity {
+
+ public JdbcEventWithIdAndEntity(Specified id, Object entity) {
+ super(id, Optional.of(entity));
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/WithEntity.java b/src/main/java/org/springframework/data/jdbc/mapping/event/WithEntity.java
new file mode 100644
index 000000000..a465fd54b
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/WithEntity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+/**
+ * Interface for {@link JdbcEvent}s which are guaranteed to have an entity. Allows direct access to that entity, without going through an {@link java.util.Optional}
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public interface WithEntity {
+
+ default Object getEntity() {
+ return ((JdbcEvent) this).getOptionalEntity()
+ .orElseThrow(() -> new IllegalStateException("Entity must not be NULL"));
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/event/WithId.java b/src/main/java/org/springframework/data/jdbc/mapping/event/WithId.java
new file mode 100644
index 000000000..108a419ac
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/event/WithId.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 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.mapping.event;
+
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
+
+/**
+ * Interface for {@link JdbcEvent}s which are guaranteed to have a {@link Specified} identifier.
+ *
+ * Offers direct access to the {@link Specified} identifier.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public interface WithId {
+
+ default Specified getSpecifiedId(){
+ return (Specified) ((JdbcEvent)this).getId();
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentProperty.java b/src/main/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentProperty.java
new file mode 100644
index 000000000..a5edb0d00
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentProperty.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 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.mapping.model;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+
+import org.springframework.data.mapping.Association;
+import org.springframework.data.mapping.PersistentEntity;
+import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
+import org.springframework.data.mapping.model.SimpleTypeHolder;
+
+/**
+ * Meta data about a property to be used by repository implementations.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public class BasicJdbcPersistentProperty extends AnnotationBasedPersistentProperty
+ implements JdbcPersistentProperty {
+
+ /**
+ * Creates a new {@link AnnotationBasedPersistentProperty}.
+ *
+ * @param field must not be {@literal null}.
+ * @param propertyDescriptor can be {@literal null}.
+ * @param owner must not be {@literal null}.
+ * @param simpleTypeHolder
+ */
+ public BasicJdbcPersistentProperty( //
+ Field field, //
+ PropertyDescriptor propertyDescriptor, //
+ PersistentEntity, JdbcPersistentProperty> owner, //
+ SimpleTypeHolder simpleTypeHolder //
+ ) {
+ super(field, propertyDescriptor, owner, simpleTypeHolder);
+ }
+
+ @Override
+ protected Association createAssociation() {
+ return null;
+ }
+
+ public String getColumnName() {
+ return getName();
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntity.java b/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntity.java
index bbe2d69cf..1c3a342f3 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntity.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntity.java
@@ -20,38 +20,26 @@ import org.springframework.data.util.TypeInformation;
/**
* meta data a repository might need for implementing persistence operations for instances of type {@code T}
+ *
* @author Jens Schauder
+ * @since 2.0
*/
public class JdbcPersistentEntity extends BasicPersistentEntity {
- private String tableName;
- private String idColumn;
+ private final String tableName;
public JdbcPersistentEntity(TypeInformation information) {
+
super(information);
+
+ tableName = getType().getSimpleName();
}
public String getTableName() {
-
- if (tableName == null)
- tableName = getType().getSimpleName();
-
return tableName;
}
public String getIdColumn() {
-
- if (idColumn == null)
- idColumn = getIdProperty().getName();
-
- return idColumn;
- }
-
- public Object getIdValue(T instance) {
- return getPropertyAccessor(instance).getProperty(getIdProperty());
- }
-
- public void setId(T instance, Object value) {
- getPropertyAccessor(instance).setProperty(getIdProperty(),value);
+ return getIdProperty().getName();
}
}
diff --git a/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentProperty.java b/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentProperty.java
index 841d64c65..e63cd4faf 100644
--- a/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentProperty.java
+++ b/src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentProperty.java
@@ -15,38 +15,13 @@
*/
package org.springframework.data.jdbc.mapping.model;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.Field;
-import org.springframework.data.mapping.Association;
-import org.springframework.data.mapping.PersistentEntity;
-import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
-import org.springframework.data.mapping.model.SimpleTypeHolder;
+import org.springframework.data.mapping.PersistentProperty;
/**
- * meta data about a property to be used by repository implementations.
- *
* @author Jens Schauder
+ * @since 2.0
*/
-public class JdbcPersistentProperty extends AnnotationBasedPersistentProperty {
-
- /**
- * Creates a new {@link AnnotationBasedPersistentProperty}.
- *
- * @param field must not be {@literal null}.
- * @param propertyDescriptor can be {@literal null}.
- * @param owner must not be {@literal null}.
- * @param simpleTypeHolder
- */
- public JdbcPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity, JdbcPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
- super(field, propertyDescriptor, owner, simpleTypeHolder);
- }
-
- @Override
- protected Association createAssociation() {
- return null;
- }
+public interface JdbcPersistentProperty extends PersistentProperty {
- public String getColumnName() {
- return getName();
- }
+ String getColumnName();
}
diff --git a/src/main/java/org/springframework/data/jdbc/repository/EntityRowMapper.java b/src/main/java/org/springframework/data/jdbc/repository/EntityRowMapper.java
index b60435215..7d6e19044 100644
--- a/src/main/java/org/springframework/data/jdbc/repository/EntityRowMapper.java
+++ b/src/main/java/org/springframework/data/jdbc/repository/EntityRowMapper.java
@@ -17,6 +17,7 @@ package org.springframework.data.jdbc.repository;
import java.sql.ResultSet;
import java.sql.SQLException;
+
import org.springframework.data.convert.ClassGeneratingEntityInstantiator;
import org.springframework.data.convert.EntityInstantiator;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
@@ -32,6 +33,7 @@ import org.springframework.jdbc.core.RowMapper;
* maps a ResultSet to an entity of type {@code T}
*
* @author Jens Schauder
+ * @since 2.0
*/
class EntityRowMapper implements RowMapper {
@@ -48,7 +50,7 @@ class EntityRowMapper implements RowMapper {
T t = createInstance(rs);
- entity.doWithProperties((PropertyHandler) property -> {
+ entity.doWithProperties((PropertyHandler) property -> {
setProperty(rs, t, property);
});
@@ -57,12 +59,15 @@ class EntityRowMapper implements RowMapper {
private T createInstance(ResultSet rs) {
return instantiator.createInstance(entity, new ParameterValueProvider() {
+ @SuppressWarnings("unchecked")
@Override
public T getParameterValue(PreferredConstructor.Parameter parameter) {
try {
return (T) rs.getObject(parameter.getName());
} catch (SQLException e) {
- throw new MappingException(String.format("Couldn't read column %s from ResultSet.", parameter.getName()));
+ throw new MappingException( //
+ String.format("Couldn't read column %s from ResultSet.", parameter.getName()) //
+ );
}
}
});
@@ -76,4 +81,4 @@ class EntityRowMapper implements RowMapper {
throw new RuntimeException(String.format("Couldn't set property %s.", property.getName()), e);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/springframework/data/jdbc/repository/EventPublishingEntityRowMapper.java b/src/main/java/org/springframework/data/jdbc/repository/EventPublishingEntityRowMapper.java
index b499296c8..1721c7873 100644
--- a/src/main/java/org/springframework/data/jdbc/repository/EventPublishingEntityRowMapper.java
+++ b/src/main/java/org/springframework/data/jdbc/repository/EventPublishingEntityRowMapper.java
@@ -15,44 +15,37 @@
*/
package org.springframework.data.jdbc.repository;
+import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.data.jdbc.mapping.event.AfterCreationEvent;
-import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
+import org.springframework.data.jdbc.mapping.event.AfterCreation;
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
+import org.springframework.data.jdbc.repository.support.JdbcPersistentEntityInformation;
import org.springframework.jdbc.core.RowMapper;
+import lombok.RequiredArgsConstructor;
+
/**
- * a RowMapper that publishes events after a delegate, did the actual work of mapping a {@link ResultSet} to an entity.
+ * a 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
*/
-public class EventPublishingEntityRowMapper implements RowMapper {
+@RequiredArgsConstructor
+public class EventPublishingEntityRowMapper implements RowMapper {
private final RowMapper delegate;
- private final JdbcPersistentEntity entity;
+ private final JdbcPersistentEntityInformation entityInformation;
private final ApplicationEventPublisher publisher;
- /**
- *
- * @param delegate does the actuall mapping.
- * @param entity provides functionality to create ids from entities
- * @param publisher used for event publishing after the mapping.
- */
- EventPublishingEntityRowMapper(RowMapper delegate,JdbcPersistentEntity entity, ApplicationEventPublisher publisher) {
-
- this.delegate = delegate;
- this.entity = entity;
- this.publisher = publisher;
- }
-
@Override
public T mapRow(ResultSet resultSet, int i) throws SQLException {
T instance = delegate.mapRow(resultSet, i);
- publisher.publishEvent(new AfterCreationEvent(instance, entity::getIdValue));
+ publisher.publishEvent(new AfterCreation(new Specified(entityInformation.getId(instance)), instance));
return instance;
}
diff --git a/src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java b/src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java
index 04aaf4672..ebff6a34d 100644
--- a/src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java
+++ b/src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java
@@ -16,21 +16,26 @@
package org.springframework.data.jdbc.repository;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.context.ApplicationEventPublisherAware;
-import org.springframework.data.jdbc.mapping.event.AfterDeleteEvent;
-import org.springframework.data.jdbc.mapping.event.AfterInsertEvent;
-import org.springframework.data.jdbc.mapping.event.AfterUpdateEvent;
-import org.springframework.data.jdbc.mapping.event.BeforeDeleteEvent;
-import org.springframework.data.jdbc.mapping.event.BeforeInsertEvent;
-import org.springframework.data.jdbc.mapping.event.BeforeUpdateEvent;
+import org.springframework.dao.NonTransientDataAccessException;
+import org.springframework.data.jdbc.mapping.event.AfterDelete;
+import org.springframework.data.jdbc.mapping.event.AfterInsert;
+import org.springframework.data.jdbc.mapping.event.AfterUpdate;
+import org.springframework.data.jdbc.mapping.event.BeforeDelete;
+import org.springframework.data.jdbc.mapping.event.BeforeInsert;
+import org.springframework.data.jdbc.mapping.event.BeforeUpdate;
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
+import org.springframework.data.jdbc.repository.support.BasicJdbcPersistentEntityInformation;
import org.springframework.data.jdbc.repository.support.JdbcPersistentEntityInformation;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.repository.CrudRepository;
@@ -42,11 +47,15 @@ import org.springframework.util.Assert;
/**
* @author Jens Schauder
+ * @since 2.0
*/
-public class SimpleJdbcRepository
- implements CrudRepository, ApplicationEventPublisherAware {
+public class SimpleJdbcRepository implements CrudRepository {
- private final JdbcPersistentEntity entity;
+ private static final String ENTITY_NEW_AFTER_INSERT = "Entity [%s] still 'new' after insert. Please set either"
+ + " the id property in a before insert event handler, or ensure the database creates a value and your "
+ + "JDBC driver returns it.";
+
+ private final JdbcPersistentEntity persistentEntity;
private final JdbcPersistentEntityInformation entityInformation;
private final NamedParameterJdbcOperations operations;
private final SqlGenerator sql;
@@ -54,18 +63,19 @@ public class SimpleJdbcRepository
private final EntityRowMapper entityRowMapper;
private final ApplicationEventPublisher publisher;
- public SimpleJdbcRepository(JdbcPersistentEntity persistentEntity, NamedParameterJdbcOperations jdbcOperations, ApplicationEventPublisher publisher) {
+ public SimpleJdbcRepository(JdbcPersistentEntity persistentEntity, NamedParameterJdbcOperations jdbcOperations,
+ ApplicationEventPublisher publisher) {
Assert.notNull(persistentEntity, "PersistentEntity must not be null.");
Assert.notNull(jdbcOperations, "JdbcOperations must not be null.");
Assert.notNull(publisher, "Publisher must not be null.");
- this.entity = persistentEntity;
- this.entityInformation = new JdbcPersistentEntityInformation(persistentEntity);
+ this.persistentEntity = persistentEntity;
+ this.entityInformation = new BasicJdbcPersistentEntityInformation<>(persistentEntity);
this.operations = jdbcOperations;
this.publisher = publisher;
- entityRowMapper = new EntityRowMapper(persistentEntity);
+ entityRowMapper = new EntityRowMapper<>(persistentEntity);
sql = new SqlGenerator(persistentEntity);
}
@@ -84,29 +94,23 @@ public class SimpleJdbcRepository
@Override
public Iterable save(Iterable entities) {
- entities.forEach(this::save);
+ List savedEntities = new ArrayList<>();
+
+ entities.forEach(e -> savedEntities.add(save(e)));
- return entities;
+ return savedEntities;
}
@Override
public T findOne(ID id) {
- return operations.queryForObject(
- sql.getFindOne(),
- new MapSqlParameterSource("id", id),
- entityRowMapper
- );
+ return operations.queryForObject(sql.getFindOne(), new MapSqlParameterSource("id", id), entityRowMapper);
}
@Override
public boolean exists(ID id) {
- return operations.queryForObject(
- sql.getExists(),
- new MapSqlParameterSource("id", id),
- Boolean.class
- );
+ return operations.queryForObject(sql.getExists(), new MapSqlParameterSource("id", id), Boolean.class);
}
@Override
@@ -126,27 +130,19 @@ public class SimpleJdbcRepository
@Override
public void delete(ID id) {
- doDelete(id, null);
+ doDelete(new Specified(id), Optional.empty());
}
@Override
public void delete(T instance) {
-
- doDelete((ID) entity.getIdValue(instance), instance);
+ doDelete(new Specified(entityInformation.getId(instance)), Optional.of(instance));
}
@Override
public void delete(Iterable extends T> entities) {
- operations.update(
- sql.getDeleteByList(),
- new MapSqlParameterSource("ids",
- StreamSupport
- .stream(entities.spliterator(), false)
- .map(entity::getIdValue)
- .collect(Collectors.toList())
- )
- );
+ operations.update(sql.getDeleteByList(), new MapSqlParameterSource("ids", StreamSupport
+ .stream(entities.spliterator(), false).map(entityInformation::getId).collect(Collectors.toList())));
}
@Override
@@ -154,52 +150,73 @@ public class SimpleJdbcRepository
operations.getJdbcOperations().update(sql.getDeleteAll());
}
- @Override
- public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
-
- }
-
private Map getPropertyMap(final S instance) {
Map parameters = new HashMap<>();
- this.entity.doWithProperties(new PropertyHandler() {
- @Override
- public void doWithPersistentProperty(JdbcPersistentProperty persistentProperty) {
- parameters.put(persistentProperty.getColumnName(), entity.getPropertyAccessor(instance).getProperty(persistentProperty));
- }
- });
+ this.persistentEntity.doWithProperties((PropertyHandler) //
+ property -> parameters.put( //
+ property.getColumnName(), //
+ persistentEntity.getPropertyAccessor(instance).getProperty(property)) //
+ );
return parameters;
}
private void doInsert(S instance) {
- publisher.publishEvent(new BeforeInsertEvent(instance, entity::getIdValue));
+
+ publisher.publishEvent(new BeforeInsert(instance));
KeyHolder holder = new GeneratedKeyHolder();
- operations.update(
- sql.getInsert(),
- new MapSqlParameterSource(getPropertyMap(instance)),
- holder);
+ Map propertyMap = getPropertyMap(instance);
+ propertyMap.put(persistentEntity.getIdColumn(), getIdValueOrNull(instance));
- entity.setId(instance, holder.getKey());
+ operations.update(sql.getInsert(), new MapSqlParameterSource(propertyMap), holder);
+ setIdFromJdbc(instance, holder);
- publisher.publishEvent(new AfterInsertEvent(instance, entity::getIdValue));
+ if (entityInformation.isNew(instance)) {
+ throw new IllegalStateException(String.format(ENTITY_NEW_AFTER_INSERT, persistentEntity));
+ }
+
+ publisher.publishEvent(new AfterInsert(new Specified(entityInformation.getId(instance)), instance));
}
- private void doDelete(ID id, Object instance) {
+ private ID getIdValueOrNull(S instance) {
- publisher.publishEvent(new BeforeDeleteEvent(instance, o -> id));
- operations.update(sql.getDeleteById(), new MapSqlParameterSource("id", id));
- publisher.publishEvent(new AfterDeleteEvent(instance, o -> id));
+ ID idValue = entityInformation.getId(instance);
+ return isIdPropertySimpleTypeAndValueZero(idValue) ? null : idValue;
+ }
+
+ private boolean isIdPropertySimpleTypeAndValueZero(ID idValue) {
+
+ return (persistentEntity.getIdProperty().getType() == int.class && idValue.equals(0))
+ || (persistentEntity.getIdProperty().getType() == long.class && idValue.equals(0L));
+ }
+
+ private void setIdFromJdbc(S instance, KeyHolder holder) {
+ try {
+ Number idValueFromJdbc = holder.getKey();
+ if (idValueFromJdbc != null) {
+ entityInformation.setId(instance, idValueFromJdbc);
+ }
+ } catch (NonTransientDataAccessException e) {
+ throw new UnableToSetIdException("Unable to set id of " + instance, e);
+ }
+ }
+
+ private void doDelete(Specified specifiedId, Optional optionalEntity) {
+
+ publisher.publishEvent(new BeforeDelete(specifiedId, optionalEntity));
+ operations.update(sql.getDeleteById(), new MapSqlParameterSource("id", specifiedId.getValue()));
+ publisher.publishEvent(new AfterDelete(specifiedId, optionalEntity));
}
private void doUpdate(S instance) {
- publisher.publishEvent(new BeforeUpdateEvent(instance, entity::getIdValue));
+ Specified specifiedId = new Specified(entityInformation.getId(instance));
+ publisher.publishEvent(new BeforeUpdate(specifiedId, instance));
operations.update(sql.getUpdate(), getPropertyMap(instance));
-
- publisher.publishEvent(new AfterUpdateEvent(instance, entity::getIdValue));
+ publisher.publishEvent(new AfterUpdate(specifiedId, instance));
}
}
diff --git a/src/main/java/org/springframework/data/jdbc/repository/SqlGenerator.java b/src/main/java/org/springframework/data/jdbc/repository/SqlGenerator.java
index 2d613d78a..5036b979f 100644
--- a/src/main/java/org/springframework/data/jdbc/repository/SqlGenerator.java
+++ b/src/main/java/org/springframework/data/jdbc/repository/SqlGenerator.java
@@ -24,6 +24,7 @@ import org.springframework.data.mapping.PropertyHandler;
/**
* @author Jens Schauder
+ * @since 2.0
*/
class SqlGenerator {
diff --git a/src/main/java/org/springframework/data/jdbc/repository/UnableToSetIdException.java b/src/main/java/org/springframework/data/jdbc/repository/UnableToSetIdException.java
new file mode 100644
index 000000000..1bbb0126f
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/repository/UnableToSetIdException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 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 org.springframework.dao.NonTransientDataAccessException;
+
+/**
+ * Signals failure to set the id property of an entity.
+ *
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public class UnableToSetIdException extends NonTransientDataAccessException {
+
+ public UnableToSetIdException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/repository/support/BasicJdbcPersistentEntityInformation.java b/src/main/java/org/springframework/data/jdbc/repository/support/BasicJdbcPersistentEntityInformation.java
new file mode 100644
index 000000000..ea22fccae
--- /dev/null
+++ b/src/main/java/org/springframework/data/jdbc/repository/support/BasicJdbcPersistentEntityInformation.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 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.support;
+
+import java.io.Serializable;
+
+import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
+import org.springframework.data.repository.core.support.PersistentEntityInformation;
+
+/**
+ * @author Jens Schauder
+ * @since 2.0
+ */
+public class BasicJdbcPersistentEntityInformation extends PersistentEntityInformation
+ implements JdbcPersistentEntityInformation {
+
+ private final JdbcPersistentEntity persistentEntity;
+
+ public BasicJdbcPersistentEntityInformation(JdbcPersistentEntity persistentEntity) {
+ super(persistentEntity);
+
+ this.persistentEntity = persistentEntity;
+ }
+
+ @Override
+ public void setId(T instance, Object value) {
+ persistentEntity.getPropertyAccessor(instance).setProperty(persistentEntity.getIdProperty(), value);
+ }
+}
diff --git a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcPersistentEntityInformation.java b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcPersistentEntityInformation.java
index 97664acf0..53df278c9 100644
--- a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcPersistentEntityInformation.java
+++ b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcPersistentEntityInformation.java
@@ -16,15 +16,14 @@
package org.springframework.data.jdbc.repository.support;
import java.io.Serializable;
-import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
-import org.springframework.data.repository.core.support.PersistentEntityInformation;
+
+import org.springframework.data.repository.core.EntityInformation;
/**
* @author Jens Schauder
+ * @since 2.0
*/
-public class JdbcPersistentEntityInformation extends PersistentEntityInformation {
+public interface JdbcPersistentEntityInformation extends EntityInformation {
- public JdbcPersistentEntityInformation(JdbcPersistentEntity persistentEntity) {
- super(persistentEntity);
- }
+ void setId(T instance, Object value);
}
diff --git a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
index f2e9b8952..2b92c3317 100644
--- a/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
+++ b/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
@@ -15,6 +15,8 @@
*/
package org.springframework.data.jdbc.repository.support;
+import lombok.RequiredArgsConstructor;
+
import java.io.Serializable;
import org.springframework.context.ApplicationEventPublisher;
@@ -29,34 +31,26 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* @author Jens Schauder
+ * @since 2.0
*/
+@RequiredArgsConstructor
public class JdbcRepositoryFactory extends RepositoryFactorySupport {
private final JdbcMappingContext context = new JdbcMappingContext();
- private final ApplicationEventPublisher publisher;
private final NamedParameterJdbcOperations jdbcOperations;
+ private final ApplicationEventPublisher publisher;
- public JdbcRepositoryFactory(
- ApplicationEventPublisher publisher,
- NamedParameterJdbcOperations jdbcOperations
- ) {
-
- this.publisher = publisher;
- this.jdbcOperations = jdbcOperations;
- }
-
+ @SuppressWarnings("unchecked")
@Override
public EntityInformation getEntityInformation(Class aClass) {
- return new JdbcPersistentEntityInformation<>((JdbcPersistentEntity) context.getPersistentEntity(aClass));
+ return new BasicJdbcPersistentEntityInformation<>((JdbcPersistentEntity) context.getPersistentEntity(aClass));
}
@Override
protected Object getTargetRepository(RepositoryInformation repositoryInformation) {
- return new SimpleJdbcRepository(
- context.getPersistentEntity(repositoryInformation.getDomainType()),
- jdbcOperations,
- publisher);
+ JdbcPersistentEntity> persistentEntity = context.getPersistentEntity(repositoryInformation.getDomainType());
+ return new SimpleJdbcRepository<>(persistentEntity, jdbcOperations, publisher);
}
@Override
diff --git a/src/test/java/org/springframework/data/jdbc/repository/EventPublishingEntityRowMapperTest.java b/src/test/java/org/springframework/data/jdbc/repository/EventPublishingEntityRowMapperTest.java
index 44113c48c..9fefea380 100644
--- a/src/test/java/org/springframework/data/jdbc/repository/EventPublishingEntityRowMapperTest.java
+++ b/src/test/java/org/springframework/data/jdbc/repository/EventPublishingEntityRowMapperTest.java
@@ -2,46 +2,46 @@ package org.springframework.data.jdbc.repository;
import static org.mockito.Mockito.*;
+import lombok.Data;
+
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.Test;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.annotation.Id;
-import org.springframework.data.jdbc.mapping.event.AfterCreationEvent;
-import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
+import org.springframework.data.jdbc.mapping.event.AfterCreation;
+import org.springframework.data.jdbc.repository.support.JdbcPersistentEntityInformation;
import org.springframework.jdbc.core.RowMapper;
-import lombok.Data;
-
/**
* @author Jens Schauder
*/
public class EventPublishingEntityRowMapperTest {
- private RowMapper rowMapperDelegate = mock(RowMapper.class);
- private JdbcPersistentEntity entity = mock(JdbcPersistentEntity.class);
- private ApplicationEventPublisher publisher = mock(ApplicationEventPublisher.class);
+ RowMapper rowMapperDelegate = mock(RowMapper.class);
+ JdbcPersistentEntityInformation entityInformation = mock(JdbcPersistentEntityInformation.class);
+ ApplicationEventPublisher publisher = mock(ApplicationEventPublisher.class);
@Test // DATAJDBC-99
public void eventGetsPublishedAfterInstantiation() throws SQLException {
- when(entity.getIdValue(any())).thenReturn(1L);
+ when(entityInformation.getId(any())).thenReturn(1L);
- EventPublishingEntityRowMapper rowMapper = new EventPublishingEntityRowMapper<>(
- rowMapperDelegate,
- entity,
+ EventPublishingEntityRowMapper rowMapper = new EventPublishingEntityRowMapper<>( //
+ rowMapperDelegate, //
+ entityInformation, //
publisher);
ResultSet resultSet = mock(ResultSet.class);
rowMapper.mapRow(resultSet, 1);
- verify(publisher).publishEvent(isA(AfterCreationEvent.class));
+ verify(publisher).publishEvent(isA(AfterCreation.class));
}
@Data
- private static class DummyEntity {
+ static class DummyEntity {
@Id private final Long Id;
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java
index f537f6d00..9a1cf50d2 100644
--- a/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java
+++ b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java
@@ -17,96 +17,71 @@ package org.springframework.data.jdbc.repository;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
-import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.*;
+
+import lombok.Data;
-import org.junit.After;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Id;
+import org.springframework.data.jdbc.repository.JdbcRepositoryIdGenerationIntegrationTests.TestConfiguration;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
-
-import lombok.Data;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
- * testing special cases for Id generation with JdbcRepositories.
+ * Testing special cases for id generation with {@link SimpleJdbcRepository}.
*
* @author Jens Schauder
*/
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = TestConfiguration.class)
public class JdbcRepositoryIdGenerationIntegrationTests {
- private final EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
- .generateUniqueName(true)
- .setType(EmbeddedDatabaseType.HSQL)
- .setScriptEncoding("UTF-8")
- .ignoreFailedDrops(true)
- .addScript("org.springframework.data.jdbc.repository/jdbc-repository-id-generation-integration-tests.sql")
- .build();
+ @Autowired NamedParameterJdbcTemplate template;
- private final NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(db);
+ @Autowired ReadOnlyIdEntityRepository readOnlyIdrepository;
- private final ReadOnlyIdEntityRepository repository = createRepository(db);
-
- private ReadOnlyIdEntity entity = createDummyEntity();
-
- @After
- public void after() {
- db.shutdown();
- }
+ @Autowired PrimitiveIdEntityRepository primitiveIdRepository;
@Test // DATAJDBC-98
public void idWithoutSetterGetsSet() {
- entity = repository.save(entity);
+ ReadOnlyIdEntity entity1 = new ReadOnlyIdEntity(null);
+ entity1.setName("Entity Name");
+ ReadOnlyIdEntity entity = entity1;
+ entity = readOnlyIdrepository.save(entity);
assertThat(entity.getId()).isNotNull();
- ReadOnlyIdEntity reloadedEntity = repository.findOne(entity.getId());
+ ReadOnlyIdEntity reloadedEntity = readOnlyIdrepository.findOne(entity.getId());
- assertEquals(
- entity.getId(),
- reloadedEntity.getId());
- assertEquals(
- entity.getName(),
- reloadedEntity.getName());
+ assertEquals(entity.getId(), reloadedEntity.getId());
+ assertEquals(entity.getName(), reloadedEntity.getName());
}
@Test // DATAJDBC-98
public void primitiveIdGetsSet() {
- entity = repository.save(entity);
+ PrimitiveIdEntity entity = new PrimitiveIdEntity(0);
+ entity.setName("Entity Name");
+ entity = primitiveIdRepository.save(entity);
assertThat(entity.getId()).isNotNull();
- ReadOnlyIdEntity reloadedEntity = repository.findOne(entity.getId());
-
- assertEquals(
- entity.getId(),
- reloadedEntity.getId());
- assertEquals(
- entity.getName(),
- reloadedEntity.getName());
- }
-
-
- private static ReadOnlyIdEntityRepository createRepository(EmbeddedDatabase db) {
-
- return new JdbcRepositoryFactory(
- mock(ApplicationEventPublisher.class),
- new NamedParameterJdbcTemplate(db)
- ).getRepository(ReadOnlyIdEntityRepository.class);
- }
-
+ PrimitiveIdEntity reloadedEntity = primitiveIdRepository.findOne(entity.getId());
- private static ReadOnlyIdEntity createDummyEntity() {
-
- ReadOnlyIdEntity entity = new ReadOnlyIdEntity(null);
- entity.setName("Entity Name");
- return entity;
+ assertEquals(entity.getId(), reloadedEntity.getId());
+ assertEquals(entity.getName(), reloadedEntity.getName());
}
private interface ReadOnlyIdEntityRepository extends CrudRepository {
@@ -116,8 +91,7 @@ public class JdbcRepositoryIdGenerationIntegrationTests {
@Data
static class ReadOnlyIdEntity {
- @Id
- private final Long id;
+ @Id private final Long id;
String name;
}
@@ -128,8 +102,43 @@ public class JdbcRepositoryIdGenerationIntegrationTests {
@Data
static class PrimitiveIdEntity {
- @Id
- private final Long id;
+ @Id private final long id;
String name;
}
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ EmbeddedDatabase dataSource() {
+
+ System.out.println(" creating datasource");
+ return new EmbeddedDatabaseBuilder() //
+ .generateUniqueName(true) //
+ .setType(EmbeddedDatabaseType.HSQL) //
+ .setScriptEncoding("UTF-8") //
+ .ignoreFailedDrops(true) //
+ .addScript("org.springframework.data.jdbc.repository/jdbc-repository-id-generation-integration-tests.sql")
+ .build();
+ }
+
+ @Bean
+ NamedParameterJdbcTemplate template(EmbeddedDatabase db) {
+ return new NamedParameterJdbcTemplate(db);
+ }
+
+ @Bean
+ ReadOnlyIdEntityRepository readOnlyIdRepository(EmbeddedDatabase db) {
+
+ return new JdbcRepositoryFactory(new NamedParameterJdbcTemplate(db), mock(ApplicationEventPublisher.class))
+ .getRepository(ReadOnlyIdEntityRepository.class);
+ }
+
+ @Bean
+ PrimitiveIdEntityRepository primitiveIdRepository(NamedParameterJdbcTemplate template) {
+
+ return new JdbcRepositoryFactory(template, mock(ApplicationEventPublisher.class))
+ .getRepository(PrimitiveIdEntityRepository.class);
+ }
+ }
}
diff --git a/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
index 8a90a9c54..9bebfc09e 100644
--- a/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
+++ b/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
@@ -18,91 +18,86 @@ package org.springframework.data.jdbc.repository;
import static java.util.Arrays.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
-import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.*;
+
+import lombok.Data;
+
+import javax.sql.DataSource;
-import org.junit.After;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Id;
+import org.springframework.data.jdbc.repository.JdbcRepositoryIntegrationTests.TestConfiguration;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
-
-import lombok.Data;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.Transactional;
/**
- * very simple use cases for creation and usage of JdbcRepositories.
+ * Very simple use cases for creation and usage of JdbcRepositories.
*
* @author Jens Schauder
*/
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = TestConfiguration.class)
+@Transactional
public class JdbcRepositoryIntegrationTests {
- private final EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
- .generateUniqueName(true)
- .setType(EmbeddedDatabaseType.HSQL)
- .setScriptEncoding("UTF-8")
- .ignoreFailedDrops(true)
- .addScript("org.springframework.data.jdbc.repository/jdbc-repository-integration-tests.sql")
- .build();
-
- private final NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(db);
+ @Autowired NamedParameterJdbcTemplate template;
- private final DummyEntityRepository repository = createRepository(db);
+ @Autowired DummyEntityRepository repository;
private DummyEntity entity = createDummyEntity();
- @After
- public void after() {
- db.shutdown();
- }
-
@Test // DATAJDBC-95
- public void canSaveAnEntity() {
+ public void savesAnEntity() {
entity = repository.save(entity);
- int count = template.queryForObject(
- "SELECT count(*) FROM dummyentity WHERE idProp = :id",
- new MapSqlParameterSource("id", entity.getIdProp()),
- Integer.class);
+ int count = template.queryForObject( //
+ "SELECT count(*) FROM dummyentity WHERE idProp = :id", //
+ new MapSqlParameterSource("id", entity.getIdProp()), //
+ Integer.class //
+ );
- assertEquals(
- 1,
- count);
+ assertEquals(1, count);
}
@Test // DATAJDBC-95
- public void canSaveAndLoadAnEntity() {
+ public void saveAndLoadAnEntity() {
entity = repository.save(entity);
DummyEntity reloadedEntity = repository.findOne(entity.getIdProp());
- assertEquals(
- entity.getIdProp(),
- reloadedEntity.getIdProp());
- assertEquals(
- entity.getName(),
- reloadedEntity.getName());
+ assertEquals(entity.getIdProp(), reloadedEntity.getIdProp());
+ assertEquals(entity.getName(), reloadedEntity.getName());
}
@Test // DATAJDBC-97
- public void saveMany() {
+ public void savesManyEntities() {
DummyEntity other = createDummyEntity();
repository.save(asList(entity, other));
- assertThat(repository.findAll())
- .extracting(DummyEntity::getIdProp)
- .containsExactlyInAnyOrder(
- entity.getIdProp(),
- other.getIdProp()
- );
+ assertThat(repository.findAll()) //
+ .extracting(DummyEntity::getIdProp) //
+ .containsExactlyInAnyOrder( //
+ entity.getIdProp(), other.getIdProp() //
+ );
}
@Test // DATAJDBC-97
@@ -124,8 +119,7 @@ public class JdbcRepositoryIntegrationTests {
Iterable all = repository.findAll();
- assertThat(all).extracting("idProp")
- .containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
+ assertThat(all).extracting("idProp").containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
}
@Test // DATAJDBC-97
@@ -137,12 +131,11 @@ public class JdbcRepositoryIntegrationTests {
Iterable all = repository.findAll(asList(entity.getIdProp(), three.getIdProp()));
- assertThat(all).extracting("idProp")
- .containsExactlyInAnyOrder(entity.getIdProp(), three.getIdProp());
+ assertThat(all).extracting("idProp").containsExactlyInAnyOrder(entity.getIdProp(), three.getIdProp());
}
@Test // DATAJDBC-97
- public void count() {
+ public void countsEntities() {
repository.save(createDummyEntity());
repository.save(createDummyEntity());
@@ -151,7 +144,7 @@ public class JdbcRepositoryIntegrationTests {
assertThat(repository.count()).isEqualTo(3L);
}
- @Test // DATAJDBC-97
+ @Test // DATAJDBC-97
public void deleteById() {
entity = repository.save(entity);
@@ -160,9 +153,11 @@ public class JdbcRepositoryIntegrationTests {
repository.delete(two.getIdProp());
- assertThat(repository.findAll())
- .extracting(DummyEntity::getIdProp)
- .containsExactlyInAnyOrder(entity.getIdProp(), three.getIdProp());
+ assertThat(repository.findAll()) //
+ .extracting(DummyEntity::getIdProp) //
+ .containsExactlyInAnyOrder( //
+ entity.getIdProp(), three.getIdProp() //
+ );
}
@Test // DATAJDBC-97
@@ -174,15 +169,13 @@ public class JdbcRepositoryIntegrationTests {
repository.delete(entity);
- assertThat(repository.findAll())
- .extracting(DummyEntity::getIdProp)
- .containsExactlyInAnyOrder(
- two.getIdProp(),
- three.getIdProp()
- );
+ assertThat(repository.findAll()) //
+ .extracting(DummyEntity::getIdProp) //
+ .containsExactlyInAnyOrder( //
+ two.getIdProp(), three.getIdProp() //
+ );
}
-
@Test // DATAJDBC-97
public void deleteByList() {
@@ -195,7 +188,7 @@ public class JdbcRepositoryIntegrationTests {
assertThat(repository.findAll()).extracting(DummyEntity::getIdProp).containsExactlyInAnyOrder(two.getIdProp());
}
- @Test // DATAJDBC-97
+ @Test // DATAJDBC-97
public void deleteAll() {
repository.save(entity);
@@ -207,7 +200,6 @@ public class JdbcRepositoryIntegrationTests {
assertThat(repository.findAll()).isEmpty();
}
-
@Test // DATAJDBC-98
public void update() {
@@ -233,18 +225,16 @@ public class JdbcRepositoryIntegrationTests {
repository.save(asList(entity, other));
- assertThat(repository.findAll())
- .extracting(DummyEntity::getName)
- .containsExactlyInAnyOrder(entity.getName(), other.getName());
+ assertThat(repository.findAll()).extracting(DummyEntity::getName).containsExactlyInAnyOrder(entity.getName(),
+ other.getName());
}
private static DummyEntityRepository createRepository(EmbeddedDatabase db) {
- return new JdbcRepositoryFactory(mock(ApplicationEventPublisher.class), new NamedParameterJdbcTemplate(db))
+ return new JdbcRepositoryFactory(new NamedParameterJdbcTemplate(db), mock(ApplicationEventPublisher.class))
.getRepository(DummyEntityRepository.class);
}
-
private static DummyEntity createDummyEntity() {
DummyEntity entity = new DummyEntity();
@@ -259,8 +249,42 @@ public class JdbcRepositoryIntegrationTests {
@Data
static class DummyEntity {
- @Id
- private Long idProp;
+ @Id private Long idProp;
String name;
}
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ EmbeddedDatabase dataSource() {
+
+ System.out.println(" creating datasource");
+ return new EmbeddedDatabaseBuilder() //
+ .generateUniqueName(true) //
+ .setType(EmbeddedDatabaseType.HSQL) //
+ .setScriptEncoding("UTF-8") //
+ .ignoreFailedDrops(true) //
+ .addScript("org.springframework.data.jdbc.repository/jdbc-repository-integration-tests.sql") //
+ .build();
+ }
+
+ @Bean
+ NamedParameterJdbcTemplate template(EmbeddedDatabase db) {
+ return new NamedParameterJdbcTemplate(db);
+ }
+
+ @Bean
+ DummyEntityRepository readOnlyIdRepository(NamedParameterJdbcTemplate template) {
+
+ return new JdbcRepositoryFactory(template, mock(ApplicationEventPublisher.class))
+ .getRepository(DummyEntityRepository.class);
+ }
+
+ @Bean
+ PlatformTransactionManager transactionManager(DataSource db) {
+ return new DataSourceTransactionManager(db);
+ }
+
+ }
}
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 36c06e17c..6c34bd934 100644
--- a/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java
+++ b/src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java
@@ -1,27 +1,33 @@
package org.springframework.data.jdbc.repository;
import static java.util.Arrays.*;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
import static org.springframework.util.Assert.*;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.annotation.Id;
-import org.springframework.data.jdbc.mapping.event.AfterDeleteEvent;
-import org.springframework.data.jdbc.mapping.event.AfterInsertEvent;
-import org.springframework.data.jdbc.mapping.event.AfterUpdateEvent;
-import org.springframework.data.jdbc.mapping.event.BeforeDeleteEvent;
-import org.springframework.data.jdbc.mapping.event.BeforeInsertEvent;
-import org.springframework.data.jdbc.mapping.event.BeforeUpdateEvent;
+import org.springframework.data.jdbc.mapping.event.AfterDelete;
+import org.springframework.data.jdbc.mapping.event.AfterInsert;
+import org.springframework.data.jdbc.mapping.event.AfterUpdate;
+import org.springframework.data.jdbc.mapping.event.BeforeDelete;
+import org.springframework.data.jdbc.mapping.event.BeforeInsert;
+import org.springframework.data.jdbc.mapping.event.BeforeUpdate;
+import org.springframework.data.jdbc.mapping.event.Identifier.Specified;
import org.springframework.data.jdbc.mapping.event.JdbcEvent;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
+import org.springframework.jdbc.core.namedparam.SqlParameterSource;
+import org.springframework.jdbc.support.KeyHolder;
import lombok.Data;
@@ -36,10 +42,25 @@ public class SimpleJdbcRepositoryEventsUnitTests {
@Before
public void before() {
- JdbcRepositoryFactory factory = new JdbcRepositoryFactory(publisher, mock(NamedParameterJdbcOperations.class));
+ NamedParameterJdbcOperations operations = createIdGeneratingOperations();
+ JdbcRepositoryFactory factory = new JdbcRepositoryFactory(operations, publisher);
repository = factory.getRepository(DummyEntityRepository.class);
}
+ private NamedParameterJdbcOperations createIdGeneratingOperations() {
+ NamedParameterJdbcOperations operations = mock(NamedParameterJdbcOperations.class);
+ when(operations.update(anyString(), any(SqlParameterSource.class), any(KeyHolder.class))).thenAnswer(new Answer() {
+ @Override
+ public Integer answer(InvocationOnMock invocation) throws Throwable {
+ HashMap keys = new HashMap<>();
+ keys.put("id", 4711L);
+ invocation.getArgumentAt(2, KeyHolder.class).getKeyList().add(keys);
+ return 1;
+ }
+ });
+ return operations;
+ }
+
@Test // DATAJDBC-99
public void publishesEventsOnSave() {
@@ -47,22 +68,24 @@ public class SimpleJdbcRepositoryEventsUnitTests {
repository.save(entity);
- isInstanceOf(BeforeUpdateEvent.class, publisher.events.get(0));
- isInstanceOf(AfterUpdateEvent.class, publisher.events.get(1));
+ isInstanceOf(BeforeUpdate.class, publisher.events.get(0));
+ isInstanceOf(AfterUpdate.class, publisher.events.get(1));
}
@Test // DATAJDBC-99
public void publishesEventsOnSaveMany() {
+
+
DummyEntity entity1 = new DummyEntity(null);
DummyEntity entity2 = new DummyEntity(23L);
repository.save(asList(entity1, entity2));
- isInstanceOf(BeforeInsertEvent.class, publisher.events.get(0));
- isInstanceOf(AfterInsertEvent.class, publisher.events.get(1));
- isInstanceOf(BeforeUpdateEvent.class, publisher.events.get(2));
- isInstanceOf(AfterUpdateEvent.class, publisher.events.get(3));
+ isInstanceOf(BeforeInsert.class, publisher.events.get(0));
+ isInstanceOf(AfterInsert.class, publisher.events.get(1));
+ isInstanceOf(BeforeUpdate.class, publisher.events.get(2));
+ isInstanceOf(AfterUpdate.class, publisher.events.get(3));
}
@@ -73,27 +96,25 @@ public class SimpleJdbcRepositoryEventsUnitTests {
repository.delete(entity);
- isInstanceOf(BeforeDeleteEvent.class, publisher.events.get(0));
- isInstanceOf(AfterDeleteEvent.class, publisher.events.get(1));
+ isInstanceOf(BeforeDelete.class, publisher.events.get(0));
+ isInstanceOf(AfterDelete.class, publisher.events.get(1));
- assertEquals(entity, publisher.events.get(0).getInstance());
- assertEquals(entity, publisher.events.get(1).getInstance());
+ assertEquals(entity, publisher.events.get(0).getOptionalEntity().get());
+ assertEquals(entity, publisher.events.get(1).getOptionalEntity().get());
- assertEquals(23L, publisher.events.get(0).getId());
- assertEquals(23L, publisher.events.get(1).getId());
+ assertEquals(new Specified(23L), publisher.events.get(0).getId());
+ assertEquals(new Specified(23L), publisher.events.get(1).getId());
}
-
@Test // DATAJDBC-99
public void publishesEventsOnDeleteById() {
repository.delete(23L);
- isInstanceOf(BeforeDeleteEvent.class, publisher.events.get(0));
- isInstanceOf(AfterDeleteEvent.class, publisher.events.get(1));
+ isInstanceOf(BeforeDelete.class, publisher.events.get(0));
+ isInstanceOf(AfterDelete.class, publisher.events.get(1));
}
-
@Data
private static class DummyEntity {
diff --git a/src/test/resources/org.springframework.data.jdbc.repository/jdbc-repository-id-generation-integration-tests.sql b/src/test/resources/org.springframework.data.jdbc.repository/jdbc-repository-id-generation-integration-tests.sql
index 0e008210e..c7a764b23 100644
--- a/src/test/resources/org.springframework.data.jdbc.repository/jdbc-repository-id-generation-integration-tests.sql
+++ b/src/test/resources/org.springframework.data.jdbc.repository/jdbc-repository-id-generation-integration-tests.sql
@@ -1,3 +1,5 @@
-- noinspection SqlNoDataSourceInspectionForFile
-CREATE TABLE ReadOnlyIdEntity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, NAME VARCHAR(100))
\ No newline at end of file
+CREATE TABLE ReadOnlyIdEntity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, NAME VARCHAR(100))
+
+CREATE TABLE PrimitiveIdEntity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, NAME VARCHAR(100))
\ No newline at end of file