【问题标题】:Problems with class loading during deserialization of type from another assembly从另一个程序集反序列化类型期间的类加载问题
【发布时间】:2009-06-16 07:30:22
【问题描述】:

有两个程序集:
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。 这是真的吗?这个问题应该如何解决?

【问题讨论】:

    标签: java .net serialization ikvm


    【解决方案1】:

    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转换时设置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      • 1970-01-01
      相关资源
      最近更新 更多