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转换期间设置