【コラム】

Java API、使ってますか?

36 JSR 308対応のコンパイラを試す

36/60

JSR 308対応のコンパイラとそのプラグイン

前回は、11月9日に公開されたJSR 308:Annotations on Java TypesのEarly Draftを元に、同仕様の概要を紹介した。JSR 308については本連載第15回でも取り上げているが、その際、開発段階にある対応コンパイラを用いて型に対するアノテーションの適用例を紹介した。

そのJSR 308対応コンパイラだが、現在の最新版はバージョン0.3.99となっており、Compiler plug-ins(Type-checking Plug-ins)で使用できるアノテーションも追加されている。今回はそれを用いて、@NonNull以外のアノテーションを使ってみようと思う。

コンパイラおよびCompiler plug-insはこのページで公開されている。まずコンパイラはファイル「jsr308-langtools.zip」をダウンロードする。これを展開するとlibtoolsディレクトリ (以下、これを[LIBTOOLS_DIR]と表記) が納められている。ビルドするにはまずmakeディレクトリにあるbuild.propertiesの32行目付近にあるブートストラップJDKの設定を、リスト1のように自身の環境にインストールされているJDKのものに変更する。

リスト1 build.propertiesを編集

boot.java.home = D:/Program Files/Java/jdk1.6.0_03
boot.java = ${boot.java.home}/bin/java
boot.javac = ${boot.java.home}/bin/javac
boot.javac.target = 6

その上でmakeディレクトリに移動し、Apache Antを用いてプロンプト1のようにビルドを実行する。

プロンプト1 コンパイラのビルド

> cd [LANGTOOLS_DIR]/make
> ant build-javac

すると[LIBTOOLS_DIR]/dist/libディレクトリにjavac.jarファイルが、[LIBTOOLS_DIR]/dist/binディレクトリにjavacコマンドが生成される。このjavacコマンドはjavac.jarを用いてコンパイルを実行するためのシェルスクリプトである。したがってシェルが使える環境ならば、[LIBTOOLS_DIR]/dist/binを環境変数PATHの最初 (インストール済みのJDKより前) に追加しておけば、javacコマンド実行時にJSR 308対応のコンパイラが呼び出されることになる。Windows環境では-jarオプションでjavac.jarを実行する (後述)。

Compiler plug-insのビルド方法は第15回で紹介したものと同様だ。「jsr308-checkers.zip」をダウンロードして任意の場所に展開し、中に含まれるcheckersディレクトリ(以下、これを[CHECKERS_DIR]と表記)に移動してApache Antを用いてビルドする(プロンプト2)。

プロンプト2 Compiler plug-insのビルド

> cd [CHECKERS_DIR]
> ant

生成されたchekers.jarに各種アノテーションが含まれているので、これをクラスパスに含めてコンパイルすればよい。

さて、Compiler plug-insには現在以下のアノテーションが用意されている。

  • @NonNull - nullを許容しない
  • @Interned - オブジェクトどうしの"=="または"!="での比較をチェック
  • Javariで提供されるMutabilityに関するアノテーション
  • IGJで提供されるMutabilityに関するアノテーション

Javari: Java with reference immutabilityでは、Mutability(変更可能性)に関する@ReadOnly、@Assignable、@Mutable、@ReadOnly、@RoMaybeなどのアノテーションが提供されている。また、IGJではJavariと同等の機能を持つ@ReadOnly, @Mutable, @Immutable, @Assignable, @AssignsFields, @Iなどが提供される。

@Internedアノテーションを試す

@Internedアノテーションは、オブジェクトどうしの"=="演算子や"!="演算子による比較を検証する機能を持つ。これらの演算子はオブジェクトの参照が同一かどうかを比較するものだが、非常に初歩的な間違いとして、これをオブジェクトどうしの値の比較に使っているケースがある。値を比較する際は本来ならばequals()メソッドを使用しなければならず、この間違いがバグの温床になってしまう。

Compiler plug-insでは、オブジェクトどうしを"=="や"!="で比較すると警告を発するようになっている(現状では例外が発生する)。そして、@Internedアノテーションを付加した型オブジェクト同士を比較する場合のみ、この警告を回避することができる。

たとえばリスト2のようなプログラムの場合、internedStr1/internedStr2/internedStr3はそれぞれ比較可能だが、normalStr1およびnormalStr2は@Internedではないため、演算子による比較ができない。

リスト2 InternedSample.java - @Internedアノテーションの使用例

import checkers.quals.Interned;

class InternedSample {
    public static void main(String[] args) {
        @Interned String internedStr1 = "foofoo";
        @Interned String internedStr2 = "foofoo";
        @Interned String internedStr3 = new @Interned String("foofoo");
        String normalStr1 = "hogehoge";
        String normalStr2 = new String("hogehoge");

        System.out.println(internedStr1 == internedStr2);   // true
        System.out.println(internedStr2 == internedStr3);   // false
        // System.out.println(normalStr1 == normalStr2);    // エラー
        // System.out.println(internedStr1 == normalStr1);  // エラー
        // System.out.println(internedStr3 != normalStr2);  // エラー
    }
}

コンパイル方法は、-typeprocessorオプションでcheckers.interned.InternedCheckerを指定してプロンプト3のようにする。Windowsのコマンドプロンプトの場合はシェルが使えないので、プロンプト4のように-jarオプションでコンパイラを実行する。

プロンプト3 @Internedアノテーションを使う場合のコンパイル

> javac -classpath [CHEKERS_JAR_PATH] -typeprocessor checkers.interned.InternedChecker InternedSample.java

プロンプト4 Windows環境でのコンパイル方法

> java -jar [LANGTOOLS_DIR]\dist\lib\javac.jar -classpath [CHEKERS_JAR_PATH] -typeprocessor checkers.interned.InternedChecker InternedSample.java

Javariの@ReadOnlyアノテーションを試す

JavariはJavaオブジェクトに対して変更可能/不可能を明示的に指定できるようにするためのライブラリである。Compiler plug-insには、Javariによる変更可能性を指定するためのアノテーションが統合された。たとえば@ReadOnlyアノテーションを指定した型のオブジェクトは、読み込み専用とされて変更することができなくなる。

リスト3では、@ReadOnlyを用いて変更不可能なStringBufferオブジェクトを作っている。この場合、roBuffは@ReadOnlyなのでappend()メソッドを用いると警告される。また、@ReadOnlyなオブジェクトを通常の(Mutableな)型の変数に代入することはできない。

リスト3 ReadOnlySample.java - Javariの@ReadOnlyアノテーションの使用例

import checkers.quals.ReadOnly;

class ReadOnlySample {
    public static void main(String[] args) {
        StringBuffer nBuff = new StringBuffer("foofoo");
        @ReadOnly StringBuffer roBuff = new StringBuffer("hogehoge");

        nBuff.append("barbar");        // OK
        //roBuff.append("piyopiyo");   // エラー

        //nBuff = roBuff;              // エラー

        roBuff = nBuff;                // OK
        //roBuff.append("piyopiyo");   // エラー
    }
}

Javariによるアノテーションを使用する場合、コンパイル時の-typeprocessorオプションの引数にはプロンプト5のように「checkers.javari.JavariChecker」を指定する。

プロンプト5 Javariによるアノテーションを使う場合のコンパイル

> javac -classpath [CHEKERS_JAR_PATH] -typeprocessor checkers.javari.JavariChecker ReadOnlySample.java

JSR 308を利用すればJavaの型に対して明示的な制限を設けることができ、それをコンパイル時に静的に検証することが可能になる。今回は用意されたアノテーションを利用したが、独自のアノテーションを作成することももちろん可能だ。JSR 308はJava SE 7に標準APIとして導入される予定となっている。

36/60

インデックス

連載目次
第60回 どうなる? 今後のJavaプラットフォーム(Java SE編)
第59回 どうなる? 今後のJavaプラットフォーム(Java EE編)
第58回 Java SE 7の要注目機能"クロージャ"はどうなるのか その6
第57回 Java SE 7の要注目機能"クロージャ"はどうなるのか その5
第56回 Java SE 7の要注目機能"クロージャ"はどうなるのか その4
第55回 Java SE 7の要注目機能"クロージャ"はどうなるのか その3
第54回 Java SE 7の要注目機能"クロージャ"はどうなるのか その2
第53回 Java SE 7の要注目機能"クロージャ"はどうなるのか
第52回 Early Draftが公開されたJSF 2.0
第51回 EJBから独立したJava Persistence 2.0
第50回 モバイルJavaの新しい潮流となるか - MSA 2.0のドラフト公開
第49回 やっぱり基本はServlet - Servlet 3.0のEarly Draftを読む
第48回 JOGLで3Dプログラミング その4
第47回 JOGLで3Dプログラミング その3
第46回 JOGLで3Dプログラミング その2
第45回 JOGLで3Dプログラミング
第44回 JARファイルを効率的にネットワーク転送するためのPack200形式
第43回 Early Draftで把握するEJB 3.1の新機能
第42回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その2
第41回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その1
第40回 リソースアダプタによる接続の仕組み
第39回 JCAを利用したシステム間接続
第38回 Java EEと外部システムの接続性を支えるJCAがバージョンアップ
第37回 Javaのモジュラリティ強化を担う"スーパーパッケージ"とは
第36回 JSR 308対応のコンパイラを試す
第35回 公開されたJSR 308のEarly Draftを検証する
第34回 スクリプト言語とJavaを結びつけるJSR 223
第33回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その2
第32回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その1
第31回 Javaの文法がそのまま使えるスクリプト言語"BeanShell"
第30回 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API
第29回 Javaアプリケーションからのリソース管理を可能にするJSR 284
第28回 XMLデータソースへの問い合わせはJSR 225で
第27回 Portlet Specification 2.0をもっと手軽に利用する
第26回 次期Javaポートレット仕様となるJSR 286
第25回 JSFとポートレットをつなげるJSR 301
第24回 Webサービス向けのポートレット仕様「WSRP」
第23回 高い相互運用性を実現するポートレットAPI - JSR 168
第22回 Java EE環境でタスクのスケジューリングを可能にするJSR 236
第21回 Java EE環境でのスレッドプログラミングを可能にするJSR 237
第20回 音声認識/合成のためのAPI - Java Speech APIとJSR 113
第19回 JSR 291でJavaプラットフォームにダイナミックコンポーネントモデルを導入
第18回 JAX-RSで簡単RESTful - JSR 311
第17回 待望のServlet 3.0がJSRに登場 - JSR 315
第16回 アノテーションを使ってバグ退治 - JSR 305
第15回 アノテーションをさらに広い範囲で利用可能にするJSR 308
第14回 Webアプリケーション開発の要となるか - JSF 2.0がJSRに登場
第13回 Webサービス経由でのJMX Agentへの接続を可能にするJSR 262
第12回 Javaアプリケーションのモジュール化をサポートするJava Module System
第11回 "NIO.2"がやってきた - JSR 203: More New I/O APIs for the Java Platform
第10回 JSR 295: Beans Bindingの参照実装を試す
第9回 けっこう便利! 単位を扱うAPI -- JSR 275: Units Specification
第8回 アノテーションでバリデーション - JSR 303: Bean Validator
第7回 Swing開発の救世主となるか - Swing Application Framework
第6回 JavaBeansのプロパティを同期させるバインディングAPI
第5回 誰よりも早く"Java SE 7"を睨む
第4回 日時情報の取り扱いを改善する JSR 310: Date and Time API
第3回 古いAPIも進化している!? - JSR 919: JavaMail 1.4
第2回 JSR 1 リアルタイムJava仕様
第1回 JCPによって進められるJava関連技術の標準化

もっと見る

提供:マイナビ

会員登録はこちら

大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう!  大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。

毎日コミュニケーションズはプライバシーマークを取得しています。



人気記事

一覧

イチオシ記事

新着記事