|
17 | 17 | package com.twitter.chill.java;
|
18 | 18 |
|
19 | 19 | import com.esotericsoftware.kryo.Kryo;
|
| 20 | +import com.esotericsoftware.kryo.KryoException; |
20 | 21 | import com.esotericsoftware.kryo.Serializer;
|
21 | 22 | import com.esotericsoftware.kryo.io.Input;
|
22 | 23 | import com.esotericsoftware.kryo.io.Output;
|
23 | 24 |
|
24 | 25 | import com.twitter.chill.IKryoRegistrar;
|
25 | 26 | import com.twitter.chill.SingleRegistrar;
|
26 | 27 |
|
| 28 | +import java.io.Serializable; |
| 29 | +import java.lang.reflect.Constructor; |
| 30 | +import java.lang.reflect.Field; |
| 31 | +import java.lang.reflect.Method; |
27 | 32 | import java.util.BitSet;
|
28 | 33 |
|
29 |
| -public class BitSetSerializer extends Serializer<BitSet> { |
| 34 | +public class BitSetSerializer extends Serializer<BitSet> implements Serializable { |
30 | 35 |
|
31 | 36 | static public IKryoRegistrar registrar() {
|
32 | 37 | return new SingleRegistrar(BitSet.class, new BitSetSerializer());
|
33 | 38 | }
|
34 | 39 |
|
| 40 | + private final static Field wordsField; |
| 41 | + private final static Constructor<BitSet> bitSetConstructor; |
| 42 | + private final static Method recalculateWordsInUseMethod; |
| 43 | + |
| 44 | + static { |
| 45 | + try { |
| 46 | + wordsField = BitSet.class.getDeclaredField("words"); |
| 47 | + wordsField.setAccessible(true); |
| 48 | + } catch (NoSuchFieldException e) { |
| 49 | + throw new KryoException("Error while getting field 'words' of bitSet", e); |
| 50 | + } |
| 51 | + try { |
| 52 | + bitSetConstructor = BitSet.class.getDeclaredConstructor(long[].class); |
| 53 | + bitSetConstructor.setAccessible(true); |
| 54 | + } catch (NoSuchMethodException e) { |
| 55 | + throw new KryoException("Unable to get BitSet(long[]) constructor", e); |
| 56 | + } |
| 57 | + try { |
| 58 | + recalculateWordsInUseMethod = BitSet.class.getDeclaredMethod("recalculateWordsInUse"); |
| 59 | + recalculateWordsInUseMethod.setAccessible(true); |
| 60 | + } catch (NoSuchMethodException e) { |
| 61 | + throw new KryoException("Unable to get BitSet.recalculateWordsInUse() method", e); |
| 62 | + } |
| 63 | + } |
| 64 | + |
35 | 65 | @Override
|
36 | 66 | public void write(Kryo kryo, Output output, BitSet bitSet) {
|
37 |
| - int len = bitSet.length(); |
38 |
| - |
39 |
| - output.writeInt(len, true); |
| 67 | + long words[] = null; |
| 68 | + // its sufficent to get only the 'words' field because |
| 69 | + // we can recompute the wordsInUse after deserialization |
| 70 | + try { |
| 71 | + words = (long[]) wordsField.get(bitSet); |
| 72 | + } catch (IllegalAccessException e) { |
| 73 | + throw new KryoException("Error while accessing field 'words' of bitSet", e); |
| 74 | + } |
| 75 | + output.writeInt(words.length, true); |
40 | 76 |
|
41 |
| - for(int i = 0; i < len; i++) { |
42 |
| - output.writeBoolean(bitSet.get(i)); |
| 77 | + for(int i = 0; i < words.length; i++) { |
| 78 | + output.writeLong(words[i]); |
43 | 79 | }
|
44 | 80 | }
|
45 | 81 |
|
46 | 82 | @Override
|
47 | 83 | public BitSet read(Kryo kryo, Input input, Class<BitSet> bitSetClass) {
|
48 | 84 | int len = input.readInt(true);
|
49 |
| - BitSet ret = new BitSet(len); |
| 85 | + long[] target = new long[len]; |
50 | 86 |
|
51 | 87 | for(int i = 0; i < len; i++) {
|
52 |
| - ret.set(i, input.readBoolean()); |
| 88 | + target[i] = input.readLong(); |
| 89 | + } |
| 90 | + |
| 91 | + BitSet ret = null; |
| 92 | + // call a private constructor: (the BitSet.valueOf() cTor is only available from Java 1.7) |
| 93 | + try { |
| 94 | + ret = bitSetConstructor.newInstance(target); |
| 95 | + } catch (ReflectiveOperationException e) { |
| 96 | + throw new KryoException("Unable to call BitSet(long[]) constructor", e); |
| 97 | + } |
| 98 | + try { |
| 99 | + recalculateWordsInUseMethod.invoke(ret); |
| 100 | + } catch (ReflectiveOperationException e) { |
| 101 | + throw new KryoException("Unable to call BitSet.recalculateWordsInUse() method", e); |
53 | 102 | }
|
54 | 103 |
|
55 | 104 | return ret;
|
|
0 commit comments