Closed GoogleCodeExporter closed 8 years ago
I'm not seeing this behavior. The following fails with a
SerializationException, as expected. Please provide a simple code snippet
showing the problem and I will reopen this bug.
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoTestCase;
public class SerializeClassTest extends KryoTestCase {
public void testFieldSerializer () {
Kryo kryo = new Kryo();
kryo.register(TestClass.class);
TestClass object1 = new TestClass();
kryo.writeClassAndObject(buffer, object1);
buffer.flip();
TestClass object2 = (TestClass)kryo.readClassAndObject(buffer);
System.out.println(object2.c);
}
static public class TestClass {
public Class c;
}
}
Original comment by nathan.s...@gmail.com
on 20 Dec 2010 at 8:05
[deleted comment]
Here's an example -- it succeeded in serializing but failed in deserializing,
which is fairly dangerous
Thanks!
Succeeded in serializing to 3 bytes
Exception in thread "main" com.esotericsoftware.kryo.SerializationException:
Unable to deserialize object of type: KryoTest$TestClass
at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:563)
at com.esotericsoftware.kryo.ObjectBuffer.readClassAndObject(ObjectBuffer.java:202)
at KryoTest.main(KryoTest.java:38)
Caused by: com.esotericsoftware.kryo.SerializationException: Error constructing
instance of class: java.lang.Class
Serialization trace:
_containedClass (KryoTest$TestClass)
at com.esotericsoftware.kryo.Kryo.newInstance(Kryo.java:681)
at com.esotericsoftware.kryo.Serializer.newInstance(Serializer.java:75)
at com.esotericsoftware.kryo.serialize.FieldSerializer.readObjectData(FieldSerializer.java:192)
at com.esotericsoftware.kryo.Serializer.readObject(Serializer.java:61)
at com.esotericsoftware.kryo.serialize.FieldSerializer.readObjectData(FieldSerializer.java:220)
at com.esotericsoftware.kryo.serialize.FieldSerializer.readObjectData(FieldSerializer.java:192)
at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:558)
... 2 more
Caused by: java.lang.IllegalAccessException: Can not call newInstance() on the
Class for java.lang.Class
at java.lang.Class.newInstance0(Class.java:320)
at java.lang.Class.newInstance(Class.java:308)
at com.esotericsoftware.kryo.Kryo.newInstance(Kryo.java:668)
... 8 more
Java code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.ObjectBuffer;
/**
*
* @author rbakhru
*/
public class KryoTest {
private static Logger LOG = LoggerFactory.getLogger(KryoTest.class);
public static class TestContainedClass {
}
public static class TestClass {
private final Class<?> _containedClass = TestContainedClass.class;
}
public static void main(String[] args) throws Exception {
Kryo kryo = new Kryo();
kryo.register(TestClass.class);
kryo.register(Class.class);
ObjectBuffer buffer = new ObjectBuffer(kryo, 1024, 1024 * 1024);
TestClass object1 = new TestClass();
byte[] bytes = buffer.writeClassAndObject(object1);
System.out.println("Succeeded in serializing to " + bytes.length + " bytes");
buffer = new ObjectBuffer(kryo, 1024, 1024 * 1024);
TestClass returnVal = (TestClass) buffer.readClassAndObject(bytes);
System.out.println(returnVal);
}
}
Original comment by rbakhru@gmail.com
on 20 Dec 2010 at 11:49
Ah, I see. The problem is here:
kryo.register(Class.class);
This registers the class "Class" with the default serializer (FieldSerializer).
This is invalid, as FieldSerializer cannot create instances of Class. The fix
is:
kryo.register(Class.class, new ClassSerializer(kryo));
Currently FieldSerializer calls Serializer#newInstance which calls
Kryo#newInstance. Either of these newInstance methods can be overridden. This
means currently the only way to know if a class can be instantiated is to call
one of these methods, which is somewhat wasteful.
FieldSerializer knows the type it needs to handle in its constructor and could
call newInstance there and throw away the response. This object creation may be
unexpected, but I guess could be documented. Calling a method intended for
overriding from the constructor will cause the subclass' method to be invoked
before the subclass constructor is run -- unexpected behavior that may cause
initialization problems. This could just be accepted, or it could be worked
around with a boolean that causes newInstance to happen only the first time
writeObjectData is called. The question is: Is it really worth the trouble
given the (admittedly somewhat minor) drawbacks?
Original comment by nathan.s...@gmail.com
on 20 Dec 2010 at 11:54
In Kryo v2, object creation for FieldSerializer and other generic serializers
typically occurs in Serializer#create(...). This method could be overridden and
could potentially read from the input before creating an instance. This means
there is no good place to check if the type can be constructed until
deserialization actually occurs.
I recommend using application specific code to verify instances of a type can
be constructed in order to catch the error before deserialization. To test if
construction is possible using the default mechanism, first call Kryo#register,
then call Kryo#newInstance.
Original comment by nathan.s...@gmail.com
on 26 Apr 2012 at 2:28
Original issue reported on code.google.com by
rbakhru@gmail.com
on 20 Dec 2010 at 5:23