#939 - Make ModifyAwareSet serializable ... (for serializable entity beans with @DbJson etc)

This commit is contained in:
Rob Bygrave
2017-01-09 19:39:54 +13:00
parent 8467934021
commit 335cef870f
10 changed files with 245 additions and 130 deletions
@@ -1,118 +0,0 @@
package io.ebeaninternal.server.type;
import java.util.Collection;
import java.util.Iterator;
/**
* Wraps a collection for the purposes of detecting modifications.
*/
public class ModifyAwareCollection<E> implements Collection<E> {
protected final ModifyAwareOwner owner;
protected final Collection<E> c;
/**
* Create with an Owner and the underlying collection this wraps.
* <p>
* The owner is notified of the additions and removals.
* </p>
*/
public ModifyAwareCollection(ModifyAwareOwner owner, Collection<E> c) {
this.owner = owner;
this.c = c;
}
public String toString() {
return c.toString();
}
public boolean add(E o) {
if (c.add(o)) {
owner.markAsModified();
return true;
}
return false;
}
public boolean addAll(Collection<? extends E> collection) {
boolean changed = false;
for (E o : collection) {
if (c.add(o)) {
owner.markAsModified();
changed = true;
}
}
return changed;
}
public void clear() {
if (!c.isEmpty()) {
owner.markAsModified();
}
c.clear();
}
public boolean contains(Object o) {
return c.contains(o);
}
public boolean containsAll(Collection<?> collection) {
return c.containsAll(collection);
}
public boolean isEmpty() {
return c.isEmpty();
}
public Iterator<E> iterator() {
return new ModifyAwareIterator<>(owner, c.iterator());
}
public boolean remove(Object o) {
if (c.remove(o)) {
owner.markAsModified();
return true;
}
return false;
}
public boolean removeAll(Collection<?> collection) {
boolean changed = false;
for (Object element : collection) {
if (c.remove(element)) {
owner.markAsModified();
changed = true;
}
}
return changed;
}
public boolean retainAll(Collection<?> collection) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = it.next();
if (!collection.contains(o)) {
it.remove();
owner.markAsModified();
changed = true;
}
}
return changed;
}
public int size() {
return c.size();
}
public Object[] toArray() {
return c.toArray();
}
public <T> T[] toArray(T[] a) {
//noinspection SuspiciousToArrayCall
return c.toArray(a);
}
}
@@ -5,6 +5,8 @@ package io.ebeaninternal.server.type;
*/
public class ModifyAwareFlag implements ModifyAwareOwner {
private static final long serialVersionUID = 1;
boolean dirty;
@Override
@@ -11,6 +11,8 @@ import java.util.ListIterator;
*/
public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
private static final long serialVersionUID = 1;
final List<E> list;
final ModifyAwareOwner owner;
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.type;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -9,6 +10,8 @@ import java.util.Set;
*/
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
private static final long serialVersionUID = 1;
final ModifyAwareOwner owner;
/**
@@ -107,7 +110,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
@Override
public Collection<V> values() {
return new ModifyAwareCollection<>(this, map.values());
return new ModifyAwareSet<>(this, new LinkedHashSet<>(map.values()));
}
@Override
@@ -1,9 +1,11 @@
package io.ebeaninternal.server.type;
import java.io.Serializable;
/**
* Owner object notified when a modification is detected.
*/
public interface ModifyAwareOwner {
public interface ModifyAwareOwner extends Serializable {
/**
* Return true if the value is considered dirty.
@@ -1,24 +1,33 @@
package io.ebeaninternal.server.type;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
/**
* Wraps a Set for the purposes of detecting modifications.
*/
public class ModifyAwareSet<E> extends ModifyAwareCollection<E> implements Set<E>, ModifyAwareOwner {
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
/**
* Create with an Owner that is notified of modifications.
*/
public ModifyAwareSet(ModifyAwareOwner owner, Set<E> s) {
super(owner, s);
}
private static final long serialVersionUID = 1;
protected final ModifyAwareOwner owner;
protected final Set<E> set;
/**
* Create as top level with it's own ModifyAwareOwner instance wrapping the given Set.
*/
public ModifyAwareSet(Set<E> s) {
super(new ModifyAwareFlag(), s);
public ModifyAwareSet(Set<E> underlying) {
this(new ModifyAwareFlag(), underlying);
}
/**
* Create with an Owner that is notified of modifications.
*/
public ModifyAwareSet(ModifyAwareOwner owner, Set<E> underlying) {
this.owner = owner;
this.set = underlying;
}
@Override
@@ -35,4 +44,96 @@ public class ModifyAwareSet<E> extends ModifyAwareCollection<E> implements Set<E
public void resetMarkedDirty() {
owner.resetMarkedDirty();
}
public String toString() {
return set.toString();
}
public boolean add(E o) {
if (set.add(o)) {
owner.markAsModified();
return true;
}
return false;
}
public boolean addAll(Collection<? extends E> collection) {
boolean changed = false;
for (E o : collection) {
if (set.add(o)) {
owner.markAsModified();
changed = true;
}
}
return changed;
}
public void clear() {
if (!set.isEmpty()) {
owner.markAsModified();
}
set.clear();
}
public boolean contains(Object o) {
return set.contains(o);
}
public boolean containsAll(Collection<?> collection) {
return set.containsAll(collection);
}
public boolean isEmpty() {
return set.isEmpty();
}
public Iterator<E> iterator() {
return new ModifyAwareIterator<>(owner, set.iterator());
}
public boolean remove(Object o) {
if (set.remove(o)) {
owner.markAsModified();
return true;
}
return false;
}
public boolean removeAll(Collection<?> collection) {
boolean changed = false;
for (Object element : collection) {
if (set.remove(element)) {
owner.markAsModified();
changed = true;
}
}
return changed;
}
public boolean retainAll(Collection<?> collection) {
boolean changed = false;
Iterator<?> it = set.iterator();
while (it.hasNext()) {
Object o = it.next();
if (!collection.contains(o)) {
it.remove();
owner.markAsModified();
changed = true;
}
}
return changed;
}
public int size() {
return set.size();
}
public Object[] toArray() {
return set.toArray();
}
public <T> T[] toArray(T[] a) {
return set.toArray(a);
}
}
@@ -0,0 +1,33 @@
package io.ebeaninternal.server.type;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import static org.assertj.core.api.Assertions.assertThat;
public class ModifyAwareFlagTest {
@Test
public void serialise() throws IOException, ClassNotFoundException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ModifyAwareFlag flag = new ModifyAwareFlag();
flag.markAsModified();
oos.writeObject(flag);
oos.flush();
oos.close();
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
ObjectInputStream ois = new ObjectInputStream(is);
ModifyAwareFlag read = (ModifyAwareFlag)ois.readObject();
assertThat(read.isMarkedDirty()).isTrue();
}
}
@@ -2,13 +2,21 @@ package io.ebeaninternal.server.type;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import static org.junit.Assert.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class ModifyAwareListTest {
@@ -242,4 +250,22 @@ public class ModifyAwareListTest {
assertTrue(set.isMarkedDirty());
}
@Test
public void serialise() throws IOException, ClassNotFoundException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ModifyAwareList<String> orig = createList();
oos.writeObject(orig);
oos.flush();
oos.close();
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
ObjectInputStream ois = new ObjectInputStream(is);
ModifyAwareList<String> read = (ModifyAwareList<String>)ois.readObject();
assertThat(read).contains("A", "B", "C", "D", "E");
}
}
@@ -2,12 +2,19 @@ package io.ebeaninternal.server.type;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
public class ModifyAwareMapTest {
@@ -181,4 +188,22 @@ public class ModifyAwareMapTest {
assertEquals(map.size(), entries.size());
assertFalse(map.isMarkedDirty());
}
@Test
public void serialise() throws IOException, ClassNotFoundException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ModifyAwareMap<String, String> orig = createMap();
oos.writeObject(orig);
oos.flush();
oos.close();
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
ObjectInputStream ois = new ObjectInputStream(is);
ModifyAwareMap<String, String> read = (ModifyAwareMap<String, String>)ois.readObject();
assertThat(read).hasSize(orig.size());
}
}
@@ -0,0 +1,39 @@
package io.ebeaninternal.server.type;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.HashSet;
import static org.assertj.core.api.Assertions.assertThat;
public class ModifyAwareSetTest {
private ModifyAwareSet<String> createSet() {
HashSet<String> set = new HashSet<>();
set.addAll(Arrays.asList("A", "B", "C", "D", "E"));
return new ModifyAwareSet<>(set);
}
@Test
public void serialise() throws IOException, ClassNotFoundException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(createSet());
oos.flush();
oos.close();
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
ObjectInputStream ois = new ObjectInputStream(is);
ModifyAwareSet<String> read = (ModifyAwareSet<String>)ois.readObject();
assertThat(read).contains("A", "B", "C", "D", "E");
}
}