Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #54 from ohshazbot/Issue53
Adds support for Guava's Sets.UnmodifiableNavigableSet
- Loading branch information
Showing
3 changed files
with
282 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
src/main/java/de/javakaffee/kryoserializers/guava/UnmodifiableNavigableSetSerializer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package de.javakaffee.kryoserializers.guava; | ||
|
||
import com.esotericsoftware.kryo.Kryo; | ||
import com.esotericsoftware.kryo.Serializer; | ||
import com.esotericsoftware.kryo.io.Input; | ||
import com.esotericsoftware.kryo.io.Output; | ||
import com.google.common.annotations.VisibleForTesting; | ||
import com.google.common.collect.ImmutableSortedSet; | ||
import com.google.common.collect.Sets; | ||
|
||
import java.lang.reflect.Field; | ||
import java.util.NavigableSet; | ||
import java.util.TreeSet; | ||
|
||
/** | ||
* A kryo {@link Serializer} for guava-libraries {@link ImmutableSortedSet}. | ||
*/ | ||
public class UnmodifiableNavigableSetSerializer extends Serializer<NavigableSet<?>> { | ||
|
||
Field delegate; | ||
|
||
public UnmodifiableNavigableSetSerializer() { | ||
// Do not allow nulls | ||
super(false); | ||
try { | ||
Class<?> clazz = Class.forName(Sets.class.getCanonicalName() + "$UnmodifiableNavigableSet"); | ||
delegate = clazz.getDeclaredField("delegate"); | ||
delegate.setAccessible(true); | ||
} catch (IllegalArgumentException e) { | ||
throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e); | ||
} catch (ClassNotFoundException e) { | ||
throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e); | ||
} catch (SecurityException e) { | ||
throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e); | ||
} catch (NoSuchFieldException e) { | ||
throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e); | ||
} | ||
} | ||
|
||
@VisibleForTesting | ||
protected Object getDelegateFromUnmodifiableNavigableSet(NavigableSet<?> object) { | ||
try { | ||
return delegate.get(object); | ||
} catch (IllegalArgumentException e) { | ||
throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e); | ||
} catch (IllegalAccessException e) { | ||
throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e); | ||
} | ||
} | ||
|
||
@Override | ||
public void write(Kryo kryo, Output output, NavigableSet<?> object) { | ||
// We want to preserve the underlying delegate class, so we need to reflectively get it and write it directly via kryo | ||
kryo.writeClassAndObject(output, getDelegateFromUnmodifiableNavigableSet(object)); | ||
} | ||
|
||
@Override | ||
public NavigableSet<?> read(Kryo kryo, Input input, Class<NavigableSet<?>> type) { | ||
return Sets.unmodifiableNavigableSet((NavigableSet<?>) kryo.readClassAndObject(input)); | ||
} | ||
|
||
@Override | ||
public NavigableSet<?> copy(Kryo kryo, NavigableSet<?> original) { | ||
return Sets.unmodifiableNavigableSet((NavigableSet<?>) kryo.copy(getDelegateFromUnmodifiableNavigableSet(original))); | ||
} | ||
|
||
/** | ||
* Creates a new {@link UnmodifiableNavigableSetSerializer} and registers its serializer | ||
* for the UnmodifiableNavigableSetSerializer related class. | ||
* | ||
* @param kryo the {@link Kryo} instance to set the serializer on | ||
*/ | ||
public static void registerSerializers(final Kryo kryo) { | ||
|
||
// UnmodifiableNavigableSetSerializer (private class) | ||
|
||
final UnmodifiableNavigableSetSerializer serializer = new UnmodifiableNavigableSetSerializer(); | ||
|
||
kryo.register(Sets.unmodifiableNavigableSet(new TreeSet<Object>()).getClass(), serializer); | ||
} | ||
} |
198 changes: 198 additions & 0 deletions
198
...test/java/de/javakaffee/kryoserializers/guava/UnmodifiableNavigableSetSerializerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
package de.javakaffee.kryoserializers.guava; | ||
|
||
import static de.javakaffee.kryoserializers.KryoTest.deserialize; | ||
import static de.javakaffee.kryoserializers.KryoTest.serialize; | ||
import static org.testng.Assert.assertEquals; | ||
import static org.testng.Assert.assertTrue; | ||
import static org.testng.Assert.assertFalse; | ||
import static org.testng.Assert.fail; | ||
|
||
import java.util.NavigableSet; | ||
import java.util.TreeSet; | ||
import java.util.concurrent.ConcurrentSkipListSet; | ||
|
||
import com.esotericsoftware.kryo.Kryo; | ||
import com.google.common.collect.Sets; | ||
|
||
import org.testng.annotations.BeforeTest; | ||
import org.testng.annotations.Test; | ||
|
||
/** | ||
* Test for {@link ImmutableSortedSetSerializer}. | ||
*/ | ||
@SuppressWarnings({"rawtypes", "unchecked"}) | ||
public class UnmodifiableNavigableSetSerializerTest { | ||
|
||
private Kryo _kryo; | ||
|
||
@BeforeTest | ||
public void setUp() { | ||
_kryo = new Kryo(); | ||
|
||
UnmodifiableNavigableSetSerializer.registerSerializers(_kryo); | ||
} | ||
|
||
Class<NavigableSet> unmodifiableClass; | ||
{ | ||
unmodifiableClass = (Class<NavigableSet>) Sets.unmodifiableNavigableSet(new TreeSet()).getClass(); | ||
} | ||
|
||
UnmodifiableNavigableSetSerializer forUnwrapping = new UnmodifiableNavigableSetSerializer(); | ||
|
||
private void assertUnderlyingSet(NavigableSet<String> deserialized, Class<?> class1) { | ||
assertEquals( | ||
forUnwrapping.getDelegateFromUnmodifiableNavigableSet(deserialized).getClass(), | ||
class1, | ||
"Expected underlying class to match"); | ||
} | ||
|
||
@Test | ||
public void testEmptyTreeSet() { | ||
final TreeSet<String> coreSet = Sets.newTreeSet(); | ||
final NavigableSet<String> obj = Sets.unmodifiableNavigableSet(coreSet); | ||
final byte[] serialized = serialize(_kryo, obj); | ||
final NavigableSet<String> deserialized = deserialize(_kryo, serialized, unmodifiableClass); | ||
assertTrue(deserialized.isEmpty()); | ||
assertEquals(deserialized.size(), obj.size()); | ||
// And ensure what we get is truly unmodifiable | ||
try { | ||
deserialized.add("a"); | ||
fail("Should have been unable to add a field to an unmodifiable collection post deserialization"); | ||
} catch (UnsupportedOperationException expected) {} | ||
assertUnderlyingSet(deserialized, coreSet.getClass()); | ||
} | ||
|
||
@Test | ||
public void testEmptySkipList() { | ||
final ConcurrentSkipListSet<String> coreSet = new ConcurrentSkipListSet(); | ||
final NavigableSet<String> obj = Sets.unmodifiableNavigableSet(coreSet); | ||
final byte[] serialized = serialize(_kryo, obj); | ||
final NavigableSet<String> deserialized = deserialize(_kryo, serialized, unmodifiableClass); | ||
assertTrue(deserialized.isEmpty()); | ||
assertEquals(deserialized.size(), obj.size()); | ||
// And ensure what we get is truly unmodifiable | ||
try { | ||
deserialized.add("a"); | ||
fail("Should have been unable to add a field to an unmodifiable collection post deserialization"); | ||
} catch (UnsupportedOperationException expected) {} | ||
assertUnderlyingSet(deserialized, coreSet.getClass()); | ||
} | ||
|
||
@Test | ||
public void testPopulatedTreeSet() { | ||
final TreeSet<String> coreSet = Sets.newTreeSet(); | ||
coreSet.add("k"); | ||
coreSet.add("r"); | ||
coreSet.add("y"); | ||
coreSet.add("o"); | ||
final NavigableSet<String> obj = Sets.unmodifiableNavigableSet(coreSet); | ||
final byte[] serialized = serialize(_kryo, obj); | ||
final NavigableSet<String> deserialized = deserialize(_kryo, serialized, unmodifiableClass); | ||
assertFalse(deserialized.isEmpty()); | ||
assertEquals(deserialized.size(), obj.size()); | ||
assertEquals(deserialized, obj); | ||
// And ensure what we get is truly unmodifiable | ||
try { | ||
deserialized.add("a"); | ||
fail("Should have been unable to add a field to an unmodifiable collection post deserialization"); | ||
} catch (UnsupportedOperationException expected) {} | ||
assertUnderlyingSet(deserialized, coreSet.getClass()); | ||
} | ||
|
||
@Test | ||
public void testPopulatedSkipList() { | ||
final ConcurrentSkipListSet<String> coreSet = new ConcurrentSkipListSet(); | ||
coreSet.add("k"); | ||
coreSet.add("r"); | ||
coreSet.add("y"); | ||
coreSet.add("o"); | ||
final NavigableSet<String> obj = Sets.unmodifiableNavigableSet(coreSet); | ||
final byte[] serialized = serialize(_kryo, obj); | ||
final NavigableSet<String> deserialized = deserialize(_kryo, serialized, unmodifiableClass); | ||
assertFalse(deserialized.isEmpty()); | ||
assertEquals(deserialized.size(), obj.size()); | ||
assertEquals(deserialized, obj); | ||
// And ensure what we get is truly unmodifiable | ||
try { | ||
deserialized.add("a"); | ||
fail("Should have been unable to add a field to an unmodifiable collection post deserialization"); | ||
} catch (UnsupportedOperationException expected) {} | ||
assertUnderlyingSet(deserialized, coreSet.getClass()); | ||
} | ||
|
||
// Kryo#copy tests | ||
|
||
@Test | ||
public void testCopyEmptyTreeSet() { | ||
final TreeSet<String> coreSet = Sets.newTreeSet(); | ||
final NavigableSet<String> obj = Sets.unmodifiableNavigableSet(coreSet); | ||
final NavigableSet<String> copied = _kryo.copy(obj); | ||
assertTrue(copied.isEmpty()); | ||
assertEquals(copied.size(), obj.size()); | ||
|
||
// And ensure what we get is truly unmodifiable | ||
try { | ||
copied.add("a"); | ||
fail("Should have been unable to add a field to an unmodifiable collection post deserialization"); | ||
} catch (UnsupportedOperationException expected) {} | ||
assertUnderlyingSet(copied, coreSet.getClass()); | ||
} | ||
|
||
@Test | ||
public void testCopyEmptySkipList() { | ||
final ConcurrentSkipListSet<String> coreSet = new ConcurrentSkipListSet(); | ||
final NavigableSet<String> obj = Sets.unmodifiableNavigableSet(coreSet); | ||
final NavigableSet<String> copied = _kryo.copy(obj); | ||
assertTrue(copied.isEmpty()); | ||
assertEquals(copied.size(), obj.size()); | ||
|
||
// And ensure what we get is truly unmodifiable | ||
try { | ||
copied.add("a"); | ||
fail("Should have been unable to add a field to an unmodifiable collection post deserialization"); | ||
} catch (UnsupportedOperationException expected) {} | ||
assertUnderlyingSet(copied, coreSet.getClass()); | ||
} | ||
|
||
@Test | ||
public void testCopyPopulatedTreeSet() { | ||
final TreeSet<String> coreSet = Sets.newTreeSet(); | ||
coreSet.add("k"); | ||
coreSet.add("r"); | ||
coreSet.add("y"); | ||
coreSet.add("o"); | ||
final NavigableSet<String> obj = Sets.unmodifiableNavigableSet(coreSet); | ||
final NavigableSet<String> copied = _kryo.copy(obj); | ||
assertFalse(copied.isEmpty()); | ||
assertEquals(copied.size(), obj.size()); | ||
assertEquals(copied, obj); | ||
|
||
// And ensure what we get is truly unmodifiable | ||
try { | ||
copied.add("a"); | ||
fail("Should have been unable to add a field to an unmodifiable collection post deserialization"); | ||
} catch (UnsupportedOperationException expected) {} | ||
assertUnderlyingSet(copied, coreSet.getClass()); | ||
} | ||
|
||
@Test | ||
public void testCopyPopulatedSkipList() { | ||
final ConcurrentSkipListSet<String> coreSet = new ConcurrentSkipListSet(); | ||
coreSet.add("k"); | ||
coreSet.add("r"); | ||
coreSet.add("y"); | ||
coreSet.add("o"); | ||
final NavigableSet<String> obj = Sets.unmodifiableNavigableSet(coreSet); | ||
final NavigableSet<String> copied = _kryo.copy(obj); | ||
assertFalse(copied.isEmpty()); | ||
assertEquals(copied.size(), obj.size()); | ||
assertEquals(copied, obj); | ||
|
||
// And ensure what we get is truly unmodifiable | ||
try { | ||
copied.add("a"); | ||
fail("Should have been unable to add a field to an unmodifiable collection post deserialization"); | ||
} catch (UnsupportedOperationException expected) {} | ||
assertUnderlyingSet(copied, coreSet.getClass()); | ||
} | ||
} |