HibernateでNoSuchMethodErrorが発生する問題

Struts + Hibernate Ver3を用いたWebアプリケーション実装中、特定のページの特定のユーザのみエラーが発生し、ページが表示されない現象に見舞われました。

ログを確認してみると、

java.lang.NoSuchMethodError: org.hibernate.hql.antlr.HqlBaseParser.recover(Lantlr/RecognitionException;Lantlr/collections/impl/BitSet;)V
が発生しておりました。

しかし、ググってもなかなか解決方法までたどり着けないんですよね。

日本のサイトで唯一情報源に成り得るのは、守破離 - Hibernate 3.2.1.gaでJPQL解釈時にNoSuchMethodErrorで落ちる事の対処法くらいでした。

(Googleを見るとHibernateネタは日本語サイトより中国語サイトの方が多いようなので)知り合いの中国人にも頼んで調べて貰ったのですが、HQL(Hibernate Query Language)の文字列において「from」を「form」の様に誤字すると発生するという情報くらいしか得られませんでした。

しかし、英語サイトも含めて調べていくと原因と対処法がやっと分かってきました。

Note to self - java.lang.NoSuchMethodError: org.hibernate.hql.antlr.HqlBaseParser.recover
Java Programming - hibernate issue

上記に挙げたサイトの情報をまとめる限り、やはり、HQLの構文に何らかの問題が存在するからなのです。

String HQL = " from User user where user.userId ='" + userId+"' and where user.fname ='" + fname +"' and where user.lname='" +lname + "'and where user.email='" + email +"'"; List result = session.createQuery(HQL);
の場合、「lname + "'and」の場所に注目していただけると理由が分かると思います。 「'」(シングルクォーテーション)と「and」の間に半角スペースが抜けているんです。

しかし、今回、私が体験した場合、もっと根が深く気付きにくい問題でした。
例えば、以下のようなコードです:

String id = "darekanoid";
String pass = "darekanopass";
// ↑上は説明の都合上
String HQL = " from User as user where user.userid = :userId"
                + "and user.password = :password";
Query query = session.createQuery(HQL);
query.setString("userId", id);
query.setString("password", pass);
List result = query.list();

HibernateでPreparedStatement(もどき?)を実施する場合は以上のようなソースコードになりますが、この場合、HQLの2行目が「"and」となっており、一行にまとめると「 from User as user where user.userid = :userIdand user.password = :password」になることでエラーが発生します。
本来なら必要ないと思われるHQLを2行に分割した理由は、開発中のプログラムのコーディング規約による制限があったからです。
ただ、エラーが発生しない場合もあるんですよ。
例えば、「String id = "aregeid "」みたく右側にユーザIDの右側にスペースが詰められている存在する場合です。CHAR型のデータを用いると、特定の文字に見たいない場合はスペースで補われますし、そのようなユーザIDを用いて検索するとNoSuchMethodErrorが発生しないようです。

この問題を解決する方法は、2点あります。

1点目は、antlr.jarのバージョンを2.7.6以上にする。
java.lang.NoSuchMethodError: org.hibernate.hql.antlr.HqlBaseParser.recoverが発生する原因は、HQLが正しくないことが原因です。antlr.jarは文字列の正規表現や文字列から数値への解析に用いられるJARだそうです。Hibernate Ver3では正しくないHQLを回復させるためにantlr.Parser.recover()メソッドを用いようとしているもとの思われます。しかし、antlr.jarが古い環境では読み込めず、今回のようなエラーが発生してしまうと考えれば納得が行きます。
もし、antlr.jarを新しいバージョンに変更できる環境であるならば、2008/02/11現在、Antlr Ver2の最新版である2.7.7に置き換えると良いと思います。

2点目はHQLが正しいか確認することw
今回、開発がある程度進んでしまった為、安定性を保証する為にantlr.jarを入れ替えることができなかったため、こちらの方を選択しました。
不思議なことに、"and"のように「and」の前にスペースがなくともなぜか無事に取得できる場合があるんですね。
HibernateはコンソールにHQLが正しいか出力する方法が存在します。開発中は、コンソールを確認し、HQLに問題が発生しないか確認する必要があると思います。

ぶっちゃげ、ちゃんと見てなかったからこのような事態が発生し、解決まで時間が掛かったということですがorz
そんなわけで、同じ悩みで開発が止まっている人の参考になれば( ̄∇ ̄)ノ♪