From dfa63538504f5a2c60bf6a79ec20282c7916c559 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 17 Jun 2016 12:30:57 +1200 Subject: [PATCH] #740 - ClassCastException: java.util.ArrayList cannot be cast to com.avaje.ebean.bean.BeanCollection at com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany.resetMany(BeanPropertyAssocMany.java:273) --- .../server/core/DefaultBeanLoader.java | 2 +- .../server/deploy/BeanCascadeInfo.java | 107 ++++++++++-------- .../server/deploy/BeanDescriptor.java | 4 +- .../server/deploy/BeanPropertyAssoc.java | 9 +- .../server/deploy/BeanPropertyAssocMany.java | 7 +- .../com/avaje/ebean/EbeanServer_refresh.java | 42 +++++++ .../server/deploy/BeanCascadeInfoTest.java | 81 +++++++++++++ src/test/resources/logback-test.xml | 8 +- 8 files changed, 202 insertions(+), 58 deletions(-) create mode 100644 src/test/java/com/avaje/ebeaninternal/server/deploy/BeanCascadeInfoTest.java diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java index ed319ff8a..50ad811d5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java @@ -281,7 +281,7 @@ public class DefaultBeanLoader { } } - SpiQuery query = (SpiQuery) server.createQuery(desc.getBeanType()); + SpiQuery query = server.createQuery(desc.getBeanType()); query.setLazyLoadProperty(ebi.getLazyLoadProperty()); if (draft) { query.asDraft(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanCascadeInfo.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanCascadeInfo.java index 31bb60815..3fb3d59b2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanCascadeInfo.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanCascadeInfo.java @@ -10,56 +10,69 @@ import javax.persistence.CascadeType; */ public class BeanCascadeInfo { - /** - * should delete cascade. - */ - boolean delete; - - /** - * Should save cascade. - */ - boolean save; + private boolean delete; - public void setTypes(CascadeType[] types) { - for (int i = 0; i < types.length; i++) { - setType(types[i]); - } + private boolean save; + + private boolean refresh; + + public void setTypes(CascadeType[] types) { + for (int i = 0; i < types.length; i++) { + setType(types[i]); } - - private void setType(CascadeType type) { - if (type.equals(CascadeType.ALL)){ - save = true; - delete = true; - } - if (type.equals(CascadeType.REMOVE)){ - delete = true; - } - if (type.equals(CascadeType.PERSIST)){ - save = true; - } - if (type.equals(CascadeType.MERGE)){ - save = true; - } - } - - /** - * Return true if delete should cascade. - */ - public boolean isDelete() { - return delete; - } - /** - * Set to true if delete should cascade. - */ - public void setDelete(boolean delete) { - this.delete = delete; - } - /** - * Return true if save should cascade. - */ - public boolean isSave() { - return save; + } + + private void setType(CascadeType type) { + switch (type) { + case ALL: + save = true; + delete = true; + refresh = true; + break; + case REMOVE: + delete = true; + break; + case REFRESH: + refresh = true; + break; + case PERSIST: + save = true; + break; + case MERGE: + save = true; + break; + default: + throw new IllegalStateException("Unexpected CascadeType "+type); } + } + + /** + * Return true if refresh should cascade. + */ + public boolean isRefresh() { + return refresh; + } + + /** + * Return true if delete should cascade. + */ + public boolean isDelete() { + return delete; + } + + /** + * Set to true if delete should cascade. + */ + public void setDelete(boolean delete) { + this.delete = delete; + } + + /** + * Return true if save should cascade. + */ + public boolean isSave() { + return save; + } /** * Set cascade save and delete settings. diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java index 6671e8e78..edb9e24f8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java @@ -2089,7 +2089,9 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { EntityBean bean = (EntityBean)dbBean; for (int i = 0; i < propertiesMany.length; i++) { - propertiesMany[i].resetMany(bean); + if (propertiesMany[i].isCascadeRefresh()) { + propertiesMany[i].resetMany(bean); + } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssoc.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssoc.java index a787a55b4..5b3619cff 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssoc.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssoc.java @@ -168,7 +168,14 @@ public abstract class BeanPropertyAssoc extends BeanProperty { public BeanDescriptor getTargetDescriptor() { return targetDescriptor; } - + + /** + * Return true if REFRESH should cascade. + */ + public boolean isCascadeRefresh() { + return cascadeInfo.isRefresh(); + } + public boolean isSaveRecurseSkippable(Object bean) { return saveRecurseSkippable && bean instanceof EntityBean && !((EntityBean) bean)._ebean_getIntercept().isNewOrDirty(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 970787e10..6be0dd11f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -265,12 +265,11 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { */ public void resetMany(EntityBean bean) { Object value = getValue(bean); - if (value == null) { - // not expecting this - set an empty reference - createReference(bean); - } else { + if (value instanceof BeanCollection) { // reset the collection back to empty ((BeanCollection)value).reset(bean, name); + } else { + createReference(bean); } } diff --git a/src/test/java/com/avaje/ebean/EbeanServer_refresh.java b/src/test/java/com/avaje/ebean/EbeanServer_refresh.java index 31a84e78b..35f9deb1d 100644 --- a/src/test/java/com/avaje/ebean/EbeanServer_refresh.java +++ b/src/test/java/com/avaje/ebean/EbeanServer_refresh.java @@ -1,8 +1,13 @@ package com.avaje.ebean; import com.avaje.tests.model.basic.EBasic; +import com.avaje.tests.model.basic.Order; +import com.avaje.tests.model.basic.OrderDetail; +import com.avaje.tests.model.basic.ResetBasicData; import org.junit.Test; +import java.util.ArrayList; + import static org.junit.Assert.assertEquals; public class EbeanServer_refresh { @@ -27,4 +32,41 @@ public class EbeanServer_refresh { server.refresh(basic); assertEquals(basic.getStatus(), EBasic.Status.ACTIVE); } + + @Test + public void refresh_when_oneToManyLoaded() { + + ResetBasicData.reset(); + + Order order = Ebean.find(Order.class, 1); + order.getCustomer().getName(); + order.getDetails().size(); + + Ebean.refresh(order); + } + + @Test + public void refresh_when_oneToManyVanilla() { + + ResetBasicData.reset(); + + Order order = Ebean.find(Order.class, 1); + order.getCustomer().getName(); + order.setDetails(new ArrayList()); + + Ebean.refresh(order); + } + + @Test + public void refresh_when_oneToManyNull() { + + ResetBasicData.reset(); + + Order order = Ebean.find(Order.class, 1); + order.getCustomer().getName(); + order.setDetails(null); + + Ebean.refresh(order); + } + } diff --git a/src/test/java/com/avaje/ebeaninternal/server/deploy/BeanCascadeInfoTest.java b/src/test/java/com/avaje/ebeaninternal/server/deploy/BeanCascadeInfoTest.java new file mode 100644 index 000000000..cd9ff6809 --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/deploy/BeanCascadeInfoTest.java @@ -0,0 +1,81 @@ +package com.avaje.ebeaninternal.server.deploy; + +import org.junit.Test; + +import javax.persistence.CascadeType; + +import static org.junit.Assert.*; + +public class BeanCascadeInfoTest { + + @Test + public void setTypes_ALL() throws Exception { + + BeanCascadeInfo info = new BeanCascadeInfo(); + info.setTypes(new CascadeType[]{CascadeType.ALL}); + assertTrue(info.isSave()); + assertTrue(info.isDelete()); + assertTrue(info.isRefresh()); + } + + @Test + public void setTypes_PERSIST() throws Exception { + + BeanCascadeInfo info = new BeanCascadeInfo(); + info.setTypes(new CascadeType[]{CascadeType.PERSIST}); + assertTrue(info.isSave()); + assertFalse(info.isDelete()); + assertFalse(info.isRefresh()); + } + + @Test + public void setTypes_MERGE() throws Exception { + + BeanCascadeInfo info = new BeanCascadeInfo(); + info.setTypes(new CascadeType[]{CascadeType.MERGE}); + assertTrue(info.isSave()); + assertFalse(info.isDelete()); + assertFalse(info.isRefresh()); + } + + @Test + public void setTypes_REMOVE() throws Exception { + + BeanCascadeInfo info = new BeanCascadeInfo(); + info.setTypes(new CascadeType[]{CascadeType.REMOVE}); + assertFalse(info.isSave()); + assertTrue(info.isDelete()); + assertFalse(info.isRefresh()); + } + + @Test + public void setTypes_REFRESH() throws Exception { + + BeanCascadeInfo info = new BeanCascadeInfo(); + info.setTypes(new CascadeType[]{CascadeType.REFRESH}); + assertFalse(info.isSave()); + assertFalse(info.isDelete()); + assertTrue(info.isRefresh()); + } + + @Test + public void setDelete() throws Exception { + + BeanCascadeInfo info = new BeanCascadeInfo(); + info.setDelete(true); + assertFalse(info.isSave()); + assertTrue(info.isDelete()); + assertFalse(info.isRefresh()); + } + + @Test + public void setSaveDelete() throws Exception { + + BeanCascadeInfo info = new BeanCascadeInfo(); + info.setSaveDelete(true, true); + assertTrue(info.isSave()); + assertTrue(info.isDelete()); + assertFalse(info.isRefresh()); + } + +} \ No newline at end of file diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index c6a513108..466673fd5 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -76,10 +76,10 @@ - - - - + + + +