Есть две сборки:
1) Сборка, содержащая сериализатор. Это место, откуда начинается сериализация и десериализация.
2) Сборка, содержащая сериализованные типы. Это место, которое вызывает сериализатор с 1-й сборки.
Идея сериализатора в Assembly1 проста. У него есть два метода, которые используются для преобразования объектов из байтовых массивов и в них. Код клиента для этого сериализатора может выглядеть так:
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 определен в Assembly2, поэтому Assembly1 ничего не знает об этом. Этот сценарий будет работать, если сериализатор реализован со стандартными классами .Net, например:
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);
}
}
}
Сериализованная форма MyClass будет содержать информацию о сборке, в которой определен MyClass. Однако, если сериализатор будет реализован с использованием классов Java (преобразованных с помощью IKVM), то при десериализации возникнет исключение ClassNotFound. Это реализация сериализатора с использованием классов Java:
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();
}
}
Это не будет работать в .Net, но будет нормально работать в Java, если загружено из Eclipse с дополнительными записями в манифестах плагинов, таких как BuddyPolicy и RegisterBuddy. Я не могу просто переключиться с JavaSerializer на DotNetSerializer, поскольку в моем приложении (которое в основном написано на Java) есть много readObject, writeObject, readResolve и т. Д. Но мне нужно как-то решить эту проблему, поэтому я ищу решение , В настоящее время я вижу некоторые гипотетические пути решения:
- Перегрузка некоторого метода ObjectOutputStream, поэтому в сериализованной форме MyClass также будет содержаться имя сборки, например «MyClass, MyAssembly, ...».
- Перегрузка некоторого метода в ObjectInputStream, поэтому класс будет загружен другим способом, возможно, его нужно искать в другой сборке и т. Д.
- Добавление некоторой информации в манифесты сборок позволяет IKVM знать, где искать MyClass.
Что-нибудь из этого реально? Как решить эту проблему?