SSブログ

アノテーションの互換性 [Java]

『プログラミング言語Java第4版』の第16章「リフレクション」の16.2節「アノテーションの問い合わせ」では、リフレクションを使用してのアノテーションの問い合わせ方法が解説されています。その節の最後の段落に次のような記述があります(363頁)。
実行時に存在するアノテーション型は、調べられようとしているクラスにアノテーションを付けるのに使用されたアノテーション型と異なる可能性がありますので、その型の2つの使われ方には互換性がない可能性があります。もし、互換性がない場合に、アノテーションの要素へアクセスしようとすると、AnnotationTypeMismatchExceptionあるいは IncompleteAnnotationExceptionがスローされます。もし、要素型がenumであり、アノテーション内のenum定数がそのenumに存在しなくなっていれば、EnumConstantNotPresentExceptionがスローされます。

この説明によれば、アノテーションは、互換性がある方法で変更することが可能だということになります。互換性を保ちながらアノテーションを変更できるという意味で、『Effective Java 第2版』には、次のように述べられています(174頁の最後の段落)。
マーカーインタフェースに優るマーカーアノテーションの主な長所は、デフォルトを持つアノテーション型要素を1つ以上追加することで、すでに使用された後でもアノテーション型に情報を追加できることです [JLS, 9.6]。単なるマーカーアノテーション型として始まっても、時間の経過に伴い機能が豊富なアノテーション型へ発展できます。そのような発展は、マーカーインタフェースでは不可能です。なぜなら、一旦実装された後に、インタフェースにメソッドを追加することは一般に不可能だからです。

つまり、既存のアノテーション型の定義に新たな要素を追加する場合には、デフォルトを指定すれば互換性を保ちながら変更が可能だということです。

実際に、既存のアノテーション型にデフォルトを持たない要素を追加した場合には、そのアノテーション型でアノテーションを付けられているコードを再コンパイルするとエラーになります。なぜならば、新たな要素の値が指定されていないからです。しかし、再コンパイルされない場合に、リフレクションによりその新たな要素の値を読み出そうとすると、IncompleteAnnotationExceptionがスローされます。

既存のアノテーション型の特定の要素の型を変更した場合には、そのアノテーション型でアノテーションを付けられているコードを再コンパイルするとエラーになったり、ならなかったりします。たとえば、元の要素の型がStringであったのををintにすればコンパイルエラーとなります。一方、元の要素の型がStringであったのを配列String[]に変更した場合には再コンパイルできます。なぜならば、要素の値が少なくとも1つはすでに指定してあるからです。しかし、どちらの場合でも、古いアノテーション型でアノテーションが付けられているコードを再コンパイルすることなく、そのアノテーションの要素の値をリフレクションにより読み出そうとするとAnnotationTypeMismatchExceptionがスローされます。

Java言語のアノテーションについてはきちんと学びたい方は、『プログラミング言語Java第4版』の第15章「アノテーション」と16.2節「アノテーションの問い合わせ」、および、拙著『Java 2 Standard Edition 5.0 Tiger―拡張された言語仕様について』の第7章「アノテーション」と8.1節「リフレクションAPI」を読まれることをお勧めします。


nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

Facebook コメント

トラックバック 0