Skip to content

Commit 6f17e04

Browse files
chermeninjohnynek
authored andcommitted
Serializers for unmodifiable Java collections. (#260)
* Serializers for unmodifiable and empty collections. Added serializers for collections created via Collections.unmodifiable...() and Collections.empty...() methods. * Some refactoring. Serializers of unmodifiable Java collections was refactored. Deleted serializers for empty collections (Kryo has default serializators for it).
1 parent 4462cbd commit 6f17e04

10 files changed

Lines changed: 615 additions & 13 deletions

chill-java/src/main/java/com/twitter/chill/java/PackageRegistrar.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,27 @@
2626
* Creates a registrar for all the serializers in the chill.java package
2727
*/
2828
public class PackageRegistrar {
29-
29+
3030
static public IKryoRegistrar all() {
3131
return new IterableRegistrar(
32-
ArraysAsListSerializer.registrar(),
33-
BitSetSerializer.registrar(),
34-
PriorityQueueSerializer.registrar(),
35-
RegexSerializer.registrar(),
36-
SqlDateSerializer.registrar(),
37-
SqlTimeSerializer.registrar(),
38-
TimestampSerializer.registrar(),
39-
URISerializer.registrar(),
40-
InetSocketAddressSerializer.registrar(),
41-
UUIDSerializer.registrar(),
42-
LocaleSerializer.registrar(),
43-
SimpleDateFormatSerializer.registrar());
32+
ArraysAsListSerializer.registrar(),
33+
BitSetSerializer.registrar(),
34+
PriorityQueueSerializer.registrar(),
35+
RegexSerializer.registrar(),
36+
SqlDateSerializer.registrar(),
37+
SqlTimeSerializer.registrar(),
38+
TimestampSerializer.registrar(),
39+
URISerializer.registrar(),
40+
InetSocketAddressSerializer.registrar(),
41+
UUIDSerializer.registrar(),
42+
LocaleSerializer.registrar(),
43+
SimpleDateFormatSerializer.registrar(),
44+
UnmodifiableCollectionSerializer.registrar(),
45+
UnmodifiableListSerializer.registrar(),
46+
UnmodifiableMapSerializer.registrar(),
47+
UnmodifiableSetSerializer.registrar(),
48+
UnmodifiableSortedMapSerializer.registrar(),
49+
UnmodifiableSortedSetSerializer.registrar()
50+
);
4451
}
4552
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2016 Alex Chermenin
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package com.twitter.chill.java;
19+
20+
import com.esotericsoftware.kryo.Kryo;
21+
import com.esotericsoftware.kryo.Serializer;
22+
import com.esotericsoftware.kryo.io.Input;
23+
import com.esotericsoftware.kryo.io.Output;
24+
import com.twitter.chill.IKryoRegistrar;
25+
import com.twitter.chill.SingleRegistrar;
26+
27+
import java.lang.reflect.Field;
28+
import java.util.*;
29+
30+
/**
31+
* A kryo {@link Serializer} for unmodifiable collections created via {@link Collections#unmodifiableCollection(Collection)}.
32+
* <p>
33+
* Note: This serializer does not support cyclic references, so if one of the objects
34+
* gets set the list as attribute this might cause an error during deserialization.
35+
* </p>
36+
*
37+
* @author <a href="mailto:alex@chermenin.ru">Alex Chermenin</a>
38+
*/
39+
public class UnmodifiableCollectionSerializer extends UnmodifiableJavaCollectionSerializer<Collection<?>> {
40+
41+
@SuppressWarnings("unchecked")
42+
static public IKryoRegistrar registrar() {
43+
return new SingleRegistrar(Collections.unmodifiableCollection(Collections.EMPTY_SET).getClass(),
44+
new UnmodifiableCollectionSerializer());
45+
}
46+
47+
@Override
48+
protected Field getInnerField() throws Exception {
49+
return Class.forName("java.util.Collections$UnmodifiableCollection").getDeclaredField("c");
50+
}
51+
52+
@Override
53+
protected Collection<?> newInstance(Collection<?> c) {
54+
return Collections.unmodifiableCollection(c);
55+
}
56+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2016 Alex Chermenin
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package com.twitter.chill.java;
19+
20+
import com.esotericsoftware.kryo.Kryo;
21+
import com.esotericsoftware.kryo.Serializer;
22+
import com.esotericsoftware.kryo.io.Input;
23+
import com.esotericsoftware.kryo.io.Output;
24+
25+
import java.lang.reflect.Field;
26+
import java.util.Collection;
27+
import java.util.Collections;
28+
29+
/**
30+
* A kryo base {@link Serializer} for unmodifiable Java collections.
31+
* <p>
32+
* Note: This serializer does not support cyclic references, so if one of the objects
33+
* gets set the list as attribute this might cause an error during deserialization.
34+
* </p>
35+
*
36+
* @author <a href="mailto:alex@chermenin.ru">Alex Chermenin</a>
37+
*/
38+
abstract class UnmodifiableJavaCollectionSerializer<T> extends Serializer<T> {
39+
40+
abstract protected T newInstance(T o);
41+
42+
abstract protected Field getInnerField() throws Exception;
43+
44+
final private Field innerField;
45+
46+
UnmodifiableJavaCollectionSerializer() {
47+
try {
48+
innerField = getInnerField();
49+
innerField.setAccessible(true);
50+
} catch (Exception e) {
51+
throw new RuntimeException(e);
52+
}
53+
}
54+
55+
@Override
56+
@SuppressWarnings("unchecked")
57+
public T read(Kryo kryo, Input input, Class<T> type) {
58+
try {
59+
T u = (T) kryo.readClassAndObject(input);
60+
return newInstance(u);
61+
} catch (Exception e) {
62+
throw new RuntimeException(e);
63+
}
64+
}
65+
66+
@Override
67+
@SuppressWarnings("unchecked")
68+
public void write(Kryo kryo, Output output, T object) {
69+
try {
70+
T u = (T) innerField.get(object);
71+
kryo.writeClassAndObject(output, u);
72+
} catch (RuntimeException e) {
73+
// Don't eat and wrap RuntimeExceptions because the ObjectBuffer.write...
74+
// handles SerializationException specifically (resizing the buffer)...
75+
throw e;
76+
} catch (Exception e) {
77+
throw new RuntimeException(e);
78+
}
79+
}
80+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2016 Alex Chermenin
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package com.twitter.chill.java;
19+
20+
import com.esotericsoftware.kryo.Kryo;
21+
import com.esotericsoftware.kryo.Serializer;
22+
import com.esotericsoftware.kryo.io.Input;
23+
import com.esotericsoftware.kryo.io.Output;
24+
import com.twitter.chill.IKryoRegistrar;
25+
import com.twitter.chill.SingleRegistrar;
26+
27+
import java.lang.reflect.Field;
28+
import java.util.*;
29+
30+
/**
31+
* A kryo {@link Serializer} for unmodifiable lists created via {@link Collections#unmodifiableList(List)}.
32+
* <p>
33+
* Note: This serializer does not support cyclic references, so if one of the objects
34+
* gets set the list as attribute this might cause an error during deserialization.
35+
* </p>
36+
*
37+
* @author <a href="mailto:alex@chermenin.ru">Alex Chermenin</a>
38+
*/
39+
public class UnmodifiableListSerializer extends UnmodifiableJavaCollectionSerializer<List<?>> {
40+
41+
@SuppressWarnings("unchecked")
42+
static public IKryoRegistrar registrar() {
43+
return new IterableRegistrar(
44+
new SingleRegistrar(Collections.unmodifiableList(Collections.EMPTY_LIST).getClass(),
45+
new UnmodifiableListSerializer()),
46+
new SingleRegistrar(Collections.unmodifiableList(new LinkedList(Collections.EMPTY_LIST)).getClass(),
47+
new UnmodifiableListSerializer())
48+
);
49+
}
50+
51+
@Override
52+
protected Field getInnerField() throws Exception {
53+
return Class.forName("java.util.Collections$UnmodifiableList").getDeclaredField("list");
54+
}
55+
56+
@Override
57+
protected List<?> newInstance(List<?> l) {
58+
return Collections.unmodifiableList(l);
59+
}
60+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2016 Alex Chermenin
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package com.twitter.chill.java;
19+
20+
import com.esotericsoftware.kryo.Kryo;
21+
import com.esotericsoftware.kryo.Serializer;
22+
import com.esotericsoftware.kryo.io.Input;
23+
import com.esotericsoftware.kryo.io.Output;
24+
import com.twitter.chill.IKryoRegistrar;
25+
import com.twitter.chill.SingleRegistrar;
26+
27+
import java.lang.reflect.Field;
28+
import java.util.*;
29+
30+
/**
31+
* A kryo {@link Serializer} for unmodifiable maps created via {@link Collections#unmodifiableMap(Map)}.
32+
* <p>
33+
* Note: This serializer does not support cyclic references, so if one of the objects
34+
* gets set the list as attribute this might cause an error during deserialization.
35+
* </p>
36+
*
37+
* @author <a href="mailto:alex@chermenin.ru">Alex Chermenin</a>
38+
*/
39+
public class UnmodifiableMapSerializer extends UnmodifiableJavaCollectionSerializer<Map<?, ?>> {
40+
41+
@SuppressWarnings("unchecked")
42+
static public IKryoRegistrar registrar() {
43+
return new SingleRegistrar(Collections.unmodifiableMap(Collections.EMPTY_MAP).getClass(),
44+
new UnmodifiableMapSerializer());
45+
}
46+
47+
@Override
48+
protected Field getInnerField() throws Exception {
49+
return Class.forName("java.util.Collections$UnmodifiableMap").getDeclaredField("m");
50+
}
51+
52+
@Override
53+
protected Map<?, ?> newInstance(Map<?, ?> m) {
54+
return Collections.unmodifiableMap(m);
55+
}
56+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2016 Alex Chermenin
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package com.twitter.chill.java;
19+
20+
import com.esotericsoftware.kryo.Kryo;
21+
import com.esotericsoftware.kryo.Serializer;
22+
import com.esotericsoftware.kryo.io.Input;
23+
import com.esotericsoftware.kryo.io.Output;
24+
import com.twitter.chill.IKryoRegistrar;
25+
import com.twitter.chill.SingleRegistrar;
26+
27+
import java.lang.reflect.Field;
28+
import java.util.*;
29+
30+
/**
31+
* A kryo {@link Serializer} for unmodifiable sets created via {@link Collections#unmodifiableSet(Set)}.
32+
* <p>
33+
* Note: This serializer does not support cyclic references, so if one of the objects
34+
* gets set the list as attribute this might cause an error during deserialization.
35+
* </p>
36+
*
37+
* @author <a href="mailto:alex@chermenin.ru">Alex Chermenin</a>
38+
*/
39+
public class UnmodifiableSetSerializer extends UnmodifiableJavaCollectionSerializer<Set<?>> {
40+
41+
@SuppressWarnings("unchecked")
42+
static public IKryoRegistrar registrar() {
43+
return new SingleRegistrar(Collections.unmodifiableSet(Collections.EMPTY_SET).getClass(),
44+
new UnmodifiableSetSerializer());
45+
}
46+
47+
@Override
48+
protected Field getInnerField() throws Exception {
49+
return Class.forName("java.util.Collections$UnmodifiableSet").getSuperclass().getDeclaredField("c");
50+
}
51+
52+
@Override
53+
protected Set<?> newInstance(Set<?> s) {
54+
return Collections.unmodifiableSet(s);
55+
}
56+
}

0 commit comments

Comments
 (0)