从另一个程序集反序列化类中的类加载问题

时间:2009-06-16 07:30:23

标签: java .net serialization ikvm

有两个组件:
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);

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中不起作用,但如果从Eclipse加载,并且在插件清单中有其他条目,例如BuddyPolicy和RegisterBuddy,它将在Java中正常工作。我不能只是从JavaSerializer切换到DotNetSerializer,因为在我的应用程序(主要是用Java编写)中有很多readObject,writeObject,readResolve等...但是我需要以某种方式解决这个问题,所以我寻求解决方案。目前我看到了一些假设的解决方法:

  • 重载ObjectOutputStream的某些方法,因此MyClass的序列化形式也将包含程序集名称,如“MyClass,MyAssembly,...”。
  • 在ObjectInputStream中重载一些方法,所以类会以某种不同的方式加载,也许应该在一些不同的程序集中搜索等。
  • 向程序集清单添加一些信息,以便IKVM知道在哪里搜索MyClass。 这是真的吗?如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

来自IKVM团队的人给了我答案:

  

1)您可以继承ObjectOutputStream   并覆盖annotateClass以进行写入   程序集名称和子类   ObjectInputStream和覆盖   resolveClass读取程序集   名。

     

2)添加以下自定义属性   到组件做的   反序列化:[汇编:   IKVM.Attributes.CustomAssemblyClassLoader(typeof运算(ikvm.runtime.AppDomainAssemblyClassLoader))]

我还发现我可以在应用程序配置文件中使用显式设置覆盖任何程序集的类加载器:

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