diff --git a/src/com/esotericsoftware/kryo/serializers/DefaultSerializers.java b/src/com/esotericsoftware/kryo/serializers/DefaultSerializers.java index f4e05b3cb..42a29fa48 100644 --- a/src/com/esotericsoftware/kryo/serializers/DefaultSerializers.java +++ b/src/com/esotericsoftware/kryo/serializers/DefaultSerializers.java @@ -62,6 +62,7 @@ import java.util.TreeMap; import java.util.TreeSet; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -852,6 +853,27 @@ private PriorityQueue createPriorityQueue (Class type, int } } + /** Serializer for {@link ConcurrentHashMap.KeySetView}. + * @author Andreas Bergander */ + public static class KeySetViewSerializer extends Serializer { + public void write (Kryo kryo, Output output, ConcurrentHashMap.KeySetView set) { + kryo.writeClassAndObject(output, set.getMap()); + kryo.writeClassAndObject(output, set.getMappedValue()); + } + + public ConcurrentHashMap.KeySetView read (Kryo kryo, Input input, Class type) { + return createKeySetView((ConcurrentHashMap)kryo.readClassAndObject(input), kryo.readClassAndObject(input)); + } + + public ConcurrentHashMap.KeySetView copy (Kryo kryo, ConcurrentHashMap.KeySetView original) { + return createKeySetView(kryo.copy(original.getMap()), kryo.copy(original.getMappedValue())); + } + + private ConcurrentHashMap.KeySetView createKeySetView (ConcurrentHashMap map, Object mappedValue) { + return map.keySet(mappedValue); + } + } + /** Serializer for {@link Locale} (immutables). * @author Tumi */ public static class LocaleSerializer extends ImmutableSerializer { diff --git a/test/com/esotericsoftware/kryo/serializers/DefaultSerializersTest.java b/test/com/esotericsoftware/kryo/serializers/DefaultSerializersTest.java index 28244afd7..29da65468 100644 --- a/test/com/esotericsoftware/kryo/serializers/DefaultSerializersTest.java +++ b/test/com/esotericsoftware/kryo/serializers/DefaultSerializersTest.java @@ -26,6 +26,7 @@ import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import com.esotericsoftware.kryo.util.DefaultInstantiatorStrategy; +import com.esotericsoftware.kryo.serializers.DefaultSerializers.KeySetViewSerializer; import java.math.BigDecimal; import java.math.BigInteger; @@ -45,6 +46,7 @@ import java.util.PriorityQueue; import java.util.TimeZone; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -246,7 +248,7 @@ void testTimestampSerializer () { roundTrip(11, newTimestamp(-1234567, 1)); roundTrip(14, newTimestamp(-1234567, 123_456_789)); } - + private java.sql.Timestamp newTimestamp(long time, int nanos) { java.sql.Timestamp t = new java.sql.Timestamp(time); t.setNanos(nanos); @@ -452,6 +454,53 @@ void testEmptyPriorityQueueSubclass () { roundTrip(3, queue); } + @Test + void testConcurrentHashMapKeySetView () { + ConcurrentHashMap.KeySetView set = ConcurrentHashMap.newKeySet(); + set.add(12); + kryo.register(ConcurrentHashMap.KeySetView.class, new KeySetViewSerializer()); + kryo.register(ConcurrentHashMap.class); + roundTrip(9, set); + } + + @Test + void testConcurrentHashMapKeySetViewFromExistingMap () { + ConcurrentHashMap map = new ConcurrentHashMap<>(); + + map.put("1", 1); + map.put("2", 2); + + ConcurrentHashMap.KeySetView set = map.keySet(4); + + kryo.register(ConcurrentHashMap.KeySetView.class, new KeySetViewSerializer()); + kryo.register(ConcurrentHashMap.class); + roundTrip(15, set); + } + + @Test + void testEmptyConcurrentHashMapKeySetView () { + ConcurrentHashMap.KeySetView set = ConcurrentHashMap.newKeySet(); + kryo.register(ConcurrentHashMap.KeySetView.class, new KeySetViewSerializer()); + kryo.register(ConcurrentHashMap.class); + roundTrip(5, set); + } + + @Test + void testConcurrentHashMapKeySetViewCopy () { + ConcurrentHashMap map = new ConcurrentHashMap<>(); + + map.put("1", 1); + map.put("2", 2); + + ConcurrentHashMap.KeySetView set = map.keySet(4); + + kryo.register(ConcurrentHashMap.KeySetView.class, new KeySetViewSerializer()); + kryo.register(ConcurrentHashMap.class); + ConcurrentHashMap.KeySetView copy = kryo.copy(set); + assertEquals(set.iterator().next(), copy.iterator().next()); + assertEquals(set.getMappedValue(), copy.getMappedValue()); + } + @Test void testCalendar () { kryo.setRegistrationRequired(false); @@ -589,7 +638,7 @@ void testURISerializer () throws Exception { @Test void testUUIDSerializer () { kryo.register(UUID.class, new DefaultSerializers.UUIDSerializer()); - + roundTrip(17, UUID.fromString("e58ed763-928c-4155-bee9-fdbaaadc15f3")); }