Java プログラミング言語では、アノテーションは属性のようにJavaソース コードに追加できる構文メタデータの一種です。[ 1 ]クラス、メソッド、変数、パラメータ、Java パッケージにアノテーションを付けることができます。Javadocタグと同様に、Java アノテーションはソース ファイルから読み取ることができます。Javadoc タグとは異なり、Java アノテーションはJava コンパイラによって生成されたJava クラス ファイルにも埋め込んで読み取ることができます。これにより、実行時にJava 仮想マシンによってアノテーションが保持され、リフレクションを介して読み取ることができます。[ 2 ] Java では、既存のアノテーションからメタ アノテーションを作成することが可能です。[ 3 ]
Javaプラットフォームには、修飾子やjavadoc タグなど、さまざまなアドホックな注釈メカニズムがあります。Java仕様要求JSR-175 は、汎用注釈 (メタデータとも呼ばれる) 機能を2002 年にJava コミュニティ プロセスに導入し、2004 年 9 月に承認されました。[ 4 ]transient@Deprecated
Java Development Kit (JDK)バージョン 1.5 以降、言語自体にアノテーションが組み込まれるようになりました。JDK バージョン 1.5aptでは、コンパイル時のアノテーション処理のための暫定的なインターフェースが提供されていましたが、JSR-269 によってこれが正式に規定され、バージョン 1.6 でjavacコンパイラに統合されました。
Java は、言語に組み込まれている一連の注釈を定義しています。7 つの標準注釈のうち、3 つはjava.langの一部であり、残りの 4 つは からインポートされますjava.lang.annotation。[ 5 ] [ 6 ]
Jakarta EE (旧称 Java Platform, Enterprise Edition)では、以下の注釈もjakarta.annotation(旧称javax.annotation): [ 7 ] [ 8 ]に存在します。
@ManagedBean以前は、 に というアノテーションがあり、jakarta.annotationこれは、リソース注入、ライフサイクルコールバック、インターセプターなどの基本的なサービスセットをサポートするコンテナ管理オブジェクトであるマネージド Bean を宣言するために使用されていました。しかし、これは削除されました。[ 9 ] [ 10 ]
この例は、アノテーションの使用方法を示しています@Override。このアノテーションは、コンパイラに親クラスで一致するメソッドをチェックするように指示します。この場合、クラス Cat のメソッドが、意図したとおりにクラス Animal のメソッドgettype()をオーバーライドしていないため、エラーが発生します。これは、不一致のケースが原因です。アノテーションがない場合、クラス Cat に名前の新しいメソッドが作成されます。getType()@Overridegettype()
public class Animal { public void speak () {}public String getType () { return "一般的な動物" ; } }public class Cat extends Animal { @Override public void speak () { // これは良いオーバーライドです。System . out . println ( "ニャー。" ); }@Override public String gettype () { // タイプミスによるコンパイル時エラー: getType() ではなく gettype() であるべきです。return "Cat" ; } }アノテーション型の宣言は、通常のインターフェース宣言と似ています。キーワード「interface」の前にアットマーク(@)を付けます。
// @Twizzle はメソッド toggle() の注釈です。@Twizzle public void toggle () {}// アノテーション Twizzle を宣言します。public @interface Twizzle {}アノテーションには、アノテーション型のメソッドとしてモデル化されたキーと値のペアのセットを含めることができます。各メソッド宣言は、アノテーション型の要素を定義します。メソッド宣言には、パラメーターやthrows句を含めてはなりません。戻り値の型は、プリミティブ型、String型、Class型、列挙型、アノテーション、およびこれらの型の配列に限定されます。メソッドにはデフォルト値を設定できます。
// 同じです: @Edible(value = true) @Edible ( true ) Item item = new Carrot ();public @interface Edible { boolean value () default false ; }@Author ( first = "Oompah" , last = "Loompah" ) Book book = new Book ();public @interface Author { String first (); String last (); }注釈自体にも、使用できる場所と時期を示す注釈を付ける場合があります。
import java.lang.annotation.* ;@Retention ( RetentionPolicy . RUNTIME ) // このアノテーションをリフレクションを介して実行時にアクセス可能にします。@Target ({ ElementType . METHOD }) // このアノテーションはクラスメソッドにのみ適用できます。public @interface Tweezable {}コンパイラは、構文上の目的のために、一連の特別な注釈(、およびを含む)を予約して@Deprecatedい@Overrideます@SuppressWarnings。
アノテーションは、フレームワークで広く使用されており、外部ソース(XML 設定ファイルなど)またはプログラム的に(API 呼び出しで)宣言する必要があるユーザー定義クラスやメソッドに、動作を簡単に適用する方法として利用されています。[ 11 ]例えば、ライブラリProject Lombok は、定型コードを削減するためにアノテーションを多用しています。[ 12 ]例えば、以下はアノテーションが付けられたJakarta Persistenceデータ クラスです。
パッケージorg.wikipedia.examples ;import java.io.Serializable ;import jakarta.persistence.Column ; import jakarta.persistence.Entity ; import jakarta.persistence.GenerationType ; import jakarta.persistence.GeneratedValue ; import jakarta.persistence.Id ; import jakarta.persistence.Table ;@Entity // エンティティ Bean を宣言します。@Table ( name = "people" ) // Bean を SQL テーブル "people" にマッピングします。public class Person implements Serializable { @Id // プライマリ キー列にマッピングします。@GeneratedValue ( strategy = GenerationType . AUTO ) // データベースが新しいプライマリ キーを生成します。private Integer id ;@Column ( length = 32 ) // 列の値を 32 文字に切り詰めます。private String name ;public Integer getId () { return id ; }public void setId ( Integer id ) { this.id = id ; }public String getName () { return name ; }public void setName ( String name ) { this.name = name ; } }アノテーションはメソッド呼び出しではなく、それ自体では何も実行しません。むしろ、実行時にクラスオブジェクトがJakarta Persistenceの実装に渡され、そこでアノテーションが抽出されてオブジェクトリレーショナルマッピングが生成されます。
以下に完全な例を示します。
パッケージorg.wikipedia.examples.annotation ;import java.lang.annotation.Documented ; import java.lang.annotation.ElementType ; import java.lang.annotation.Inherited ; import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ; import java.lang.annotation.Target ;@Documented @Retention ( RetentionPolicy . RUNTIME ) @Target ({ ElementType . TYPE , ElementType . METHOD , ElementType . CONSTRUCTOR , ElementType . ANNOTATION_TYPE , ElementType . PACKAGE , ElementType . FIELD , ElementType . LOCAL_VARIABLE }) @Inherited public @interface Unfinished { public enum Priority { LOW , MEDIUM , HIGH } String value (); String [] changedBy () default "" ; String [] lastChangedBy () default "" ; Priority priority () default Priority . MEDIUM ; String createdBy () default "James Gosling" ; String lastChanged () default "2011-07-08" ; }パッケージorg.wikipedia.examples.annotation ;public @interface UnderConstruction { String owner () default "Patrick Naughton" ; String value () default "オブジェクトは構築中です。" ; String createdBy () default "Mike Sheridan" ; String lastChanged () default "2011-07-08" ; }次に、Jakarta Facesを使用します。
パッケージorg.wikipedia.examples.validators ;import jakarta.faces.application.FacesMessage ; import jakarta.faces.component.UIComponent ; import jakarta.faces.context.FacesContext ; import jakarta.faces.validator.Validator ; import jakarta.faces.validator.ValidatorException ;import org.wikipedia.examples.annotation.UnderConstruction ; import org.wikipedia.examples.annotation.Unfinished ; import org.wikipedia.examples.annotation.Unfinished.Priority ; import org.wikipedia.examples.util.Util ;@UnderConstruction ( owner = "Jon Doe" ) public class DateValidator implements Validator { public void validate ( FacesContext context , UIComponent component , Object value ) throws ValidatorException { String date = ( String ) value ; String errorLabel = "有効な日付を入力してください。" ; if ( ! component . getAttributes (). isEmpty ()) { errorLabel = ( String ) component . getAttributes (). get ( "errordisplayval" ); }if ( ! Util.validateAGivenDate ( date )) { @Unfinished ( changedBy = " Steve" , value = "メッセージをコンテキストに追加するかどうか、確認してください" , priority = Priority.HIGH ) FacesMessage message = new FacesMessage ( ) ; message.setSeverity ( FacesMessage.SEVERITY_ERROR ) ; message.setSummary ( errorLabel ) ; message.setDetail ( errorLabel ) ; throw new ValidatorException ( message ) ; } } }Java ソースコードがコンパイルされる際、アノテーションはアノテーションプロセッサと呼ばれるコンパイラ プラグインによって処理されます。プロセッサは情報メッセージを生成したり、追加の Java ソース ファイルやリソースを作成したりできます。これらはコンパイルされ、処理されます。ただし、アノテーションプロセッサはアノテーションされたコード自体を変更することはできません。(コードの変更は、Java 言語仕様の範囲外の方法を使用して実装できます。)Java コンパイラは、アノテーションの が または の場合、アノテーション メタデータを条件付きでクラス ファイルに格納しますRetentionPolicy。CLASSその後RUNTIME、JVMや他のプログラムはメタデータを参照して、プログラム要素とのやり取り方法や動作の変更方法を判断できます。
アノテーションプロセッサを使用してアノテーションを処理することに加えて、Java プログラマはリフレクションを使用してアノテーションを処理する独自のコードを記述することもできます。Java SE 5 では、パッケージで定義されている新しいインターフェイスがサポートされています。このパッケージには、Java リフレクション クラス(、、、、、など)によって実装されるjava.lang.reflectインターフェイスが含まれています。このインターフェイスの実装は、Java 仮想マシンで現在実行中のプログラムのアノテーション付き要素を表すために使用されます。このインターフェイスを使用すると、アノテーションをリフレクションで読み取ることができます。AnnotatedElementClassConstructorFieldMethodPackage
このAnnotatedElementインターフェースは、保持期間を持つアノテーションへのアクセスを提供しますRUNTIME。このアクセスはgetAnnotation、、、getAnnotationsおよびisAnnotationPresentメソッドによって提供されます。アノテーション型はクラスと同様にコンパイルされ、バイトコードファイルに格納されるため、これらのメソッドによって返されるアノテーションは、通常のJavaオブジェクトと同様にクエリできます。アノテーションを処理する完全な例を以下に示します。
パッケージorg.wikipedia.examples.annotation ;import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ;// これは処理対象のアノテーションです// ターゲットのデフォルトはすべての Java 要素です// 保持ポリシーを RUNTIME に変更します (デフォルトは CLASS) @Retention ( RetentionPolicy . RUNTIME ) public @interface TypeHeader { // 開発者属性に指定されるデフォルト値String developer () default "Unknown" ; String lastModified (); String [] teamMembers (); int meaningOfLife (); }// これはクラスに適用されるアノテーションです@TypeHeader ( developer = "Bob Bee" , lastModified = "2013-02-12" , teamMembers = { "Ann" , "Dan" , "Fran" }, meaningOfLife = 42 ) public class SetCustomAnnotation { // クラスの内容をここに記述します}パッケージorg.wikipedia.examples ;// これはアノテーションを処理するサンプルコードですimport java.lang.annotation.Annotation ; import java.lang.reflect.AnnotatedElement ;public class UseCustomAnnotation { public static void main ( String [] args ) { Class < SetCustomAnnotation > classObject = SetCustomAnnotation . class ; readAnnotation ( classObject ); }static void readAnnotation ( AnnotatedElement element ) { try { System . out . println ( "Annotation element values: %n" ); if ( element . isAnnotationPresent ( TypeHeader . class )) { // getAnnotation は Annotation 型を返しますAnnotation singleAnnotation = element . getAnnotation ( TypeHeader . class ); TypeHeader header = ( TypeHeader ) singleAnnotation ;System.out.printf ( "開発者: %s%n" , header.developer ( ) ) ; System.out.printf ( "最終更新日: % s%n" , header.lastModified ( ) );// teamMembersはString[] として返されますSystem.out.print ( "チームメンバー: " ); for ( String member : header.teamMembers ( ) ) { System.out.printf ( " % s , " , member ) ; } System.out.println ( ) ;System.out.println ( "人生の意味: %s % n " , header.meaningOfLife ( ) ) ; } } catch ( Exception e ) { e.printStackTrace ( ) ; } } }JUnitなどのライブラリは、アノテーション処理を使用して単体テストを生成します。