There are two assemblies:
1) Assembly containing serializer. This is a place from where serialization and deserialization starts.
2) Assembly containing serialized types. This is a place which is calling serializer from 1st assembly.
The idea of serializer in assembly1 is simple. It has two methods which are used for conversions of objects from and to byte arrays. The client code for that serializer can look like this:
ISerializer serializer = ...
MyClass my = new MyClass();
byte[] data = serializer.Serialize(my);
Console.WriteLine(Encoding.ASCII.GetString(data)); // dump serialized form
MyClass another = (MyClass)serializer.Deserialize(data);
MyClass is defined in assembly2, so assembly1 knows nothing about it. That scenario will work if serializer is implemented with standard .Net classes, like this:
public class DotNetSerializer : ISerializer
{
public byte[] Serialize(object obj)
{
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, obj);
byte[] result = stream.GetBuffer();
Array.Resize(ref result, (int)stream.Length);
return result;
}
}
public object Deserialize(byte[] data)
{
BinaryFormatter formatter = new BinaryFormatter();
using (Stream stream = new MemoryStream(data))
{
return formatter.Deserialize(stream);
}
}
}
The serialized form of MyClass will contain information about assembly in which MyClass is defined. However, if serializer will be implemented with usage of Java's classes (converted with IKVM) then there will be ClassNotFound exception thrown during deserialization. This is a serializer implementation using Java classes:
public class JavaSerializer : ISerializer
{
public object Deserialize(byte[] data)
{
ByteArrayInputStream stream = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(stream);
return ois.readObject();
}
public byte[] Serialize(object obj)
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(stream);
oos.writeObject(obj);
stream.flush();
return stream.toByteArray();
}
}
This will not work in .Net, but will work normally in Java if loaded from Eclipse with additional entries in plugin manifests such as BuddyPolicy and RegisterBuddy. I can't just switch from JavaSerializer to DotNetSerializer since in my application (which is mostly written in Java) there are lots of readObject,writeObject,readResolve,etc... But I need to fix that problem somehow, so I seeking for solution. Currently I see some hypothetical ways of solution:
- Overloading some method of ObjectOutputStream, so serialized form of MyClass will contain assembly name too, like "MyClass, MyAssembly, ...".
- Overloading some method in ObjectInputStream, so class will be loaded in some different way, maybe it should be searched in some different assembly, etc.
- Adding some information to assemblies manifests so IKVM will know where to search for MyClass. Is anything of this is real? How this problem should be solved?