Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/com/esotericsoftware/kryo/serializers/DefaultSerializers.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -852,6 +853,27 @@ private PriorityQueue createPriorityQueue (Class<? extends Collection> type, int
}
}

/** Serializer for {@link ConcurrentHashMap.KeySetView}.
* @author Andreas Bergander */
public static class KeySetViewSerializer extends CollectionSerializer<ConcurrentHashMap.KeySetView> {
protected void writeHeader (Kryo kryo, Output output, ConcurrentHashMap.KeySetView set) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that this is not ideal. We are writing the keys twice. Once here as part of the map in the header and then again in the main write method of the CollectionSerializer. It would be enough to write the map because the keyset is only a view. Can you try to implement this without extending CollectionSerializer and implement Serializer directly? This should make the serialized payload significantly smaller.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

writeHeader would simply become write and create would become read.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing me in the right direction! PR is updated according to your comments.

kryo.writeClassAndObject(output, set.getMap());
kryo.writeClassAndObject(output, set.getMappedValue());
}

protected ConcurrentHashMap.KeySetView create (Kryo kryo, Input input, Class<? extends ConcurrentHashMap.KeySetView> type, int size) {
return createKeySetView((ConcurrentHashMap)kryo.readClassAndObject(input), kryo.readClassAndObject(input));
}

protected ConcurrentHashMap.KeySetView createCopy (Kryo kryo, ConcurrentHashMap.KeySetView original) {
return createKeySetView(original.getMap(), original.getMappedValue());
}

private ConcurrentHashMap.KeySetView createKeySetView (ConcurrentHashMap map, Object mappedValue) {
return map.keySet(mappedValue);
}
}

/** Serializer for {@link Locale} (immutables).
* @author Tumi <[email protected]> */
public static class LocaleSerializer extends ImmutableSerializer<Locale> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -452,6 +454,53 @@ void testEmptyPriorityQueueSubclass () {
roundTrip(3, queue);
}

@Test
void testConcurrentHashMapKeySetView () {
ConcurrentHashMap.KeySetView<Integer, Boolean> set = ConcurrentHashMap.newKeySet();
set.add(12);
kryo.register(ConcurrentHashMap.KeySetView.class, new KeySetViewSerializer());
kryo.register(ConcurrentHashMap.class);
roundTrip(13, set);
}

@Test
void testConcurrentHashMapKeySetViewFromExistingMap () {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

map.put("1", 1);
map.put("2", 2);

ConcurrentHashMap.KeySetView<String, Integer> set = map.keySet(4);

kryo.register(ConcurrentHashMap.KeySetView.class, new KeySetViewSerializer());
kryo.register(ConcurrentHashMap.class);
roundTrip(22, set);
}

@Test
void testEmptyConcurrentHashMapKeySetView () {
ConcurrentHashMap.KeySetView set = ConcurrentHashMap.newKeySet();
kryo.register(ConcurrentHashMap.KeySetView.class, new KeySetViewSerializer());
kryo.register(ConcurrentHashMap.class);
roundTrip(6, set);
}

@Test
void testConcurrentHashMapKeySetViewCopy () {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

map.put("1", 1);
map.put("2", 2);

ConcurrentHashMap.KeySetView<String, Integer> set = map.keySet(4);

kryo.register(ConcurrentHashMap.KeySetView.class, new KeySetViewSerializer());
kryo.register(ConcurrentHashMap.class);
ConcurrentHashMap.KeySetView<String, Integer> copy = kryo.copy(set);
assertEquals(set.iterator().next(), copy.iterator().next());
assertEquals(set.getMappedValue(), copy.getMappedValue());
}

@Test
void testCalendar () {
kryo.setRegistrationRequired(false);
Expand Down Expand Up @@ -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"));
}

Expand Down