Fix #23 - Covers: unit tests for: stateless updates which fails when executing without...

This commit is contained in:
Rob Bygrave
2014-04-23 21:16:30 +12:00
parent b012720a5e
commit a7df7da984
12 changed files with 222 additions and 28 deletions
@@ -31,6 +31,12 @@ public interface BeanCollection<E> extends Serializable {
ALL
}
/**
* Return true if the collection is empty and untouched. Used to detect if a
* collection was 'cleared' deliberately or just un-initialised.
*/
public boolean isEmptyAndUntouched();
/**
* Return the bean that owns this collection.
*/
@@ -744,6 +744,13 @@ public final class EntityBeanIntercept implements Serializable {
return obj1.equals(obj2);
}
/**
* Called when a BeanCollection is initialised automatically.
*/
public void initialisedMany(int propertyIndex) {
loadedProps[propertyIndex] = true;
}
/**
* Method that is called prior to a getter method on the actual entity.
*/
@@ -58,6 +58,12 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected boolean modifyRemoveListening;
protected boolean modifyListening;
/**
* Flag used to tell if empty collections have been cleared etc or just
* uninitialised.
*/
protected boolean touched;
/**
* Constructor not non-lazy loading collection.
*/
@@ -112,7 +118,14 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
checkEmptyLazyLoad();
}
protected void touched() {
/**
* Set touched. If setFlag is false then typically an isEmpty() call and still
* considering that to be untouched.
*/
protected void touched(boolean setFlag) {
if (setFlag) {
touched = true;
}
if (beanCollectionTouched != null) {
// only call this once
beanCollectionTouched.notifyTouched(this);
@@ -46,6 +46,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
super(loader, ownerBean, propertyName);
}
@Override
public boolean isEmptyAndUntouched() {
return !touched && (list == null || list.isEmpty());
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
list.add((E) bean);
@@ -77,16 +82,24 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
list = new ArrayList<E>();
}
}
touched();
touched(true);
}
}
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (list == null) {
lazyLoadCollection(false);
}
touched();
touched(setTouched);
}
}
@@ -259,7 +272,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
public boolean isEmpty() {
init();
initAsUntouched();
return list.isEmpty();
}
@@ -39,6 +39,10 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
super(ebeanServer, ownerBean, propertyName);
}
public boolean isEmptyAndUntouched() {
return !touched && (map == null || map.isEmpty());
}
@SuppressWarnings("unchecked")
public void internalPut(Object key, Object bean) {
@@ -86,16 +90,24 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
map = new LinkedHashMap<K, E>();
}
}
touched();
touched(true);
}
}
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (map == null) {
lazyLoadCollection(false);
}
touched();
touched(setTouched);
}
}
@@ -212,7 +224,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
}
public boolean isEmpty() {
init();
initAsUntouched();
return map.isEmpty();
}
@@ -40,6 +40,10 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
super(loader, ownerBean, propertyName);
}
public boolean isEmptyAndUntouched() {
return !touched && (set == null || set.isEmpty());
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
set.add((E) bean);
@@ -86,16 +90,24 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
set = new LinkedHashSet<E>();
}
}
touched();
touched(true);
}
}
private void initWithoutTouchedFlag() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setFlag) {
synchronized (this) {
if (set == null) {
lazyLoadCollection(true);
}
touched();
touched(setFlag);
}
}
@@ -220,7 +232,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
public boolean isEmpty() {
init();
initWithoutTouchedFlag();
return set.isEmpty();
}
@@ -158,6 +158,18 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
help.add(bc, detailBean);
}
public boolean isEmptyBeanCollection(EntityBean bean) {
Object val = getValue(bean);
if (val == null) {
return true;
}
if (val instanceof BeanCollection<?>) {
// if empty and not been cleared or elements removed
return ((BeanCollection<?>)val).isEmptyAndUntouched();
}
return false;
}
@Override
public Object getValue(EntityBean bean) {
return super.getValue(bean);
@@ -565,7 +565,10 @@ public final class DefaultPersister implements Persister {
// many's with cascade save
BeanPropertyAssocMany<?>[] manys = desc.propertiesManySave();
for (int i = 0; i < manys.length; i++) {
saveMany(new SaveManyPropRequest(insertedParent, manys[i], parentBean, request));
// check that property is loaded and not empty uninitialised collection
if (request.isLoadedProperty(manys[i]) && !manys[i].isEmptyBeanCollection(parentBean)) {
saveMany(new SaveManyPropRequest(insertedParent, manys[i], parentBean, request));
}
}
}
@@ -605,7 +608,7 @@ public final class DefaultPersister implements Persister {
public boolean isSaveIntersection() {
return t.isSaveAssocManyIntersection(many.getIntersectionTableJoin().getTable(), many.getBeanDescriptor().getName());
}
private Object getValue() {
return many.getValue(parentBean);
}