Nov11 / kryo

Automatically exported from code.google.com/p/kryo
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

Not able to Serialize a class which had EnumSet as a member variable. #28

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Register a class which has EnumSet in it
2.
3.

What is the expected output? What do you see instead?

Caused by: java.lang.IllegalArgumentException: Class is not registered: 
java.util.RegularEnumSet
    at com.esotericsoftware.kryo.Kryo.getRegisteredClass(Kryo.java:311)
    at com.esotericsoftware.kryo.Kryo.writeClass(Kryo.java:366)
    at com.esotericsoftware.kryo.serialize.FieldSerializer.writeObjectData(FieldSerializer.java:165)
    ... 3 more

What version of the Kryo are you using?
1.03

Please provide any additional information below.
RegularEnumSet is not public so not able to register I could register EnumSet 
but not working.

Original issue reported on code.google.com by manish.s...@gmail.com on 30 Sep 2010 at 4:53

GoogleCodeExporter commented 9 years ago
You will need to write a custom serializer for EnumSet. If you have an EnumSet, 
the only way to know the element type for the set is to look at one of the 
elements. Interestingly, if you have an empty EnumSet, you cannot determine 
what type it is. This means you cannot serialize an empty EnumSet, because you 
don't know what type to use for deserialization. Your only recourse is to take 
up the issue with Joshua Bloch, the EnumSet author.

This should get you started:

class EnumSetSerializer extends SimpleSerializer<EnumSet> {
    private final Kryo kryo;

    public EnumSetSerializer (Kryo kryo) {
        this.kryo = kryo;
    }

    public void write (ByteBuffer buffer, EnumSet set) {
        if (set.isEmpty()) throw new SerializationException("An empty EnumSet cannot be serialized.");
        kryo.writeClass(buffer, set.iterator().next().getClass());
        IntSerializer.put(buffer, set.size(), true);
        for (Object e : set)
            EnumSerializer.put(buffer, (Enum)e);
    }

    public EnumSet read (ByteBuffer buffer) {
        Class elementType = kryo.readClass(buffer).getType();
        int size = IntSerializer.get(buffer, true);
        ArrayList enums = new ArrayList(size);
        for (int i = 0; i < size; i++)
            enums.add(EnumSerializer.get(buffer, elementType));
        return EnumSet.copyOf(enums);
    }
}

Note that Kryo uses a map to go from a class to a serializer. Since EnumSet is 
abstract, you need to customize your usage of Kryo so that concrete instances 
of EnumSet are handled as if they were simply EnumSet:

Kryo kryo = new Kryo() {
    public RegisteredClass getRegisteredClass (Class type) {
        if (EnumSet.class.isAssignableFrom(type)) type = EnumSet.class;
        return super.getRegisteredClass(type);
    }
};
kryo.register(EnumSet.class, new EnumSetSerializer(kryo));
kryo.register(SomeEnum.class);
EnumSet<SomeEnum> set = EnumSet.of(SomeEnum.a, SomeEnum.c);
kryo.writeClassAndObject(buffer, set);
// ...
kryo.readClassAndObject(buffer);

As a (not so great) alternative, you can use built-in Java serialization for 
EnumSet.

Original comment by nathan.s...@gmail.com on 10 Oct 2010 at 3:13