0

2 つのアセンブリがあります
。1) シリアライザーを含むアセンブリ。これは、シリアライゼーションとデシリアライゼーションが開始される場所です。
2) シリアル化された型を含むアセンブリ。これは、最初のアセンブリからシリアライザを呼び出している場所です。
assembly1 のシリアライザーの考え方は単純です。バイト配列との間のオブジェクトの変換に使用される 2 つのメソッドがあります。そのシリアライザーのクライアント コードは次のようになります。

    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 が定義されているアセンブリに関する情報が含まれます。ただし、(IKVM で変換された) Java のクラスを使用してシリアライザーが実装される場合、逆シリアル化中に 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 では機能しませんが、BuddyPolicy や RegisterBuddy などのプラグイン マニフェストに追加のエントリを指定して Eclipse からロードした場合、Java では正常に機能します。JavaSerializer から DotNetSerializer に切り替えることはできません。私のアプリケーション (ほとんどが Java で記述されている) には、readObject、writeObject、readResolve などがたくさんあるためです。 . 現在、いくつかの仮説的な解決方法があります。

  • ObjectOutputStream のいくつかのメソッドをオーバーロードするため、MyClass のシリアル化された形式には、「MyClass、MyAssembly、...」などのアセンブリ名も含まれます。
  • ObjectInputStream でいくつかのメソッドをオーバーロードするため、クラスは別の方法でロードされます。おそらく、別のアセンブリで検索する必要があります。
  • IKVM が MyClass を検索する場所を認識できるように、アセンブリ マニフェストにいくつかの情報を追加します。これの何かは本当ですか?この問題はどのように解決されるべきですか?
4

1 に答える 1

0

IKVM チームの担当者が答えを教えてくれました。

1) ObjectOutputStream をサブクラス化し、annotateClass をオーバーライドしてアセンブリ名を書き込み、ObjectInputStream をサブクラス化し、resolveClass をオーバーライドしてアセンブリ名を読み取ることができます。

2) 次のカスタム属性を、逆シリアル化を行うアセンブリに追加します: [assembly: 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 からの変換中に設定される可能性もあります。

于 2009-06-17T03:44:55.057 に答える