Skip to content

Commit

Permalink
Add additional safe serializers for commonly used JDK classes (#930)
Browse files Browse the repository at this point in the history
Adds serializers for the following classes:

- java.net.URI
- java.util.UUID
- java.util.regex.Pattern
- java.util.concurrent.atomic.AtomicBoolean
- java.util.concurrent.atomic.AtomicInteger
- java.util.concurrent.atomic.AtomicLong
- java.util.concurrent.atomic.AtomicReference
  • Loading branch information
theigl authored Dec 16, 2022
1 parent 9947cdb commit b6fd8f9
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 5 deletions.
114 changes: 112 additions & 2 deletions src/com/esotericsoftware/kryo/serializers/DefaultSerializers.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.sql.Time;
Expand All @@ -58,7 +60,13 @@
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;

/** Contains many serializer classes that are provided by {@link Kryo#addDefaultSerializer(Class, Class) default}.
* @author Nathan Sweet */
Expand Down Expand Up @@ -900,6 +908,7 @@ public List copy (Kryo kryo, List original) {
}
}

/** Serializer for {@link BitSet} */
public static class BitSetSerializer extends Serializer<BitSet> {
public void write (Kryo kryo, Output output, BitSet set) {
long[] values = set.toLongArray();
Expand All @@ -910,12 +919,113 @@ public void write (Kryo kryo, Output output, BitSet set) {
public BitSet read (Kryo kryo, Input input, Class type) {
int length = input.readVarInt(true);
long[] values = input.readLongs(length);
BitSet set = BitSet.valueOf(values);
return set;
return BitSet.valueOf(values);
}

public BitSet copy (Kryo kryo, BitSet original) {
return BitSet.valueOf(original.toLongArray());
}
}

/** Serializer for {@link Pattern} */
public static class PatternSerializer extends ImmutableSerializer<Pattern> {
public void write (final Kryo kryo, final Output output, final Pattern pattern) {
output.writeString(pattern.pattern());
output.writeInt(pattern.flags(), true);
}

public Pattern read (final Kryo kryo, final Input input, final Class<? extends Pattern> patternClass) {
String regex = input.readString();
int flags = input.readInt(true);
return Pattern.compile(regex, flags);
}
}

/** Serializer for {@link URI} */
public static class URISerializer extends ImmutableSerializer<java.net.URI> {
public void write (Kryo kryo, Output output, URI uri) {
output.writeString(uri.toString());
}

public URI read (Kryo kryo, Input input, Class<? extends URI> uriClass) {
try {
return new URI(input.readString());
} catch (URISyntaxException ex) {
throw new KryoException(ex);
}
}
}

/** Serializer for {@link UUID} */
public static class UUIDSerializer extends ImmutableSerializer<UUID> {
public void write (Kryo kryo, Output output, UUID uuid) {
output.writeLong(uuid.getMostSignificantBits());
output.writeLong(uuid.getLeastSignificantBits());
}

public UUID read (final Kryo kryo, final Input input, final Class<? extends UUID> uuidClass) {
return new UUID(input.readLong(), input.readLong());
}
}

/** Serializer for {@link AtomicBoolean} */
public static class AtomicBooleanSerializer extends Serializer<AtomicBoolean> {
public void write (Kryo kryo, Output output, AtomicBoolean object) {
output.writeBoolean(object.get());
}

public AtomicBoolean read (Kryo kryo, Input input, Class<? extends AtomicBoolean> type) {
return new AtomicBoolean(input.readBoolean());
}

public AtomicBoolean copy (Kryo kryo, AtomicBoolean original) {
return new AtomicBoolean(original.get());
}
}

/** Serializer for {@link AtomicInteger} */
public static class AtomicIntegerSerializer extends Serializer<AtomicInteger> {
public void write (Kryo kryo, Output output, AtomicInteger object) {
output.writeInt(object.get());
}

public AtomicInteger read (Kryo kryo, Input input, Class<? extends AtomicInteger> type) {
return new AtomicInteger(input.readInt());
}

public AtomicInteger copy (Kryo kryo, AtomicInteger original) {
return new AtomicInteger(original.get());
}
}

/** Serializer for {@link AtomicLong} */
public static class AtomicLongSerializer extends Serializer<AtomicLong> {
public void write (Kryo kryo, Output output, AtomicLong object) {
output.writeLong(object.get());
}

public AtomicLong read (Kryo kryo, Input input, Class<? extends AtomicLong> type) {
return new AtomicLong(input.readLong());
}

public AtomicLong copy (Kryo kryo, AtomicLong original) {
return new AtomicLong(original.get());
}
}

/** Serializer for {@link AtomicReference} */
public static class AtomicReferenceSerializer extends Serializer<AtomicReference> {
public void write (Kryo kryo, Output output, AtomicReference object) {
kryo.writeClassAndObject(output, object.get());
}

public AtomicReference read (Kryo kryo, Input input, Class<? extends AtomicReference> type) {
final Object value = kryo.readClassAndObject(input);
return new AtomicReference(value);
}

public AtomicReference copy (Kryo kryo, AtomicReference original) {
return new AtomicReference<>(kryo.copy(original.get()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
Expand All @@ -43,6 +44,12 @@
import java.util.Locale;
import java.util.PriorityQueue;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;

import org.junit.jupiter.api.Test;
import org.objenesis.strategy.StdInstantiatorStrategy;
Expand Down Expand Up @@ -518,19 +525,90 @@ void testArraysAsListDeepCopy () throws Exception {

@Test
void testURLSerializer () throws Exception {
kryo.setInstantiatorStrategy(new DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
kryo.register(URL.class);

roundTrip(42, new URL("https://github.com/EsotericSoftware/kryo"));
roundTrip(78, new URL("https://github.com:443/EsotericSoftware/kryo/pulls?utf8=%E2%9C%93&q=is%3Apr"));
}

@Test
void testURISerializer () throws Exception {
kryo.register(URI.class, new DefaultSerializers.URISerializer());

roundTrip(42, new URI("https://github.com/EsotericSoftware/kryo"));
roundTrip(78, new URI("https://github.com:443/EsotericSoftware/kryo/pulls?utf8=%E2%9C%93&q=is%3Apr"));
}

@Test
void testUUIDSerializer () {
kryo.register(UUID.class, new DefaultSerializers.UUIDSerializer());

roundTrip(17, UUID.fromString("e58ed763-928c-4155-bee9-fdbaaadc15f3"));
}

@Test
void testPatternSerializer () {
kryo.register(Pattern.class, new DefaultSerializers.PatternSerializer());

roundTrip(4, Pattern.compile(".", Pattern.DOTALL));
roundTrip(4, Pattern.compile("."));
}

@Test
void testAtomicBooleanSerializer () {
kryo.register(AtomicBoolean.class, new DefaultSerializers.AtomicBooleanSerializer());

roundTrip(2, new AtomicBoolean(true));
roundTrip(2, new AtomicBoolean(false));
}

@Test
void testAtomicIntegerSerializer () {
kryo.register(AtomicInteger.class, new DefaultSerializers.AtomicIntegerSerializer());

roundTrip(5, new AtomicInteger());
roundTrip(5, new AtomicInteger(0));
roundTrip(5, new AtomicInteger(1));
roundTrip(5, new AtomicInteger(-1));
}

@Test
void testAtomicLongSerializer () {
kryo.register(AtomicLong.class, new DefaultSerializers.AtomicLongSerializer());

roundTrip(9, new AtomicLong());
roundTrip(9, new AtomicLong(0));
roundTrip(9, new AtomicLong(1));
roundTrip(9, new AtomicLong(-1));
}

@Test
void testAtomicReferenceSerializer () {
kryo.register(AtomicReference.class, new DefaultSerializers.AtomicReferenceSerializer());

roundTrip(2, new AtomicReference<>());
roundTrip(3, new AtomicReference<>(1L));
}

protected void doAssertEquals(Object object1, Object object2) {
if (object1 instanceof PriorityQueue && object2 instanceof PriorityQueue) {
final PriorityQueue q1 = (PriorityQueue) object1;
final PriorityQueue q2 = (PriorityQueue) object2;
super.doAssertEquals(q1.peek(), q2.peek());
super.doAssertEquals(q1.toArray(), q2.toArray());
super.doAssertEquals(q1.peek(), q2.peek());
super.doAssertEquals(q1.toArray(), q2.toArray());
} else if (object1 instanceof Pattern && object2 instanceof Pattern) {
final Pattern q1 = (Pattern)object1;
final Pattern q2 = (Pattern)object2;
super.doAssertEquals(q1.pattern(), q2.pattern());
super.doAssertEquals(q1.flags(), q2.flags());
} else if (object1 instanceof AtomicBoolean && object2 instanceof AtomicBoolean) {
super.doAssertEquals(((AtomicBoolean)object1).get(), ((AtomicBoolean)object2).get());
} else if (object1 instanceof AtomicInteger && object2 instanceof AtomicInteger) {
super.doAssertEquals(((AtomicInteger)object1).get(), ((AtomicInteger)object2).get());
} else if (object1 instanceof AtomicLong && object2 instanceof AtomicLong) {
super.doAssertEquals(((AtomicLong)object1).get(), ((AtomicLong)object2).get());
} else if (object1 instanceof AtomicReference && object2 instanceof AtomicReference) {
super.doAssertEquals(((AtomicReference)object1).get(), ((AtomicReference)object2).get());
} else {
super.doAssertEquals(object1, object2);
}
Expand Down

0 comments on commit b6fd8f9

Please sign in to comment.