読者です 読者をやめる 読者になる 読者になる

【Java】JAXBとxmlnsとns連番バグ?

昨日リリースしたシステム、早速障害が発覚。 スリーストライクからの最後のチャンスを得てやっと品質向上終わって解放されると思ったのに。

といっても、今回は極めて運が悪い。 誰も悪くない。悪くないが、さて、上客にどう伝えるものか。

XML NameSpace

XMLには名前空間という概念がある。

(参考)

XML名前空間の簡単な説明

色々とかいつまむと、外に定義したDTD定義を<family1:elem>みたいにプリフィクスを書いて引用できる仕組みだ。

JAXBと:ns1

JAXBは、JavaSDKが提供するメソッド一発でJavaのクラスとXMLを相互変換できるようにする便利なユーティリティ群。 すごく乱暴に言ってしまうと、XMLのO/Rマッパみたいなもの。

さてこのJAXBは色々と悪名高く、特にnamespaceのプリフィクスを勝手に「ns1」とか「ns2」とかに書いてしまう。

連番バグ?

さて、JAXBで付与する名前空間が複数ある場合、それぞれ順当に「ns1」「ns2」と割り当てていくが、 どういう訳か時折こいつらが順不同になる。 (<ns1:elem ns2:attr>になったり<ns2:elem ns1:attr>になったり)

ギッチギチに検証するDTDを与えてやればあら不思議。 いとも簡単にDTD検証から先に進めなくなってしまう。

この入れ替わってしまう現象が謎で、以下がわかっている。

  • プロセス起動する限りは同じ割り当てとなる
  • プロセス落とすと入れ替わる”ことも”ある。
  • 特定の順番に設定されることが大多数で、一度設定すると連続でプロセスを落として上げてしても別のパターンにならない?

どうにもこうにも

4年間起こらなかった。回避も検出もできる訳ないだろう。。

(2016/10/04 追記)

原因を恐らく特定したけど書くのを忘れていた。

原因

JAXBでXML→クラスにパースする場合、タグ1つにつき1つのクラスが割り当てられる。 だからいっぱいクラスがあって、それぞれ定義がまちまち。

で、担当していたシステムが、以下みたいに、参照先のnamespaceの記述順が違うクラスをいくつか持っていた。

public class Book {

    private String title;
    private Author author;

    @XmlElement(namespace="http://www.example.com/BAR")
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @XmlElement(namespace="http://www.example.com/FOO")
    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }
}
public class Author {

    private String name;

    @XmlElement(namespace="http://www.example.com/FOO")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

つまり、この2つのクラスどちらを先に読み込むかで、最初に識別するnamespaceが変わって連番の振りかたが前後する。 ふぁっく。

JAXBContext.newInstance(contextPath)の中は追っていない。やる気が起きない。