クラスの動的再ロード処理
seasarとかでHotdeployというのをやっているのでseasarのコードをSVNから落としてきて勉強中。
下のコードとかからコードを追いつつ、自分でも適当にコードを作ってみて試していたわけですが
すでにわかりやすい解説がWebにあったのね(そりゃそうか)
http://www.nminoru.jp/~nminoru/java/class_unloading.html
これぐらいの解説を何回かに分けてやろうかなぁと思ってたわけですがWebバンザイ
知り合いから参考になるリンク先を貰った
http://www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic.html
jaxenのXPathパーザーのバグ
XPath評価エンジンjaxenに長らく見つかっていなかった XPath 1.0 仕様書に則っていなかったバグが見つかったようで。
http://jira.codehaus.org/browse/JAXEN-193
jaxenはDOMやJDOM,XOM,dom4jとXPath 1.0 式を使用して結果を取ってくるライブラリ(XPath 2.0 サポートはする気が全くないみたい)で、http://jaxen.org から取得できます。
また、maven1やmaven2のリポジトリにも登録されているはずです。
ちなみにjaxen.orgは説明やリンク先が間違っている、ソースzipあると書いてあるのに実際には無いなんてことがしょっちゅうあるので注意。落ちてることも。(いい加減もうCVS無いのだからCVSへのリンク削除したらいいのに・・・)
問題のバグですがこれは 文字"*"の構文解析がXPath 1.0 の 3.7章「Lexical Structure」の下記の内容に従っていなかったと見られる物です。
原文:http://www.w3.org/TR/xpath#exprlex
If there is a preceding token and the preceding token is not one of @, ::, (, [, , or an Operator, then a * must be recognized as a MultiplyOperator and an NCName must be recognized as an OperatorName.
If the character following an NCName (possibly after intervening ExprWhitespace) is (, then the token must be recognized as a NodeType or a FunctionName.
If the two characters following an NCName (possibly after intervening ExprWhitespace) are ::, then the token must be recognized as an AxisName.
Otherwise, the token must not be recognized as a MultiplyOperator, an OperatorName, a NodeType, a FunctionName, or an AxisName.
日本語訳:http://www.infoteria.com/jp/contents/xml-data/REC-xpath-19991116-jpn.htm#exprlex
前にトークンがあり、そのトークンが @、::、(、 [、, または Operatorではない場合には、* を MultiplyOperator として認識しなければならい (must)。また NCName を OperatorName として認識しなければならない (must)。
NCName の後に続く文字 (ExprWhitespace を間に挟む場合もある) が ( の場合は、そのトークンを NodeType または FunctionName として認識しなければならない (must)。
NCName の後に続く2つの文字 (ExprWhitespace を間に挟む場合もある) が :: の場合は、そのトークンを AxisName として認識しなければならない (must)。
上記以外の場合はトークンを MultiplyOperator または OperatorName、NodeType、FunctionName、AxisName として認識してはならない (must)。
上記の"*"に関するところだけを抜き出すと、@*や、::*、(*、[* や Operator(andやorなど)*の場合は"*"をMultiplyOperator(算数の掛け算記号と考えて貰うと良いです)として認識してはならないとのことです。この場合、"*"は何に該当するかというと3.7章に書いてあるBNF式を追っていくと、NameTestに該当します。まぁ確かに@*などはNameTestなので掛け算と思われたらたまらんわけですが。
これを踏まえ、jaxen-193によるとjaxenで下記のXPath式を処理しようとするとSAXPathExceptionが発生します。
(SAXPathはjaxenの内部で使用されるXPath構文解析エンジンの名前です)
/*[ * or processing-instruction() ]
/*[ processing-instruction() or * ]
修正に結構手間取っていてだれか妙案はない?とMLにて話が出ており(http://archive.jaxen.codehaus.org/dev/14904761.1192805692397.JavaMail.haus-jira%40codehaus01.managed.contegix.com)、一応パッチらしき物は出ていますがまだコミットはされていない模様。(SVNのログ見る限り。http://fisheye.codehaus.org/changelog/jaxen/trunk/jaxen?todate=1209261370459)
実際のコードを見ると分かるのですが"*"は単にどのような場合でもSTARというトークンに分類されており、この辺りが問題ではないかと思われます。いつ直るのかなぁ・・・
surefire 2.4.3 リリース
というわけで surefire 2.4.3 がリリースされました。
http://maven.apache.org/plugins/maven-surefire-plugin/
リリース文によると additionalClassPath についての文書が追加されたようなので以下訳文。
-
-
- -
-
元:http://maven.apache.org/plugins/maven-surefire-plugin/examples/additional-classpath.html
Additional Classpath Elements
もし Surefire を実行する際にクラスパスに対して何か(リソースや特別なjarファイルなど)追加したいなら、一般にはdependencyとしてクラスパスに追加することを勧めます。共有するJarファイルをあなたの組織のプライベートなリモートレポジトリにデプロイすることを考えてください。
しかし、どうしてもクラスパスにカスタムしたリソースやJarファイルを追加したいなら additionalClasspathElements 要素を使用できます。
Additional Classpath Elements
If you need to put more stuff in your classpath when Surefire executes (e.g some funky resources or a container special jar), we normally recommend you add it to your classpath as a dependency. Consider deploying shared jars to a private remote repository for your organization.
But, if you must, you can use the additionalClasspathElements element to add custom resources/jars to your classpath.
<project> [...] <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <additionalClasspathElements> <additionalClasspathElement>path/to/additional/resources</additionalClasspathElement> <additionalClasspathElement>path/to/additional/jar</additionalClasspathElement> </additionalClasspathElements> </configuration> </plugin> </plugins> </build> [...] </project>
あまりたいしたことは書かれていないような。
ナビゲーションが面どい
所用があって日記の関連記事の前回・次回ナビゲーションを各日記に一つ一つ追加していったのだが作業がめんどい。どーにかならんのか。
IDリンクの場合リンクのエイリアス文字列も設定できないっぽいし。ううーむ
maven ant の落とし穴
※maven2 ではなく maven1 です
maven1 では、 maven ant で project.xml から ant の build.xml を作成してくれる便利なプラグインがありますがこいつがどうにもこうにも信用できません。
■駄目なところ1
maven1 にはプロパティとして
- ~/.maven/build.properties
- 各プロジェクトの build.properties
- 各プロジェクトの project.properties
の3種類のファイル中のプロパティをロードする仕組みがあるのですが、作成した build.xml はproject.propertiesを読んでくれません。
■駄目なところ2
maven1 は、 maven.compile.target など、maven.compile系でjavacを実行するときの各種設定ができます。
なのに作成されたbuild.xmlはこの値を全く参照しません
■駄目なところ3
同様に maven.proxy 系も全くみません。しかも、元々参照していたのを最新コードでは参照しないように変更されているという・・・
などなどそこら中に落とし穴が空きまくっている状態なので maven ant を行う場合はご注意を。
まだ maven1 の ant プラグインを落としてきてローカルで各種プロパティを見るように修正した方が使い勝手がよいかも・・・
maven-surefire-plugin についての覚え書き
とりあえず maven-surefire-plugin のバージョンが 4.5-SNAPSHOT で、かつ fork=once と、junitを使用している場合だけ調査
maven surefire プラグインのソース構造
このエントリで必要なもののみを記述
surefire ├mavne-surefire-plugin │└SurefirePlugin ├maven-surefire-booter │└SurefireBooter ├maven-surefire-api │└Surefire └maven-providers ├surefire-junit │├JUnitDirectoryTestDuite.java │└JUnitTestSet ├surefire-junit4 │├JUnit4DirectoryTestDuite.java │└JUnit4TestSet └surefire-testng
maven surefire プラグインの動作順番
フォークする前処理
- SurefirePlugin でpom中の各種設定値を取得
- SurefireBooter の各種フィールドに上記の値を設定
- テンポラリフォルダに surefirebooter*.jar というファイルを作成する。この中身はMANIFEST.MFのみ。
- MANIFEST.MFの中身は クラスパス設定と、SurefireBooterをMain-Classとすることが書いてある
- クラスパス設定は下記の順で追加される
(※${project.testClasspathElements}が使用される。read only指定のため差し替え不可?) 指定があった場合:${project.build.outputDirectory}の替わりに 指定があった場合:${project.build.testClassesDirectory}の替わりに
- このため、dependenciesとaddClasspathElements中に同じクラスが存在すると、dependenciesの方が勝ちます
- テンポラリフォルダに surefire*tmp というファイルを作成する。この中身は各種プロパティが設定されている。プロパティはフォーク前の各種OSやJavaのプロパティ値など
フォーク
- コマンドラインから javaコマンドを使用して先ほどのsurefirebooter*.jarを実行
- 各種プロパティをsurefire*tmpからロード
- SurefireBooterからSurefire#runを実行
Surefireでのテストクラスのロード処理
- ベースディレクトリとしてtestClassesDirectoryを用い、そこからディレクトリを辿って
や の対象となっているクラスをリストにする - ※ディレクトリ探索クラスはdependenciesの記述により下記のように変更されます
- testNGもしくはtestNGArtifactNameがある場合:TestNGDirectoryTestSuite
- maven-junit-plugin のバージョンが4から始まる場合:JUnit4DirectoryTestSuite
- その他の場合:JUnitDirectoryTestSuite
- ※ディレクトリ探索クラスはdependenciesの記述により下記のように変更されます
- この段階でテストクラスファイルが見つからない場合処理終了。
- クラスファイルが見つかった場合、リストからテストメソッドを集める
- junit及びjunit4の場合、テストメソッドのかき集め方は下記の通り
- リスト中のクラスがTest派生の場合は通常通り
- リスト中のクラスがTest派生では無い場合、そのクラス中のstaticではなく、returnTypeがvoidで、かつメソッド名の最初4文字が"test"のメソッドがテストメソッドとしてロードされる。
- suite() の扱い
- suite() を含むがTestクラス派生でない場合maven-junit-pluginの
を4から始めておけば集めてくれる。3の場合は駄目 - suite() を含むクラスがTest派生の場合はバージョンが4以降でなくてもsuiteメソッドが使用される。
- suite() を含むがTestクラス派生でない場合maven-junit-pluginの
- junit及びjunit4の場合、テストメソッドのかき集め方は下記の通り
テスト実行
- JUnitRunnerを使用して先ほど集めたテスト群をテスト実行