目次へ

NB4で「虎の穴」

JDK5.0"Tiger"の新機能をいちはやく検証,解説してくれるサイト「J2SE5.0 虎の穴」をご存知のかたも多いと思います。今回,著者の櫻庭 祐一さんとお近づきになれて,このサイトの内容をNetBeans4で実践してみようということになりました。上記サイトが出たときはTigerはまだベータ版で,リリースにあたって少し仕様が変更になったようです。それに対応してのサンプルコードの更新も櫻庭さんと相談しながらつかイポー的に教えてもらってあります。順不同で実践していくので新しいトピックほど上にくる積み上げ方式ザマス。

/続・「メタデータは魔法の言葉」/「メタデータは魔法の言葉」/


続・「メタデータは魔法の言葉」

再掲:オリジナルはこちら

最初の試みがいい感じで行ったので,実践を続けましょう。自動生成したソースファイルで作るプロキシクラスとファクトリクラスを利用するクライアントAnnotationSampleClient2をプロジェクトに導入する。要はファイルのコピペだ。これはNB4で新しくお目見えの「Favorites」ウィンドウを使うとラクである。

「Favorites」ウィンドウはデフォルトでは出てきていないかも知れない。そのときはメニューバーから「Window」->「Favorites」を選ぶと,「Projects」や「Runtime」などのウィンドウと同じところに出てくる。
ルートのアイコンを右クリックして「Add to Favorites...」を選ぶと,ファイル参照画面となる。

お好きなディレクトリ(ファイルでもいい)を選ぶと,そのディレクトリ以下の構造がブラウズできるし,ファイルのコピーや消去,ディレクトリの新規作成や消去などができる。わざわざNBを引っ込めてOSのファイルブラウザで作業するのは案外煩雑なので,NB上でできるこれはなかなか助かる。ワタシの環境では「nb4works」ディレクトリをFavorites(「お気に入り」って隣のうちのムスメも「へんなことば」って言ってたぞゴルァMSJapan!)に登録してあるので,階層を掘っていって今のソースファイルを置いてある拠点のtigerholeディレクトリまでたどり着く。

「src」は「虎の穴」からダウンロードしたソースファイルを保管してある場所だ。ここからAnnotasionSampleClient2.を選んで右クリックで「Copy」...

で,プロジェクトのソースがある「src1」ディレクトリを右クリックして「Paste.」

これでAnnotationSampleClient2が今のプロジェクトソースディレクトリにコピーされた。

マイフェイバリットツールになりそうなこの「Favorite」だが,実はこの甘い蜜には危険な落とし穴がある。これはNB4.1になって改善されたかどうかまだ試していませんが4.0というものがリリース版として世に出ている以上警告するのがワタクシの義務であると考えます。ちょっと本題からずれるけどゴメンネ。それは

ディレクトリごとのコピーペーストは絶対に行わないよう注意をよびかけています

その危険ぶりをとくと御覧いただこう。「Favorite」 ウィンドウ上に,こんな構造のディレクトリがあるとする。file1とfile2を抱えるsubfolder1を,親ディレクトリのfolder1下にコピーしたい。よくあることである。バックアップなど取りたい場合である。当然,このように「subfolder1」ノードをコピーして・・・

親の「folder1」上でペーストをかますであろう。

すると・・・

オーイ

危険すぎる!あまりに危険だ!これはバグというべきだろうかやはり。それとも仕様なのかッ!?あとでNetBeans.ORGにブウタレておきます。

すみません。本題に戻ります。このように危険をはらんだスリリングなFavoritesウィンドウですが,AnnotationSampleClient2を実行する前に,JDKのプロパティファイルを修正しておく必要があるという,ここの実践にもとても役立ちます。FavoritesにJDKのディレクトリを登録してしまえばよいのです。

で,ディレクトリjre/libと降りて行き,「ogging.properties」を探し出してダブルクリックすれば,NBのエディタ上で編集できるのです。

かなりOS環境に近くなっていますねNB4!ディレクトリごとのコピペさえ行わなければナッ!こうしてAnnotationClient2を実行してみましょう。

右クリックで実行するだけでよいのです。結果が

あれ?

ちょっと,ログ出力の順番が,オリジナルのコンソールウィンドウのスクショと違いますネ。

ええもちろんワタシもこの状態でコンソールからやってみました

c:¥nonidata¥nbrcworks¥metadatapro3¥build¥classes ディレクトリに下りていって,

java -classpath . AnnotationSampleClient2

とやればいいんですね。

すると,オリジナルどおりの順序で出力が得られました

さて,NBでのこの結果はいいのでしょうか。単に出力速度にバラつきが見られたというだけのことでしょうか。それともNBがなにかスカポンタンなことをやらかしたのでしょうか。どう思われますかチェリ〜。


「メタデータは魔法の言葉」

オリジナルはこちら

まず,ページの「おわりに」にあるサンプルコード「Metadata.zip」をダウンロードする。これを展開して,その中から以下のファイルおよびディレクトリを適当な場所にコピーする。

AnnotationSample.java
AnnotationSampleClient.java
jpディレクトリ

わたしは,tigerhole/src1というディレクトリにこれをコピーした。

それからNetBeansでメニューバーから「File」->「New Project」を選択し,新規プロジェクト作成ウィザードを立ち上げる。
プロジェクトの種類として,「General」->「Java Project with Existing Source」を選択,次に進む。
Sourceのあるフォルダに,このtigerhole/src1を指定。
プロジェクト名はmetadatapro3にした。3にしたワケはその前に2回ほど失敗しているのヨホーホホホホホー。

このような構造のプロジェクトが出来上がる。

さて,JDK5.0のリリースに伴い,以下のコードを修正する必要がある。と教わったのヨ。

static インポートの仕様の変更による。
beta2 ではenum も static インポートで記述できたが,リリース版 ではそれができない。

と教わったのヨ(つかそんな理由がのに子に思いつくわけがないと賢明な読者諸兄は思っておられるに違いないのでいちいちことわらないことにシマス)。

AnnotationSample.javaのコード

まず,インポート宣言。

前: import static jp.gr.java_conf.skrb.annotation.LogLevel.*;
後: import jp.gr.java_conf.skrb.annotation.LogLevel;

それから,metadataのvalueの設定のところ。

前: @Log(value = INFO)
後: @Log(value = LogLevel.INFO)

前: @Log(value = FINE)
後: @Log(value = LogLevel.FINE)

これで,AnnotationSample.javaのソースエディタからは,エラーを示す赤線が消える。アノタれているアットマークの緑もすがすがしく,NB4がJDK5.0に対応していることがわかる。

AnnotationClient.javaを実行してみる。もちろん「Projects」ウィンドウ内で「AnnotationClient.java」ノードを右クリックして「Run File」を選ぶだけ〜。

このように主婦のワタシでも実行できました。

つぎはjavadocの実行である。それにはまずカスタムDoclet(javadocの作り方を書いた指針だヨ。普通ただjavadocコマンドをカマすと標準のDocletが使われるんダ)であるLoglet.javaを以下のように編集する必要がある。

extractLogLevel メソッドの変更である。
それってどこにあるのッ!?とソースファイル中を血眼で探す必要はないんだヨ。このように「Projects」ウィンドウから,extractLogLevelメソッドのノードを探す。このノードをダブルクリックすれば,ソースファイルの該当部分にカーソルが飛ぶんダ!

そこで編集。

前:
    private String extractLogLevel(AnnotationDesc annotation) {
        AnnotationDesc.MemberValuePair[] members = annotation.memberValues();

        for (int i = 0; i < members.length; i++) {                
            if (members[i].member().name().equals(LOG_VALUE)) {
                return members[i].value().toString();
            }
        }

        return null;
    }

後:
    private String extractLogLevel(AnnotationDesc annotation) {
        AnnotationDesc.ElementValuePair[] members = annotation.elementValues();

        for (int i = 0; i < members.length; i++) {                
            if (members[i].element().name().equals(LOG_VALUE)) {
                return members[i].value().toString();
            }
        }

        return null;
    }
 

これはリフレクションでAnnotaion の情報を保持するためのクラス名が変更されたことによる(偉そうだのに子!ガキの遣いだのに子!)

さて,このLoglet.javaはコンパイルしてクラスにしておく必要がある。当然。だがこのままだとNetBeansが

パッケージimport com.sun.javadocは存在しません

と言ってくる。

おまへSun様の名前がついててjavadocなんていうお馴染みの名前のパッケージが存在しねえはねえだろ

といいたいところだがこれは他の環境においても,以下のアーカイブにクラスパスを通すことが必要なようなのだ。

C:¥jdk1.5.0¥lib¥tools.jar

これには,プロジェクトmetadatapro3のプロパティを設定する。「Projects」ウィンドウで,「metadatapro3」のノードを右クリックして「properties」を出す。

「Compiling Sources」の設定画面を出し,クラスパスに「C:¥jdk1.5.0¥lib¥tools.jar」を追加する。「Add JAR/Folder」のボタンをクリックすると,ファイル参照画面になるので,該当のファイルを探して選択すればよいのダ。

これで,「Project」ウィンドウの「Loglet.java」ノードを右クリックして「Compile file」を選び,コンパイルすればヨヒ。

さあjavadocコマンドだ。NetBeansでは,右クリックして「Generate Javadoc for Project」を選ぶことができる。

これで実行されるのは,プロジェクトに自動生成されるbuild.xmlファイルに書かれているjavadocターゲットだ。build.xmlはまあいわゆる隠しファイルのようなもので「Project」ウィンドウからは見えない。「Files」ウィンドウを出す必要がある。

build.xmlファイル,実はその正体はbuild-impl.xmlを呼び出しているだけである。こちらのbuild-impl.xmlのほうにNetBeansで自動記入された内容がズラリと書かれている。それを編集したい場合はチョクで手をつけずに,build.xmlのほうで同名ターゲットをオーバーライドせよというのである。
javadocターゲットはこのように書かれている。

ええ,途中でバッツンと切ってあります。要するにめんどくせえことが書かれているということだけを示したかったのです。
まず,javadoc-buildというターゲットをヤリます。これがjavadocタスク本体をヤルことに該当します。${dist.javadoc.dir}は他でdistというディレクトリに指定されています。それを作って,あとはdestdirのsourceのnotreeの・・・というコマいオプションを指定することになりますが,これはプロジェクトの「Properties」で設定することになります。

これがいま現在のmetadataprop3で,独自のDocletを使うわけだから指定を全部はずしました。たとえば,「Class Hierarchy Tree」 の欄にチェックを入れると,上のjavadocタスクのnotree=のオプションが変わるという具合です。
ちなみに,これはプロジェクト内の全パッケージ・全クラスについてのJavadocを作ることになっています。

ターゲットjavadoc-browseは,上のProperitesウィンドウで「Preview Generated Javadoc」がオンになっている場合,Javadoc作成のコマンド実行後自動的にブラウザを立ち上げて作成したJavadocを見る,というタスクです。

そして,ターゲットjavadocはこれらを順にヤレ,という設定になっているのです。

そこで,build.xmlで,このターゲットjavadocをオーバーライドすることにした。

 まず,カスタムDocletを指定すると,もともとのdestdirつまり,コマンドラインだとオプションフラグ -d を指定してはイケナクなるようだ。エラーになる。他のオプションもダーと消した。
 カスタムDocletを指定するだけでは,いかに同じプロジェクト内にあっても,Antはbuild/classesディレクトリに生成されるLoglet.classを見つけてはくれない。あまり勤勉でない蟻野郎だ。キリギリスに負けるんじゃないだろうか。とにかくこのように,docletタグにpath属性を指定してやる必要がある。
 また,とにかく AnnotationSample.javaをヤッてくれ,というのを指定するのにどこにそれを入れるのかも結構迷ったが,これでよいようだ。

これで,プロジェクトを右クリックー!「Genereate Javadoc for Project」!・・・BUILD SUCCESSUFLと出るが,生成するはずのAnnotationProxy.javaとAnnotationFacroty.javaが,生成されない。フォルダをリフレッシュしても,プロジェクト中のどこを探しても見つからない。

プロジェクト中のどこを探しても。まさかプロジェクト外にあるのか?

あった。

検索ワン公を放ってみる。テキストファイルへの入力すらおぼつかないCPUパワーを食いやがって,しかしヤツはそいつらを咥えて戻ってきた。このワン公あまりかわいくはない。GIMPの犬らしい不明な動物のほうがずっとかわいい。もちろんカメ・・・ああ「カメレオン観察日記」も最近書いてないな・・・もちろん見るたびにかわいくてグニャな気分になっているのだけれど・・・しかしワン公とにかくよく探してきた。それは「c:¥nb4」すなわちNetBeansIDEをインストールした直下にあったのだ。

しかし,とにかくファイルは自動作成された。これはつまり,Loglet.javaという,Doclet指定ファイルでファイルの自動作成を指示しているためだ。とりあえずこの段階で櫻庭さんにメールを出してみた。櫻庭さ〜ん。そろそろチェリーって呼んでいいですかー。そのチェリーの教えてくれたところによると,Loglet.javaのcreateProxyメソッドとcreateFacoryメソッドに,ファイル作成を指定する場所があるので,そこにファイルパスに関する情報を付加シナサイということだった。

まず,createProxyメソッド。

 private void createProxy(ClassDoc cls) throws IOException {
        
        String directory = System.getProperty("nandest");
        String proxyName = directory + "¥¥" + cls.name() + "Proxy.java"; 

...以下省略。プロパティとしてたとえば「dest」を指定し・・・と教えてもらったのだがNetBeansがもしdestというパラメータを他に持っていてバッティングなどしたら困ると思ったので独自の名前"nandest"にした。なんですと〜。という。

createFactoryメソッドも同様だ。

 private void createFactory(ClassDoc cls) throws IOException {
        String directory = System.getProperty("nandest");
        String factoryName = directory + "¥¥" + cls.name() + "Factory.java";

このように,プロパティを取得させるようにしておいて,そのプロパティはbuild.xml中の蟻targetで指定せよとのこと。

こんなやり方知ってた?のには全然知らなかったァ〜。世の中まだまだたくさん,学ぶべきことはあるな!

とにかく,これで「Generate Javadocs....を実行する。結果は出力ウィンドウに・・・

さらに,生成ファイルは・・・

いぇ〜!ちゃんどできたゼッ!みなさんもグラフィカルに虎の穴を実践してみませんか!?