2009年7月22日水曜日

NHibernate 2.1.0 on Mono 2.4

このエントリーをはてなブックマークに追加
2.1.0.Alpha2 は Mono 2.4 上で使用できたが、2.1.0.Alpha3 以降、次の様な例外が発生していた。

Unhandled Exception: NHibernate.MappingException:Could not compile the mapping document: Product.hbm.xml --->
  System.InvalidOperationException: There was an error reflecting type 'NHibernate.Cfg.MappingSchema.HbmMapping'. --->
  System.InvalidOperationException: To be XML serializable, types which inherit from ICollection must have an implementation of Add(System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[NHibernate.Mapping.MetaAttribute, NHibernate, Version=2.1.0.3001, Culture=neutral, PublicKeyToken=aa95f207798dfdb4]]) at all levels of their inheritance hierarchy.
  System.Collections.Generic.IDictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[NHibernate.Mapping.MetaAttribute, NHibernate, Version=2.1.0.3001, Culture=neutral, PublicKeyToken=aa95f207798dfdb4]] does not implement Add(System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[NHibernate.Mapping.MetaAttribute, NHibernate, Version=2.1.0.3001, Culture=neutral, PublicKeyToken=aa95f207798dfdb4]]).

この例外については、
で議論されていて、参照すれば分かるが、現在、この例外は NHibernate 側で対応済み。

しかし、当初の NHibernate 側の態度は、

「v2.1.0 beta 2 bug under mono 2.4」から引用
No that mean that mean that if you can prove that the cause is inside NH and
we can do something ok.If you can't prove that the problem is inside NH
well... you should find the place where create the issue.
NH's is for NH issues and not for mono isees nor for DataProvider issues nor
RDBMS issues and so on.

Btw Mono should work at least as NET.
When a framework is working without problems on windows and has a problem in
Mono the most probably is an issue in Mono, and Mono's users should help to
improve it and not asking workaround everywhere.
いいえ、もしNHに原因があると証明できるのなら、私たちは何か対応することができるでしょうが、NHに原因があると証明できないなら、問題提起を行う別のふさわしい場所を見つけるべき、ということです。
ここは、NHの問題を提起する場であり、Mono の問題、データプロバイダの問題、RDBMS の問題を扱う場ではないのです。

ところで、Mono は少なくとも .NET と同じように動くべきです。
Windows 上の .NET 環境で問題なく動いていて、Mono 環境で問題があるなら、おそらく、問題の大部分は、Mono にあるでしょう、また、Mono のユーザーは、問題解決の手助けをするべきですが、いたる所で解決策を尋ねるべきではありません。
ふーむ、そりゃそうだが、つれないなぁ。

一方、Mono 側では、この例外に関する次のようなコメントが。

「Bug 519442 - Inconsistent XML serialization between Mono 2.4 and .NET 3.5 throwing InvalidOperationException」から引用
Ask the HNibernate devs if ignoring these fields is the expected behavior.

If they are confirming this, ask them to apply [XmlIgnore] to these fields,
because they are relying on an undocumented MS.NET feature or bug. If the
feature is documented, we'll fix it.

If they expect these fields to be serialized, we'd need a test case or at least
a link to the problematic location in their source code because I cannot
reproduce a successful XML serialization of IDictionary<K,V> under MS.NET 3.5.
NHibernate 開発者たちに、これらのフィールドのシリアル化を無視するのが、期待された振舞いであるかどうか、尋ねてください。

彼らがこれを認識しているなら、彼らは正式文書に記載のない MS.NET の機能かバグを当てにしていることになるので、これらのフィールドに [XmlIgnore] を適用するように頼んでください。この機能が記載されるなら、私たちはそれに対応するつもりです。

彼らが、これらのフィールドがシリアル化されると考えるのなら、私は、MS.NET3.5 環境下で IDictionary<K,V> の XML シリアル化がうまくいくのを再現できないので、テストケースか、少なくとも、彼らのソースコードの内、問題のありそうな箇所へのリンクが必要となります。
なるほどなぁ。

結果、NHibernate のソースの僅かな修正で対応できたことを考えると、上記の NHibernate 側の態度は性急すぎだったと思う。

また、NHibernate 側には、Mono サポートに対する拒絶に近いものがあったようにも思う(もっとも、Mono 上で NHibernate を利用する人が、どれほどいるだろうかと考えると、それもしょうがないことかな、とも思う)。

ま、それは置いといて、手元にあった、2.1.0.Beta1 のソースに、修正パッチを適用し、
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using NHibernate.Mapping;
using NHibernate.Util;

namespace NHibernate.Cfg.MappingSchema
{
  [Serializable]
  public abstract class AbstractDecoratable : IDecoratable
  {
    private static readonly IDictionary<string, MetaAttribute> EmptyMetaData = new CollectionHelper.EmptyMapClass<string, MetaAttribute>();

    private IDictionary<string, MetaAttribute> mappedMetaData;
    private IDictionary<string, MetaAttribute> inheritableMetaData;

    [XmlIgnore]
    public virtual IDictionary<string, MetaAttribute> MappedMetaData
    {
      get
      {
        if (mappedMetaData == null)
        {
          CreateMappedMetadata(GetMetadataField());
        }
        return mappedMetaData;
      }
    }

    [XmlIgnore]
    public IDictionary<string, MetaAttribute> InheritableMetaData
    {
      get
      {
        if (mappedMetaData == null)
        {
          CreateMappedMetadata(GetMetadataField());
        }
        return inheritableMetaData;
      }
    }
  ...
ビルド後、試してみたが、うまく動いた。

IDictionary<K,V> を型にもつプロパティに XmlIgnoreAttribute(XmlIgnore)属性の付与が必要だったわけだが、あれれ、同じく IDictionary<K,V> を型にもつフィールドには、[XmlIgnore] はいらないのか?

うーむ、不思議だ(オレが知らないだけで、全然不思議じゃない可能性大だが、ちなみにこれは本当に本家 .NET でも実行時に例外は発生しなかったのかいな)。

ということで、本家 .NET 上で動作して、Mono 上で動作しなかったとしても、必ずしも Mono の不具合とは限らない、こともあると覚えておこう。

また、すでに SourceForge.netのNHibernateプロジェクトページから、対応済みの 2.1.0.GA がリリースされている。試してみたが、もちろん、うまく動いた。ありがたい。

0 件のコメント:

コメントを投稿