Java 从另一个程序集反序列化类型期间类加载问题
有两个程序集:Java 从另一个程序集反序列化类型期间类加载问题,java,.net,serialization,ikvm,Java,.net,Serialization,Ikvm,有两个程序集: 1) 包含序列化程序的程序集。这是序列化和反序列化开始的地方。 2) 包含序列化类型的程序集。这是从第一个程序集调用序列化程序的位置。 assembly1中序列化程序的思想很简单。它有两种方法,用于将对象从字节数组和转换为字节数组。该序列化程序的客户端代码可以如下所示: ISerializer serializer = ... MyClass my = new MyClass(); byte[] data = serializer.Serialize(m
1) 包含序列化程序的程序集。这是序列化和反序列化开始的地方。
2) 包含序列化类型的程序集。这是从第一个程序集调用序列化程序的位置。
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);
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是在assembly2中定义的,因此assembly1对此一无所知。如果序列化程序是用标准的.Net类实现的,则该场景将起作用,如下所示:
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);
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中不起作用,但如果从Eclipse加载插件清单中的附加条目(如BuddyPolicy和RegisterBuddy),则在Java中可以正常工作。我不能只是从JavaSerializer切换到DotNetSerializer,因为在我的应用程序(主要是用Java编写的)中,有很多readObject、writeObject、readResolve等。。。但我需要以某种方式解决这个问题,所以我在寻找解决方案。目前我看到了一些假设的解决方法:
- 重载ObjectOutputStream的某些方法,因此MyClass的序列化形式也将包含程序集名称,如“MyClass,MyAssembly,…”
- 重载ObjectInputStream中的某个方法,所以类将以不同的方式加载,可能应该在不同的程序集中搜索,等等
- 向程序集清单添加一些信息,以便IKVM知道在哪里搜索MyClass。 这些东西是真的吗?这个问题应该如何解决
- IKVM团队的人给了我答案:
1) 您可以将ObjectOutputStream子类化
并重写要编写的注释类
程序集名称和子类
ObjectInputStream和override
resolveClass以读取程序集
名字
2) 添加以下自定义属性
到执行以下操作的程序集:
反序列化:[程序集:
IKVM.Attributes.CustomAssemblyClassLoader(typeof(IKVM.runtime.AppDomainAssemblyClassLoader))]
我还发现,我可以使用应用程序配置文件中的显式设置覆盖任何程序集的classloader:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ikvm-classloader:MyExampleAssembly" value="ikvm.runtime.AppDomainAssemblyClassLoader, IKVM.OpenJDK.ClassLibrary, Version=0.37.0.0, Culture=neutral, PublicKeyToken=null" />
</appSettings>
</configuration>
当使用-classloader命令行参数时,它也可能在从java jar转换期间设置