diff --git a/ebean-api/src/main/java/io/ebean/common/ModifyHolder.java b/ebean-api/src/main/java/io/ebean/common/ModifyHolder.java index 6da14d3a5..957b0fa88 100644 --- a/ebean-api/src/main/java/io/ebean/common/ModifyHolder.java +++ b/ebean-api/src/main/java/io/ebean/common/ModifyHolder.java @@ -3,9 +3,7 @@ package io.ebean.common; import io.ebean.bean.EntityBean; import java.io.Serializable; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.*; /** * Holds sets of additions and deletions from a 'owner' List Set or Map. @@ -23,19 +21,19 @@ class ModifyHolder implements Serializable { /** * Deletions list for manyToMany persistence. */ - private Set modifyDeletions = new LinkedHashSet<>(); + private Map modifyDeletions = new IdentityHashMap<>(); /** * Additions list for manyToMany persistence. */ - private Set modifyAdditions = new LinkedHashSet<>(); + private Map modifyAdditions = new IdentityHashMap<>(); private boolean touched; void reset() { touched = false; - modifyDeletions = new LinkedHashSet<>(); - modifyAdditions = new LinkedHashSet<>(); + modifyDeletions = new IdentityHashMap<>(); + modifyAdditions = new IdentityHashMap<>(); } /** @@ -50,51 +48,46 @@ class ModifyHolder implements Serializable { } private boolean undoDeletion(E bean) { - return (bean != null) && modifyDeletions.remove(bean); + return (bean != null) && modifyDeletions.remove(bean) != null; } void modifyAddition(E bean) { if (bean != null) { touched = true; - if (bean instanceof EntityBean) { ((EntityBean) bean)._ebean_getIntercept().setDeletedFromCollection(false); } - // If it is to delete then just remove the deletion if (!undoDeletion(bean)) { - // Insert - modifyAdditions.add(bean); + modifyAdditions.put(bean, bean); } } } private boolean undoAddition(Object bean) { - return (bean != null) && modifyAdditions.remove(bean); + return (bean != null) && modifyAdditions.remove(bean) != null; } @SuppressWarnings("unchecked") void modifyRemoval(Object bean) { if (bean != null) { touched = true; - if (bean instanceof EntityBean) { ((EntityBean) bean)._ebean_getIntercept().setDeletedFromCollection(true); } - // If it is to be added then just remove the addition if (!undoAddition(bean)) { - modifyDeletions.add((E) bean); + modifyDeletions.put((E) bean, bean); } } } Set getModifyAdditions() { - return modifyAdditions; + return modifyAdditions.keySet(); } Set getModifyRemovals() { - return modifyDeletions; + return modifyDeletions.keySet(); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java index f273b9dbc..1f1da9fc0 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java @@ -295,7 +295,16 @@ public class SaveManyBeans extends SaveManyBase { } transaction.depth(+1); - + if (deletions != null && !deletions.isEmpty()) { + for (Object other : deletions) { + EntityBean otherDelete = (EntityBean) other; + // the object from the 'other' side of the ManyToMany + // build a intersection row for 'delete' + IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherDelete, publish); + SpiSqlUpdate sqlDelete = intRow.createDelete(server, DeleteMode.HARD); + persister.executeOrQueue(sqlDelete, transaction, queue); + } + } if (additions != null && !additions.isEmpty()) { for (Object other : additions) { EntityBean otherBean = (EntityBean) other; @@ -318,16 +327,6 @@ public class SaveManyBeans extends SaveManyBase { } } } - if (deletions != null && !deletions.isEmpty()) { - for (Object other : deletions) { - EntityBean otherDelete = (EntityBean) other; - // the object from the 'other' side of the ManyToMany - // build a intersection row for 'delete' - IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherDelete, publish); - SpiSqlUpdate sqlDelete = intRow.createDelete(server, DeleteMode.HARD); - persister.executeOrQueue(sqlDelete, transaction, queue); - } - } // decrease the depth back to what it was transaction.depth(-1); } diff --git a/ebean-core/src/test/java/io/ebean/common/BeanListTest.java b/ebean-core/src/test/java/io/ebean/common/BeanListTest.java index 11a7429d7..03c08efad 100644 --- a/ebean-core/src/test/java/io/ebean/common/BeanListTest.java +++ b/ebean-core/src/test/java/io/ebean/common/BeanListTest.java @@ -4,7 +4,6 @@ import io.ebean.bean.BeanCollection; import org.junit.Test; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -13,9 +12,9 @@ import static org.assertj.core.api.Assertions.assertThat; public class BeanListTest { - private Object object1 = new Object(); - private Object object2 = new Object(); - private Object object3 = new Object(); + private final Object object1 = new Object(); + private final Object object2 = new Object(); + private final Object object3 = new Object(); private List all() { List all = new ArrayList<>(); @@ -33,7 +32,7 @@ public class BeanListTest { } @Test - public void test_setModifyListening_null() throws Exception { + public void test_setModifyListening_null() { BeanList list = new BeanList<>(); list.setModifyListening(null); @@ -45,7 +44,7 @@ public class BeanListTest { } @Test - public void test_setModifyListening_none() throws Exception { + public void test_setModifyListening_none() { BeanList list = new BeanList<>(); list.setModifyListening(BeanCollection.ModifyListenMode.NONE); @@ -57,28 +56,28 @@ public class BeanListTest { } @Test - public void testAdd() throws Exception { + public void testAdd() { BeanList list = new BeanList<>(); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); list.add(object1); - assertThat(list.getModifyAdditions()).containsExactly(object1); + assertThat(list.getModifyAdditions()).containsOnly(object1); assertThat(list.getModifyRemovals()).isEmpty(); list.add(object1); - assertThat(list.getModifyAdditions()).containsExactly(object1); + assertThat(list.getModifyAdditions()).containsOnly(object1); list.add(object2); - assertThat(list.getModifyAdditions()).containsExactly(object1, object2); + assertThat(list.getModifyAdditions()).containsOnly(object1, object2); list.remove(object1); - assertThat(list.getModifyAdditions()).containsExactly(object2); + assertThat(list.getModifyAdditions()).containsOnly(object2); assertThat(list.getModifyRemovals()).isEmpty(); } @Test - public void testAddAll_given_emptyStart() throws Exception { + public void testAddAll_given_emptyStart() { BeanList list = new BeanList<>(); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -86,12 +85,12 @@ public class BeanListTest { // act list.addAll(all()); - assertThat(list.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(list.getModifyAdditions()).containsOnly(object1, object2, object3); assertThat(list.getModifyRemovals()).isEmpty(); } @Test - public void test_removals_DeleteThenAddBack_expect_noChange() throws Exception { + public void test_removals_DeleteThenAddBack_expect_noChange() { BeanList list = new BeanList<>(some()); list.setModifyListening(BeanCollection.ModifyListenMode.REMOVALS); @@ -106,33 +105,33 @@ public class BeanListTest { } @Test - public void test_sort_whenAll_expect_noChange() throws Exception { + public void test_sort_whenAll_expect_noChange() { BeanList list = new BeanList<>(all()); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); // act - Collections.sort(list, Comparator.comparingInt(Object::hashCode)); + list.sort(Comparator.comparingInt(Object::hashCode)); assertThat(list.getModifyRemovals()).isEmpty(); assertThat(list.getModifyAdditions()).isEmpty(); } @Test - public void test_sort_whenRemovals_expect_noChange() throws Exception { + public void test_sort_whenRemovals_expect_noChange() { BeanList list = new BeanList<>(all()); list.setModifyListening(BeanCollection.ModifyListenMode.REMOVALS); // act - Collections.sort(list, Comparator.comparingInt(Object::hashCode)); + list.sort(Comparator.comparingInt(Object::hashCode)); assertThat(list.getModifyRemovals()).isEmpty(); assertThat(list.getModifyAdditions()).isEmpty(); } @Test - public void testAdd_given_someAlreadyIn() throws Exception { + public void testAdd_given_someAlreadyIn() { BeanList list = new BeanList<>(some()); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -143,12 +142,12 @@ public class BeanListTest { assertThat(list.contains(object2)).isTrue(); list.add(object2); // object2 added as List allows duplicates - assertThat(list.getModifyAdditions()).containsExactly(object1, object2); + assertThat(list.getModifyAdditions()).containsOnly(object1, object2); assertThat(list.getModifyRemovals()).isEmpty(); } @Test - public void testAddSome_given_someAlreadyIn() throws Exception { + public void testAddSome_given_someAlreadyIn() { BeanList list = new BeanList<>(some()); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -156,43 +155,43 @@ public class BeanListTest { // act list.addAll(all()); - assertThat(list.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(list.getModifyAdditions()).containsOnly(object1, object2, object3); assertThat(list.getModifyRemovals()).isEmpty(); } @Test - public void testRemove_given_beansInAdditions() throws Exception { + public void testRemove_given_beansInAdditions() { BeanList list = new BeanList<>(); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); list.addAll(all()); - assertThat(list.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(list.getModifyAdditions()).containsOnly(object1, object2, object3); // act list.remove(object2); list.remove(object3); - assertThat(list.getModifyAdditions()).containsExactly(object1); + assertThat(list.getModifyAdditions()).containsOnly(object1); assertThat(list.getModifyRemovals()).isEmpty(); } @Test - public void testRemoveAll_given_beansInAdditions() throws Exception { + public void testRemoveAll_given_beansInAdditions() { BeanList list = new BeanList<>(); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); list.addAll(all()); - assertThat(list.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(list.getModifyAdditions()).containsOnly(object1, object2, object3); // act list.removeAll(some()); - assertThat(list.getModifyAdditions()).containsExactly(object1); + assertThat(list.getModifyAdditions()).containsOnly(object1); assertThat(list.getModifyRemovals()).isEmpty(); } @Test - public void testRemove_given_beansNotInAdditions() throws Exception { + public void testRemove_given_beansNotInAdditions() { BeanList list = new BeanList<>(all()); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -203,11 +202,11 @@ public class BeanListTest { // assert assertThat(list.getModifyAdditions()).isEmpty(); - assertThat(list.getModifyRemovals()).containsExactly(object2, object3); + assertThat(list.getModifyRemovals()).containsOnly(object2, object3); } @Test - public void testRemoveAll_given_beansNotInAdditions() throws Exception { + public void testRemoveAll_given_beansNotInAdditions() { BeanList list = new BeanList<>(all()); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -217,11 +216,11 @@ public class BeanListTest { // assert assertThat(list.getModifyAdditions()).isEmpty(); - assertThat(list.getModifyRemovals()).containsExactly(object2, object3); + assertThat(list.getModifyRemovals()).containsOnly(object2, object3); } @Test - public void testClear() throws Exception { + public void testClear() { BeanList list = new BeanList<>(all()); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -230,12 +229,12 @@ public class BeanListTest { list.clear(); //assert - assertThat(list.getModifyRemovals()).containsExactly(object1, object2, object3); + assertThat(list.getModifyRemovals()).containsOnly(object1, object2, object3); assertThat(list.getModifyAdditions()).isEmpty(); } @Test - public void testClear_given_someBeansInAdditions() throws Exception { + public void testClear_given_someBeansInAdditions() { BeanList list = new BeanList<>(); list.add(object1); @@ -247,27 +246,27 @@ public class BeanListTest { list.clear(); //assert - assertThat(list.getModifyRemovals()).containsExactly(object1); + assertThat(list.getModifyRemovals()).containsOnly(object1); assertThat(list.getModifyAdditions()).isEmpty(); } @Test - public void testRetainAll_given_beansInAdditions() throws Exception { + public void testRetainAll_given_beansInAdditions() { BeanList list = new BeanList<>(); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); list.addAll(all()); - assertThat(list.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(list.getModifyAdditions()).containsOnly(object1, object2, object3); // act list.retainAll(some()); - assertThat(list.getModifyAdditions()).containsExactly(object2, object3); + assertThat(list.getModifyAdditions()).containsOnly(object2, object3); assertThat(list.getModifyRemovals()).isEmpty(); } @Test - public void testRetainAll_given_someBeansInAdditions() throws Exception { + public void testRetainAll_given_someBeansInAdditions() { BeanList list = new BeanList<>(); list.add(object1); @@ -278,12 +277,12 @@ public class BeanListTest { // act list.retainAll(some()); - assertThat(list.getModifyAdditions()).containsExactly(object3); - assertThat(list.getModifyRemovals()).containsExactly(object1); + assertThat(list.getModifyAdditions()).containsOnly(object3); + assertThat(list.getModifyRemovals()).containsOnly(object1); } @Test - public void testRetainAll_given_noBeansInAdditions() throws Exception { + public void testRetainAll_given_noBeansInAdditions() { BeanList list = new BeanList<>(all()); list.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -291,7 +290,7 @@ public class BeanListTest { // act list.retainAll(some()); - assertThat(list.getModifyRemovals()).containsExactly(object1); + assertThat(list.getModifyRemovals()).containsOnly(object1); } @Test diff --git a/ebean-core/src/test/java/io/ebean/common/BeanMapTest.java b/ebean-core/src/test/java/io/ebean/common/BeanMapTest.java index 003539a72..3101fc0f2 100644 --- a/ebean-core/src/test/java/io/ebean/common/BeanMapTest.java +++ b/ebean-core/src/test/java/io/ebean/common/BeanMapTest.java @@ -34,30 +34,30 @@ public class BeanMapTest { } @Test - public void testAdd() throws Exception { + public void testAdd() { BeanMap map = new BeanMap<>(); map.setModifyListening(BeanCollection.ModifyListenMode.ALL); map.put("1", object1); map.put("4", null); - assertThat(map.getModifyAdditions()).containsExactly(object1); + assertThat(map.getModifyAdditions()).containsOnly(object1); assertThat(map.getModifyRemovals()).isEmpty(); map.put("1", object1); map.put("4", null); - assertThat(map.getModifyAdditions()).containsExactly(object1); + assertThat(map.getModifyAdditions()).containsOnly(object1); map.put("2", object2); - assertThat(map.getModifyAdditions()).containsExactly(object1, object2); + assertThat(map.getModifyAdditions()).containsOnly(object1, object2); map.remove("1"); - assertThat(map.getModifyAdditions()).containsExactly(object2); + assertThat(map.getModifyAdditions()).containsOnly(object2); assertThat(map.getModifyRemovals()).isEmpty(); } @Test - public void testAddAll_given_emptyStart() throws Exception { + public void testAddAll_given_emptyStart() { BeanMap set = new BeanMap<>(); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -65,28 +65,28 @@ public class BeanMapTest { // act set.putAll(all()); - assertThat(set.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(set.getModifyAdditions()).containsOnly(object1, object2, object3); assertThat(set.getModifyRemovals()).isEmpty(); } @Test - public void testAdd_given_someAlreadyIn() throws Exception { + public void testAdd_given_someAlreadyIn() { BeanMap map = new BeanMap<>(some()); map.setModifyListening(BeanCollection.ModifyListenMode.ALL); // act - assertThat(map.values().contains(object1)).isFalse(); + assertThat(map.containsValue(object1)).isFalse(); map.put("1", object1); - assertThat(map.values().contains(object2)).isTrue(); + assertThat(map.containsValue(object2)).isTrue(); map.put("2", object2); - assertThat(map.getModifyAdditions()).containsExactly(object1); + assertThat(map.getModifyAdditions()).containsOnly(object1); assertThat(map.getModifyRemovals()).isEmpty(); } @Test - public void testAddSome_given_someAlreadyIn() throws Exception { + public void testAddSome_given_someAlreadyIn() { BeanMap map = new BeanMap<>(some()); map.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -94,44 +94,44 @@ public class BeanMapTest { // act map.putAll(all()); - assertThat(map.getModifyAdditions()).containsExactly(object1); + assertThat(map.getModifyAdditions()).containsOnly(object1); assertThat(map.getModifyRemovals()).isEmpty(); } @Test - public void testRemove_given_beansInAdditions() throws Exception { + public void testRemove_given_beansInAdditions() { BeanMap map = new BeanMap<>(); map.setModifyListening(BeanCollection.ModifyListenMode.ALL); map.putAll(all()); - assertThat(map.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(map.getModifyAdditions()).containsOnly(object1, object2, object3); // act map.remove("2"); map.remove("3"); - assertThat(map.getModifyAdditions()).containsExactly(object1); + assertThat(map.getModifyAdditions()).containsOnly(object1); assertThat(map.getModifyRemovals()).isEmpty(); } @Test - public void testRemoveAll_given_beansInAdditions() throws Exception { + public void testRemoveAll_given_beansInAdditions() { BeanMap map = new BeanMap<>(); map.setModifyListening(BeanCollection.ModifyListenMode.ALL); map.putAll(all()); - assertThat(map.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(map.getModifyAdditions()).containsOnly(object1, object2, object3); // act map.remove("2"); map.remove("3"); - assertThat(map.getModifyAdditions()).containsExactly(object1); + assertThat(map.getModifyAdditions()).containsOnly(object1); assertThat(map.getModifyRemovals()).isEmpty(); } @Test - public void testRemove_given_beansNotInAdditions() throws Exception { + public void testRemove_given_beansNotInAdditions() { BeanMap map = new BeanMap<>(all()); map.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -142,11 +142,11 @@ public class BeanMapTest { // assert assertThat(map.getModifyAdditions()).isEmpty(); - assertThat(map.getModifyRemovals()).containsExactly(object2, object3); + assertThat(map.getModifyRemovals()).containsOnly(object2, object3); } @Test - public void testRemoveAll_given_beansNotInAdditions() throws Exception { + public void testRemoveAll_given_beansNotInAdditions() { BeanMap map = new BeanMap<>(all()); map.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -157,11 +157,11 @@ public class BeanMapTest { // assert assertThat(map.getModifyAdditions()).isEmpty(); - assertThat(map.getModifyRemovals()).containsExactly(object2, object3); + assertThat(map.getModifyRemovals()).containsOnly(object2, object3); } @Test - public void testClear() throws Exception { + public void testClear() { BeanMap map = new BeanMap<>(all()); map.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -170,12 +170,12 @@ public class BeanMapTest { map.clear(); //assert - assertThat(map.getModifyRemovals()).containsExactly(object1, object2, object3); + assertThat(map.getModifyRemovals()).containsOnly(object1, object2, object3); assertThat(map.getModifyAdditions()).isEmpty(); } @Test - public void testClear_given_someBeansInAdditions() throws Exception { + public void testClear_given_someBeansInAdditions() { BeanMap map = newModifyListeningMap(); map.put("2", object2); @@ -185,7 +185,7 @@ public class BeanMapTest { map.clear(); //assert - assertThat(map.getModifyRemovals()).containsExactly(object1); + assertThat(map.getModifyRemovals()).containsOnly(object1); assertThat(map.getModifyAdditions()).isEmpty(); } @@ -228,7 +228,7 @@ public class BeanMapTest { assertThat(map).doesNotContainKeys("1"); assertThat(map.get("1")).isNull(); - assertThat(map.getModifyRemovals()).containsExactly(object1); + assertThat(map.getModifyRemovals()).containsOnly(object1); } @Test @@ -245,7 +245,7 @@ public class BeanMapTest { assertThat(map).isEmpty(); assertThat(keySet).isEmpty(); - assertThat(map.getModifyRemovals()).containsExactly(object1, object2); + assertThat(map.getModifyRemovals()).containsOnly(object1, object2); } @Test @@ -258,20 +258,14 @@ public class BeanMapTest { map.setModifyListening(BeanCollection.ModifyListenMode.ALL); final Set keySet = map.keySet(); - final Iterator iterator = keySet.iterator(); - while (iterator.hasNext()) { - final String key = iterator.next(); - if (key.equals("2")) { - iterator.remove(); - } - } + keySet.removeIf(key -> key.equals("2")); assertThat(map).hasSize(2); assertThat(keySet).hasSize(2); assertThat(keySet).containsExactly("1", "3"); assertThat(map).containsKeys("1", "3"); - assertThat(map.getModifyRemovals()).containsExactly(object2); + assertThat(map.getModifyRemovals()).containsOnly(object2); } @Test @@ -294,7 +288,7 @@ public class BeanMapTest { assertThat(keySet).containsExactly("1", "4"); assertThat(map).containsKeys("1", "4"); - assertThat(map.getModifyRemovals()).containsExactly(object2, object3, object5); + assertThat(map.getModifyRemovals()).containsOnly(object2, object3, object5); } @@ -318,7 +312,7 @@ public class BeanMapTest { assertThat(keySet).containsExactly("2", "3", "5"); assertThat(map).containsKeys("2", "3", "5"); - assertThat(map.getModifyRemovals()).containsExactly(object1, object4); + assertThat(map.getModifyRemovals()).containsOnly(object1, object4); } @Test(expected = UnsupportedOperationException.class) @@ -348,7 +342,7 @@ public class BeanMapTest { assertThat(entries).isEmpty(); assertThat(map).isEmpty(); - assertThat(map.getModifyRemovals()).containsExactly(object1); + assertThat(map.getModifyRemovals()).containsOnly(object1); } @Test @@ -365,7 +359,7 @@ public class BeanMapTest { assertThat(existed22).isFalse(); assertThat(map).hasSize(4); - assertThat(map.getModifyRemovals()).containsExactly(object1); + assertThat(map.getModifyRemovals()).containsOnly(object1); } @Test @@ -395,7 +389,7 @@ public class BeanMapTest { } assertThat(map).hasSize(3); assertThat(entries).hasSize(3); - assertThat(map.getModifyRemovals()).containsExactly(object2, object5); + assertThat(map.getModifyRemovals()).containsOnly(object2, object5); } @Test @@ -406,7 +400,7 @@ public class BeanMapTest { entries.removeAll(asList(new AbstractMap.SimpleEntry<>("1", object1), new AbstractMap.SimpleEntry<>("3", object4), new AbstractMap.SimpleEntry<>("4", object4))); assertThat(map).hasSize(3); assertThat(entries).hasSize(3); - assertThat(map.getModifyRemovals()).containsExactly(object1, object4); + assertThat(map.getModifyRemovals()).containsOnly(object1, object4); } @Test @@ -417,7 +411,7 @@ public class BeanMapTest { entries.retainAll(asList(new AbstractMap.SimpleEntry<>("1", object1), new AbstractMap.SimpleEntry<>("3", object4), new AbstractMap.SimpleEntry<>("4", object4))); assertThat(map).hasSize(2); assertThat(entries).hasSize(2); - assertThat(map.getModifyRemovals()).containsExactly(object2, object3, object5); + assertThat(map.getModifyRemovals()).containsOnly(object2, object3, object5); } private BeanMap newModifyListeningMap() { diff --git a/ebean-core/src/test/java/io/ebean/common/BeanSetTest.java b/ebean-core/src/test/java/io/ebean/common/BeanSetTest.java index c274d34d7..40253faef 100644 --- a/ebean-core/src/test/java/io/ebean/common/BeanSetTest.java +++ b/ebean-core/src/test/java/io/ebean/common/BeanSetTest.java @@ -31,28 +31,28 @@ public class BeanSetTest { } @Test - public void testAdd() throws Exception { + public void testAdd() { BeanSet set = new BeanSet<>(); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); set.add(object1); - assertThat(set.getModifyAdditions()).containsExactly(object1); + assertThat(set.getModifyAdditions()).containsOnly(object1); assertThat(set.getModifyRemovals()).isEmpty(); set.add(object1); - assertThat(set.getModifyAdditions()).containsExactly(object1); + assertThat(set.getModifyAdditions()).containsOnly(object1); set.add(object2); - assertThat(set.getModifyAdditions()).containsExactly(object1, object2); + assertThat(set.getModifyAdditions()).containsOnly(object1, object2); set.remove(object1); - assertThat(set.getModifyAdditions()).containsExactly(object2); + assertThat(set.getModifyAdditions()).containsOnly(object2); assertThat(set.getModifyRemovals()).isEmpty(); } @Test - public void testAddAll_given_emptyStart() throws Exception { + public void testAddAll_given_emptyStart() { BeanSet set = new BeanSet<>(); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -60,12 +60,12 @@ public class BeanSetTest { // act set.addAll(all()); - assertThat(set.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(set.getModifyAdditions()).containsOnly(object1, object2, object3); assertThat(set.getModifyRemovals()).isEmpty(); } @Test - public void testAdd_given_someAlreadyIn() throws Exception { + public void testAdd_given_someAlreadyIn() { BeanSet set = new BeanSet<>(some()); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -76,12 +76,12 @@ public class BeanSetTest { assertThat(set.contains(object2)).isTrue(); set.add(object2); - assertThat(set.getModifyAdditions()).containsExactly(object1); + assertThat(set.getModifyAdditions()).containsOnly(object1); assertThat(set.getModifyRemovals()).isEmpty(); } @Test - public void testAddSome_given_someAlreadyIn() throws Exception { + public void testAddSome_given_someAlreadyIn() { BeanSet set = new BeanSet<>(some()); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -89,43 +89,43 @@ public class BeanSetTest { // act set.addAll(all()); - assertThat(set.getModifyAdditions()).containsExactly(object1); + assertThat(set.getModifyAdditions()).containsOnly(object1); assertThat(set.getModifyRemovals()).isEmpty(); } @Test - public void testRemove_given_beansInAdditions() throws Exception { + public void testRemove_given_beansInAdditions() { BeanSet set = new BeanSet<>(); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); set.addAll(all()); - assertThat(set.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(set.getModifyAdditions()).containsOnly(object1, object2, object3); // act set.remove(object2); set.remove(object3); - assertThat(set.getModifyAdditions()).containsExactly(object1); + assertThat(set.getModifyAdditions()).containsOnly(object1); assertThat(set.getModifyRemovals()).isEmpty(); } @Test - public void testRemoveAll_given_beansInAdditions() throws Exception { + public void testRemoveAll_given_beansInAdditions() { BeanSet set = new BeanSet<>(); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); set.addAll(all()); - assertThat(set.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(set.getModifyAdditions()).containsOnly(object1, object2, object3); // act set.removeAll(some()); - assertThat(set.getModifyAdditions()).containsExactly(object1); + assertThat(set.getModifyAdditions()).containsOnly(object1); assertThat(set.getModifyRemovals()).isEmpty(); } @Test - public void testRemove_given_beansNotInAdditions() throws Exception { + public void testRemove_given_beansNotInAdditions() { BeanSet set = new BeanSet<>(all()); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -136,11 +136,11 @@ public class BeanSetTest { // assert assertThat(set.getModifyAdditions()).isEmpty(); - assertThat(set.getModifyRemovals()).containsExactly(object2, object3); + assertThat(set.getModifyRemovals()).containsOnly(object2, object3); } @Test - public void testRemoveAll_given_beansNotInAdditions() throws Exception { + public void testRemoveAll_given_beansNotInAdditions() { BeanSet set = new BeanSet<>(all()); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -150,11 +150,11 @@ public class BeanSetTest { // assert assertThat(set.getModifyAdditions()).isEmpty(); - assertThat(set.getModifyRemovals()).containsExactly(object2, object3); + assertThat(set.getModifyRemovals()).containsOnly(object2, object3); } @Test - public void testClear() throws Exception { + public void testClear() { BeanSet set = new BeanSet<>(all()); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -163,12 +163,12 @@ public class BeanSetTest { set.clear(); //assert - assertThat(set.getModifyRemovals()).containsExactly(object1, object2, object3); + assertThat(set.getModifyRemovals()).containsOnly(object1, object2, object3); assertThat(set.getModifyAdditions()).isEmpty(); } @Test - public void testClear_given_someBeansInAdditions() throws Exception { + public void testClear_given_someBeansInAdditions() { BeanSet set = new BeanSet<>(); set.add(object1); @@ -180,27 +180,27 @@ public class BeanSetTest { set.clear(); //assert - assertThat(set.getModifyRemovals()).containsExactly(object1); + assertThat(set.getModifyRemovals()).containsOnly(object1); assertThat(set.getModifyAdditions()).isEmpty(); } @Test - public void testRetainAll_given_beansInAdditions() throws Exception { + public void testRetainAll_given_beansInAdditions() { BeanSet set = new BeanSet<>(); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); set.addAll(all()); - assertThat(set.getModifyAdditions()).containsExactly(object1, object2, object3); + assertThat(set.getModifyAdditions()).containsOnly(object1, object2, object3); // act set.retainAll(some()); - assertThat(set.getModifyAdditions()).containsExactly(object2, object3); + assertThat(set.getModifyAdditions()).containsOnly(object2, object3); assertThat(set.getModifyRemovals()).isEmpty(); } @Test - public void testRetainAll_given_someBeansInAdditions() throws Exception { + public void testRetainAll_given_someBeansInAdditions() { BeanSet set = new BeanSet<>(); set.add(object1); @@ -211,12 +211,12 @@ public class BeanSetTest { // act set.retainAll(some()); - assertThat(set.getModifyAdditions()).containsExactly(object3); - assertThat(set.getModifyRemovals()).containsExactly(object1); + assertThat(set.getModifyAdditions()).containsOnly(object3); + assertThat(set.getModifyRemovals()).containsOnly(object1); } @Test - public void testRetainAll_given_noBeansInAdditions() throws Exception { + public void testRetainAll_given_noBeansInAdditions() { BeanSet set = new BeanSet<>(all()); set.setModifyListening(BeanCollection.ModifyListenMode.ALL); @@ -224,7 +224,7 @@ public class BeanSetTest { // act set.retainAll(some()); - assertThat(set.getModifyRemovals()).containsExactly(object1); + assertThat(set.getModifyRemovals()).containsOnly(object1); } } diff --git a/ebean-core/src/test/java/org/tests/m2m/TestM2MModifyTest.java b/ebean-core/src/test/java/org/tests/m2m/TestM2MModifyTest.java index 1f12f85c8..3a50fa547 100644 --- a/ebean-core/src/test/java/org/tests/m2m/TestM2MModifyTest.java +++ b/ebean-core/src/test/java/org/tests/m2m/TestM2MModifyTest.java @@ -1,14 +1,15 @@ package org.tests.m2m; import io.ebean.BaseTestCase; -import io.ebean.Ebean; +import io.ebean.DB; +import org.junit.Test; import org.tests.model.basic.MRole; import org.tests.model.basic.MUser; -import org.junit.Assert; -import org.junit.Test; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + public class TestM2MModifyTest extends BaseTestCase { @Test @@ -19,8 +20,8 @@ public class TestM2MModifyTest extends BaseTestCase { MRole r1 = new MRole("r1"); // Save r1 and r2 - Ebean.save(r0); - Ebean.save(r1); + DB.save(r0); + DB.save(r1); // Create a new user MUser u0 = new MUser("usr0"); @@ -28,32 +29,27 @@ public class TestM2MModifyTest extends BaseTestCase { u0.addRole(r1); // Save the user - Ebean.save(u0); + DB.save(u0); List roles = u0.getRoles(); - Assert.assertTrue(roles.size() == 2); + assertThat(roles).hasSize(2); - u0 = Ebean.find(MUser.class, u0.getUserid()); + u0 = DB.find(MUser.class, u0.getUserid()); roles = u0.getRoles(); - int nrRoles = roles.size(); - - Assert.assertTrue(nrRoles == 2); + assertThat(roles).hasSize(2); roles.clear(); roles.add(r0); roles.add(r1); roles.remove(r1); - Ebean.save(u0); + DB.save(u0); - u0 = Ebean.find(MUser.class, u0.getUserid()); + u0 = DB.find(MUser.class, u0.getUserid()); roles = u0.getRoles(); - - nrRoles = roles.size(); - - Assert.assertTrue(nrRoles == 1); + assertThat(roles).hasSize(1); } } diff --git a/ebean-core/src/test/java/org/tests/model/orphanremoval/OmBeanListChild.java b/ebean-core/src/test/java/org/tests/model/orphanremoval/OmBeanListChild.java new file mode 100644 index 000000000..75790e26a --- /dev/null +++ b/ebean-core/src/test/java/org/tests/model/orphanremoval/OmBeanListChild.java @@ -0,0 +1,33 @@ +package org.tests.model.orphanremoval; + +import io.ebean.Model; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Version; + +@Entity +public class OmBeanListChild extends Model { + + @Id + private Long id; + + private final String name; + + @ManyToOne + private OmBeanListParent parent; + + @Version + private long version; + + public OmBeanListChild(String name) { + this.name = name; + } + + public Long getId() { + return id; + } +} + + diff --git a/ebean-core/src/test/java/org/tests/model/orphanremoval/OmBeanListParent.java b/ebean-core/src/test/java/org/tests/model/orphanremoval/OmBeanListParent.java new file mode 100644 index 000000000..6a9cd478f --- /dev/null +++ b/ebean-core/src/test/java/org/tests/model/orphanremoval/OmBeanListParent.java @@ -0,0 +1,40 @@ +package org.tests.model.orphanremoval; + +import io.ebean.Model; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Version; +import java.util.List; + +import static javax.persistence.CascadeType.ALL; + +@Entity +public class OmBeanListParent extends Model { + + @Id + private long id; + + @Version + private long version; + + @OneToMany(cascade = ALL, mappedBy = "parent", orphanRemoval = true) + private List children; + + public long getId() { + return id; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + // So a BeanList is used and overwriting children will replace the table entries + this.children.clear(); + this.children.addAll(children); + } +} + + diff --git a/ebean-core/src/test/java/org/tests/model/orphanremoval/TestOrphanRemovalOverwrite.java b/ebean-core/src/test/java/org/tests/model/orphanremoval/TestOrphanRemovalOverwrite.java new file mode 100644 index 000000000..9c6fa045b --- /dev/null +++ b/ebean-core/src/test/java/org/tests/model/orphanremoval/TestOrphanRemovalOverwrite.java @@ -0,0 +1,37 @@ +package org.tests.model.orphanremoval; + +import org.junit.Test; + +import java.util.List; + +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class TestOrphanRemovalOverwrite { + + @Test + public void testOverwritingMapping() { + OmBeanListParent parent = new OmBeanListParent(); + parent.save(); + + // Refreshing/querying sets the modifyListening flag on the association's BeanList + parent.refresh(); + + List childList = singletonList(new OmBeanListChild("child1")); + // Adding the children to the BeanList causes _ebean_getIdentity to be invoked before the children have been persisted and + // have Ids. + parent.setChildren(childList); + + // Give the children Ids + parent.save(); + + // Refreshing here generates new objects for the associated children that are referred to by the parent. + parent.refresh(); + + assertNotNull("The children should now have Ids as they are persisted to the db.", childList.get(0).getId()); + assertEquals("The children should have the same Id as the ones on the parent.", + childList.get(0).getId(), parent.getChildren().get(0).getId()); + assertEquals("The children should therefore equal the children on the parent.", childList, parent.getChildren()); + } +}