gaob13 / kryo

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

Implement exception with details on unregistered class, or callback #7

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Steps will reproduce the problem:
1. kryo.writeClassAndObject(buffer, object); // when object's class or some 
class from its graph is not registered 
2. you get IllegalArgumentException exception with textual description of 
class, like "Class is not registered: <Class name>" 

Instead, it would be better to throw an exception with explicit Class 
property in it, to make it possible to see which class was not registered. 
With the code like this:

throw new KryoUnregisteredException(type, "Class is not registered: "...)

This addition is needed to register classes dynamically in runtime, and 
retry the serialization until all classes are registered.

Alternative solution would be to use user-supplied callback code which 
performs registration instead of throwing an exception.

Original issue reported on code.google.com by dmitry10...@gmail.com on 27 Feb 2010 at 7:06

GoogleCodeExporter commented 9 years ago
When a class is registered, it is assigned a sequential int ID. When an 
instance is
serialized, this ID is written in the bytes. When the bytes are deserialized, 
Kryo
needs to construct an object based on the ID in the bytes.

Because the registered class IDs are sequential, the order in which they are
registered when serialized must be identical when deserialized. What you 
propose, to
automatically register classes, would cause the sequential registered class IDs 
to be
dependent on the order that unregistered classes are encountered. I see two 
problems
with this:

1) You won't be able to deserialize an object if it has never been registered
explicitly and it has never been serialized.

2) If you run your app twice, it is quite probable that you serialize objects 
in a
different order, which means you may encounter unregistered classes in a 
different
order. This would cause the registered class IDs to be different than when your
objects were serialized and you would not be able to deserialize objects from 
the
previous program run.

The only time I can see your proposal being useful is if you only ever 
deserialize
bytes that were serialized in the same run of your program. Is this the case?

Forcing classes to be registered is a bit inconvenient, but is the simplest and 
most
efficient solution.

Please note that Kryo has a built-in feature for serializing unregistered 
classes.
See the Kryo#setAllowUnregisteredClasses(boolean) method. When true, 
unregistered
classes will not throw an exception. Instead of the registered class ID being 
written
to bytes, the full class name String is written. This is less efficient than 
writing
an int ID, but does solve the problem.

I have toyed with the idea of making the class registration behavior pluggable. 
Eg,
you might want to not register any classes and when unregistered classes are
encountered, you write a new row in a database containing the ID and class 
name. This
increases complexity but doesn't increase the serialized size. If people have a 
need
for pluggable class registration behavior, I will prioritize the task higher.

Original comment by nathan.s...@gmail.com on 28 Feb 2010 at 8:19

GoogleCodeExporter commented 9 years ago
Issue 2 has been merged into this issue.

Original comment by nathan.s...@gmail.com on 4 Mar 2010 at 4:54

GoogleCodeExporter commented 9 years ago
Nathan, thank you very much for your explanation. 

I use Kryo for networking code which works like this:
1. It tries to serialize message object and all reachable objects within its 
graph
2. When it encounters the exception:
2.1. It registers the missing class 
2.2. It sends name/bytecode of registered classes to receiving party, so it 
register the same classes in the 
same order. That's how order is maintained.
2.3. Do this until all classes in graph are registered. 
3. When it's done, it sends the serialized message to receiving party, which 
can deserialize it properly 
because all required classes are already received and registered in the same 
order.

It would be great if you throw Exception with class in it, along with textual 
representation of error, so I 
don't have to parse class name from textual description of error in Exception.

Original comment by dmitry10...@gmail.com on 17 Mar 2010 at 9:23

GoogleCodeExporter commented 9 years ago
I would like to make improvements to the way classes are registered. Trying a 
graph
repeatedly to take a special action for each class is not ideal. I would like a
pluggable mechanism that decides how unregistered classes are handled.

Original comment by nathan.s...@gmail.com on 25 Mar 2010 at 1:27

GoogleCodeExporter commented 9 years ago

Original comment by nathan.s...@gmail.com on 25 Mar 2010 at 1:28

GoogleCodeExporter commented 9 years ago
Checked in to r82. Some minor API breakage, but I am much happier with this 
part of
the API now. You can call Kryo#setRegistrationOptional(true), then the protected
Kryo#handleUnregisteredClass method will be called as unregistered classes are
encountered. The default implementation registers the classes to use the class 
name
String in the serialized bytes. For your usage, you would override
handleUnregisteredClass and register the class with an ordinal instead, then 
send the
other parties in your app the class to register so they get the same ordinal.

Original comment by nathan.s...@gmail.com on 26 Mar 2010 at 12:11