所変わればエラー変わる

NetBeans 6.0.1のプロジェクトにコンパイル済みの自作のアノテーションのクラスをライブラリィとして食わせると

Hoge.java:31: 注釈 com.hoge.FooAnotation に <clinit> がありません。

とエラーが出てそれ以上ビルドが進まない。
といえばクラスの初期化コードだが、Javaの場合アノテーションはインタフェース扱いであり、クラスの初期化コードは関係無いと思うんだが。

ひょっとして、属性のデフォルト値の設定に問題があるのか? でも一般的なビルドでもEclipseでもこんなエラー出たことないしな。

追記:

原因が判明した。やはりがあった。
アノテーションの属性には規定値(default)を設定するのだが、その規定値を定数とするために、内部にスタティックなフィールドを定義していたのだ。

@Documented
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FooAnotation {
    public static final int ITEMINDEX_NAN = -1;
    〜
    int ItemIndex() default ITEMINDEX_NAN;

当該の行を他の定数クラス等に移動するとビルドが通った。

さて、ここでEclipseのビルドとNetBeansのビルドで差が出たわけだが、NetBeansのビルドはjavacをAntタスクで起動しているだけなので、Eclipseコンパイラが何か技を使っていると見るべきだろう。(javacのバグという確率も0%ではないが)

もし仮にEclipseのコンパイルが技を使っているとすれば、Eclipseでビルドしたクラスが他で動かないということになる訳で(事実NetBeansではビルドすら通らない)、とってもまずいと思うのだが。

既存のクラスの .form ファイルを生成できますか?

できません。
既存のクラスの .form ファイルを生成できますか? - 日本語 NetBeans ユーザー FAQ

ということはNetBeans(Matisse)で編集したJFrameクラスを他のIDEに持っていくことはできても、他のIDEで編集したそれをNetBeansで取り込むことはできない、ということ。 がっかりだ。(対象のバージョンは NetBeans 3.6, 4.0, 4.1, 5.0, 5.5 となっているが6.xでも同じなのだろう)

JavaGUIビルダを見分ける際の基準として「IDEに依存した独自コードを吐くか否か」というのがあるが、例え独自コードを吐かなくとも同期が必要な他のファイルに依存している(この場合は.form)のであれば同じだ。

一応、既存のクラスから.formを生成するFormGeneratorなるものが有志の手で用意されているようだが、そうではなくこのような機能を最初からIDEに取り込むか、EclipseのVEの解決策のようにあくまで通常のJavaコードを吐くようにGUIビルダが動かないと、いつまでたってもEclipseからの移行は進まない。(Matisse自体の出来が良いので、最近では重いEclipseを嫌って最初からNetBeansを使うチームもいるようだが)

また、今や「旧時代のIDE」と評されることもあるVisual Studioだが、GUIビルダの出来と使い勝手に関してはまだまだ先んじている。(ここの出来の良さだけでお金を払うユーザがいる)この辺は最近では差は縮まったものの、最初からIDEを使うことを前提にしているものと、そうではないものとの間に横たわる巨大な溝を感じると共に、SwingベースのGUIビルダを作る大変さを見せ付けられた。(EclipseのVEの開発が滞っているのが解る気がする)

好みの問題もあるが、エディタやダイアログの反応の悪さとフォント描画の扱いが良くなるだけで※、かなり印象変わると思うんだけどな -> NetBeans 6

スクリーンショットを見る限りではMac上でのフォントのレンダリングは美麗だ。Windows&日本語フォントだと汚いのかも。

とは言うものの

NetBeans6のプロジェクトウィザードから生成したSwingのデスクトップ(C.R.U.D)アプリケーションは

  • Java Persistent API
  • Java Beans Binding (JSR-295)
  • Swing Application Framework (JSR-296)

これらを組み合わせて作られている本格的なデータバインディング/データアクセスアプリケーションである。
スクリーンショット(Windows XPにて。JVMオプション"-Dawt.useSystemAAFontSettings=on"指定)

(これはあくまで一例。接続するデータベーステーブルのメタデータにより画面内容は変わる)
これは間違いなく.NET WindowsForms+ADO.NETの組み合わせでVisual Studioが自動生成する同様のアプリケーションを意識して作られており、その場でデータベースに接続して必要なカラムを選んでいく行程も含めて、実際それにかなり近づいていると言えよう。
未確定要素となり得る、次のJSDKで導入される予定のJSRを2つも(295, 296)含んでいることを考慮に入れても素晴らしい出来だ。

あくまで定性的な評価ではあるが、ソースコードを見れば何をやっているかが解る点、GUIコンポーネントの動作が軽い点に関してはこちらの方が上だろう。特にJava6におけるJTableクラスは、.NET WindowsFormのDataGridViewの重さに辟易したプログラマには驚く程軽く感じるだろう。

前言とっとと撤回

好みの問題もあるが、エディタやダイアログの反応の悪さとフォント描画の扱いが良くなるだけで※、かなり印象変わると思うんだけどな -> NetBeans 6

スクリーンショットを見る限りではMac上でのフォントのレンダリングは美麗だ。Windows&日本語フォントだと汚いのかも。

Java6環境を使用できるのであれば、アプリケーションの実行時にも指定したJVMオプション"-Dawt.useSystemAAFontSettings=on"をNetBeansの設定ファイル(/etc/netbeans.conf)に指定することで、かなり印象を変えることができる。

# ${HOME} will be replaced by JVM user.home system property
netbeans_default_userdir="${HOME}/.netbeans/6.0"

# Options used by NetBeans launcher by default, can be overridden by explicit
# command line switches:
netbeans_default_options="-J-client -J-Xss32m -J-Xms32m -J-Xmx255m -J-XX:PermSize=32m -J-XX:MaxPermSize=200m -J-Xverify:none -J-Dapple.laf.useScreenMenuBar=true -J-Dawt.useSystemAAFontSettings=on"# (Note that a default -Xmx is selected for you automatically.)

# If you specify the heap size (-Xmx) explicitely, you may also want to enable
# Concurrent Mark & Sweep garbage collector. In such case add the following
# options to the netbeans_default_options:
# -J-XX:+UseConcMarkSweepGC -J-XX:+CMSClassUnloadingEnabled -J-XX:+CMSPermGenSweepingEnabled
# (see http://wiki.netbeans.org/wiki/view/FaqGCPauses)

# Default location of JDK, can be overridden by using --jdkhome :
netbeans_jdkhome="C:\java\java6"

# Additional module clusters, using ${path.separator} (';' on Windows or ':' on Unix):
#netbeans_extraclusters="/absolute/path/to/cluster1:/absolute/path/to/cluster2"


フォントのサブピクセルアンチエイリアス描画は、環境によっては暈けた、フォーカスの合っていないような印象を与えるので好みもあるだろうが、一般的な液晶ディスプレイを使用している場合はこちらの方が綺麗に感じるのではないだろうか。

2/21:修正

NyaRuRuさんにコメントでご指摘頂いた通りだが、上のスクリーンショットは"サブピクセルアンチエイリアス"ではなく、"アンチエイリアス"を指定した結果である。
Java6ではVMオプションパラメタを"-Dawt.useSystemAAFontSettings=lcd"にすることでサブピクセルアンチエイリアスを有効にできるが、その機能はWindowsXP以降のWindowsプラットホームの場合はClearTypeに依存するので、スクリーンショットのように小さいポイントの日本語フォントでは(NetBeansのエディタにおけるデフォルトの論理フォントである"Monospaced"は"MSゴシック"にマッピングされていると思われる)通常のアンチエイリアスのようなエッジの緩い描画にはならない。

HttpURLConnectionとCookieサポートのちぐはぐさ

以前のエントリで、Java6では永続Cookieの読み書きサポートが追加されたと書いたが、これはあくまでJava Plugin環境又はJava Web Start環境での話であり、一般的なSwingアプリケーションでは以下のコードのようにデフォルトのCookieManagerを生成して取得できるCookieHandlerではインメモリ上で扱うCookieしか使用できず、肝心の永続化Cookieはサポートされない。

static Map> cookies = new HashMap>(); 
private static void retrieveCookie(URL url) {
    cookieManager = new CookieManager();
    CookieHandler.setDefault(cookieManager);
    CookieHandler handler = CookieHandler.getDefault();
    cookies = handler.get(url.toURI(), cookies);
}
.... 
retrieveCookie(new URL("http://d.hatena.ne.jp/Kazzz/"));
....
アプリケーションを停止すると取得したCookieは保存期間に関わらず消えてしまう

結局は自らCookieシリアライズする必要があるのだが、これに関しては、かの「Java in the Box」の櫻庭さんがITProへの記事で非常に詳しく採りあげているので、これを参考にするのがよさそうだ。(Cookieシリアライズ自体に問題がありそうだが)

「Java SE 6完全攻略」第42回 Cookieを扱う その3 - ITpro > Development >Java技術最前線

がしかし、普通にシリアライズされた永続化Cookieの読み書きの参照実装を入れなかったのは何故なのだろう。セキュリティホールの原因になることを回避?(永続化クッキーのメカニズムを実装すべきではない? ) ブラウザ依存する実装だから? はなはだ疑問だ。

追記:とはいえ、.NETもIEのCoookieストアから永続Cookieを引っ張り出してくるにはWindows APIの力を借りる必要がある。( InternetGetCookie


※櫻庭さんが寄稿された一連のJava 6の記事は非常に貴重で参考になる。
Java技術最前線/櫻庭祐一 - ITpro > Development >Java技術最前線

Relics of Struts

J2EEの枠組みに嫌気が差して別な場所で遊んでいたのだが、いざ戻ってみたららいつのまにかJ2EEはこんな状態だ。(BEAの買収はシンボリックな出来事だった)

それでもStrutsだけはどこにでも存在する。名を変え実装を変えて、企業システムの中心にどっかりと根を張っていたりする。償却のことを考えれば今後数年はこのままだろう。

次にこれを置き換えるのは何だろう。