検索

キーワード


【Java】独自アノテーションの定義・カスタマイズの方法

  • 公開日:2020-09-24 09:12:11
  • 最終更新日:2021-01-25 18:52:24
【Java】独自アノテーションの定義・カスタマイズの方法

こんにちは、駆け出しプログラマーの若江です!

ここでは初学者として学習を終えた私からアウトプットの意味も込めて、

独自アノテーションについて紹介させていただきます。

できる限り初学者が理解しやすい内容として紹介させていただくので、参考となれば幸いです!


関連記事リンク:アノテーションの基礎 / インターフェースとは?

独自アノテーションの作成と使い方

注釈の役割を持つアノテーションには、

標準アノテーションなどのようにあらかじめ用意されたアノテーションと、

独自で作成するアノテーションの2種類があります。

ここでは後者の独自アノテーションを作成する方法や使い方について紹介させていただきます。

※アノテーションの基礎については別記事で紹介させていただいています。


独自アノテーションの作成 (@interface)

独自作成できるアノテーションはデータを持たない「マーカーアノテーション」、

データを持つ「単一アノテーション、フルアノテーション」どちらも作成することができます。

また、クラスやメソッドなどアノテーションを付与できる場所の特定などもできるため、

標準アノテーションと同じような形で独自作成のアノテーションを扱うことが可能です。


@interface の付与

アノテーション作成はクラスへ、

class 宣言の代わりに「@interface」アノテーションを記述することで簡単に作成することができます。

・@interface 付与の基本構文: public @interface アノテーション名 { 内容 }


◆ @interface の付与例

public @interface CreateAnnotation {
}


@interface を付与したクラスはその機能によって、

暗黙的に java.lang.annotation.Annotation インターフェースを実装した、

アノテーション型のクラスとなります。


メソッドの作成

アノテーション型のクラスにメソッドを作成することで、

値を保持するアノテーション( 単一アノテーション / フルアノテーション )を作成することができます。

メソッドは抽象メソッドと同じ記述がされます。

・アノテーションのメソッドの基本構文: 戻り値の型 メソッド名();

記述するメソッドが1つの場合は「単一アノテーション」、

メソッドが複数の場合は「フルアノテーション」です。


メソッドには public と abstract の修飾子を付けることができます。

修飾子を付けなくても暗黙的に public abstract なため、基本的には省略した書き方をします。


◆アノテーションのメソッド作成例(フルアノテーション)

public @interface CreateAnnotation {

	public abstract String str();
	abstract String str2();
	public String str3();
	String str4();
}


上記サンプルコードは全てエラーが出ません。

ただし複数の抽象メソッドを作ると、

そのアノテーションを使用する際は必ず全てのメソッドへアクセスしなくてはなりませんので、

必要な分だけ作成するようにしましょう。


独自アノテーションの使い方

同パッケージ内に作成したアノテーションは標準アノテーションのように付与することができます。

異なるパッケージで作成したアノテーションは import することで付与することができます。


アノテーションの付与は、パッケージやクラス、変数、メソッドなどほとんどの場所に可能ですが、

後ほど紹介するメタアノテーションの機能を使うことで付与できる場所を限定することができます。


◆独自アノテーションの付与例

【アノテーション型 クラス】 アノテーションを作成

package annotation;
public @interface CreateAnnotation {
}

【アノテーション付与クラス】 同パッケージで上記作成したアノテーションをメソッドへ付与

package annotation;
public class Test {

	@CreateAnnotation // 独自アノテーションを付与
	public static void main(String[] args) {
	}
}

【アノテーション付与クラス】 別パッケージで上記作成したアノテーションをメソッドへ付与

package sample;
import annotation.CreateAnnotation;
public class Test {

	@CreateAnnotation // import をしてアノテーションを付与
	public static void main(String[] args) {
	}
}


単一アノテーション / フルアノテーションの付与

データを保持するアノテーションは以下のように記述することで付与できます。

・単一アノテーション: @アノテーション名( メソッド名 = 値 )

・フルアノテーション: @アノテーション名( メソッド名 = 値, メソッド名 = 値, ~ )


アノテーションで作成した抽象メソッドを呼び出して値を保持します。

「値」はメソッドで指定した戻り値の型で記述することができます。

フルアノテーションの場合、値を記述する順番は不問です。


◆単一アノテーションの付与例

【アノテーション型 クラス】

public @interface CreateAnnotation {
	
	String name();
}

【アノテーションを付与するクラス】

public class Test {

	@CreateAnnotation(name = "アノテーション")
	public static void main(String[] args) {

	}
}


◆フルアノテーションの付与例

【アノテーション型 クラス】 メソッドを2つ作成

public @interface CreateAnnotation {

	String name();
	int number();
}

【アノテーションを付与するクラス】 

public class Test {

	@CreateAnnotation(name = "アノテーション", number = 0)
	public static void main(String[] args) {
	}
}


フルアノテーションは「 ,(カンマ) 」で区切ることで複数の値を記述することができます。


単一アノテーションの value

単一アノテーションの場合、作成するメソッドの名前を value にすることで

アノテーションを付与する際のメソッド名を省略して記述することができます。


◆アノテーションのメソッド名を value で作成した例

【アノテーション型 クラス】 メソッド名が value のメソッドを作成

public @interface CreateAnnotation {

	String value();
}

【アノテーションを付与するクラス】 メソッド名を省略してアノテーションを記述

public class Test {

	@CreateAnnotation("アノテーション")
	public static void main(String[] args) {
	}
}


標準アノテーションの @SuppressWarnings がこのような省略形で書かれています。


アノテーションの default

アノテーション作成時に「default」 を使うことで

アノテーションにあらかじめ値を保持させることが可能です。

default で値を保持した場合は、アノテーション付与時のメソッドの記述を省略することができます。


◆ default で値を設定する例

【アノテーション型 クラス】 2つ目のメソッドに default を使って値を設定

public @interface CreateAnnotation {

	String name();
	int number() default 1;
}

【アノテーションを付与するクラス】 上記クラスのメソッド number を省略

public class Test {

	@CreateAnnotation(name = "アノテーション")
	public static void main(String[] args) {
	}
}


default 機能が働いているため、アノテーション付与時に number を書かなくてもエラーになりません。


アノテーションの enum

アノテーションのメソッドは enum (列挙型)の値を渡すことも可能です。

作成した enum は「アノテーション型クラス名.メソッド名.定数名」でアクセスができます。


◆ enum のメソッド作成例

【アノテーション型 クラス】 enum の NameColor と enum の値を受け取る NameColor 型の color を作成

public @interface CreateAnnotation {

	enum NameColor{
		RED, YELLOW, BLUE
	};

	NameColor color();
}

【アノテーションを付与するクラス】 上記 NameColor 型の color メソッドを呼んで enum の値を1つ保持

public class Test {

	@CreateAnnotation(color = CreateAnnotation.NameColor.RED)
	public static void main(String[] args) {
	}
}



独自アノテーションのカスタマイズ

メタアノテーション」と呼ばれる、独自アノテーションのために用意されたアノテーションがあります。

メタアノテーションは先ほどのように作成した独自アノテーションに、

カスタマイズする形で機能を追加することができます。


メタアノテーションには種類がありますが、

今回はよく使う「@Target」「@Retention」「@Inherited」を紹介します。

※メタアノテーションでは各アノテーションを import する必要があります。


@Target

@Target が持つ定数を使うと、独自アノテーションを付与する場所の指定ができます。

@Targetで付与できる定数一覧


上記の中から今回は ElementType.METHOD を使って、

メソッドだけに付与できるアノテーションの作成をしてみましょう。


◆ ElementType.METHOD の付与例

【アノテーション型 クラス】 @Target の ElementType.METHOD を付与

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
public @interface CreateAnnotation {
	String name();
}

【アノテーションを付与するクラス】 メソッド以外にアノテーションを付与するとエラーとなる

// クラスにアノテーションを付与しようとしているためエラーになる
@CreateAnnotation(name = "アノテーション")
public class Test {

	public static void main(String[] args) {
	}
}


上記アノテーションはメソッドのみに付与できる設定のため、

Test クラスではなく main メソッドへ付与するとエラーが解消されます。

また、アノテーションを付与できる場所を複数指定することも可能です。

しかし @Target は単一アノテーションのためデータは1つしか保持できません。

このような場合は1つのデータとして、配列「{ }」を渡すことで複数の値を記述することが可能となります。


◆ @Target で複数の定数を保持する例

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface CreateAnnotation {

	String name();
}


@Target へ配列で「ElementType.METHOD」と「ElementType.TYPE」を渡すことができました。


@Retention

@Retention を付与すると、独自アノテーションの有効範囲を指定することができます。

@Retention には有効範囲別に3つの定数が用意されています。

これら3つの定数は java.lang.annotation.RetentionPolicy に定義されいます。

@Retentionで付与できる定数一覧

今回は RetentionPolicy.RUNTIME の使用例を見てみましょう。


◆ @Retention の付与例

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface CreateAnnotation {

	String name();
}


@Inherited

@Inherited を使うと、そのアノテーションが持つ情報を継承先の子クラスにも継承します。

@Inherited はクラスに対してしか使うことができません。


◆ @Inherited の付与例

import java.lang.annotation.Inherited;
@Inherited
public @interface CreateAnnotation {

	String name();
}



アノテーション情報の取得

アノテーションの @Retention が RUNTIME の(JVMで読み取りされている)場合、

リフレクションという機能を使ってアノテーションの情報を取得することができます。

リフレクションの取得機能はアノテーションの情報以外にもたくさん用意されていますが、

ここでは割愛させていただきアノテーションの情報取得方法を紹介させていただきます。


getAnnotation

アノテーションの情報を取得するには「getAnnotation」メソッドを使います。

getAnnotation は「AnnotatedElement インターフェース」を実装したクラスで使うことができます。

アノテーションの情報を取得する場合、AnnotatedElement インターフェースを実装したクラス

Classクラス」や「Methodクラス」、「Fieldクラス」などの getAnnotation メソッドを利用します。

ここでは Class と Method クラスを使った例を見てみましょう。


Class クラスの getAnnotation

Class の getAnnotation メソッドを使う場合は以下記述をします。

・Class の getAnnotation 基本構文:

 Class< ? > 変数名① = 独自アノテーションを 付与したクラス名.class;

 独自アノテーション名 変数名② = (独自アノテーション名)変数名①.getAnnotation(独自アノテーション名.class);


◆ Class クラスの getAnnotation 利用例

【独自アノテーション作成クラス】 抽象メソッドを1つ作成したアノテーション

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface GetAnnotationClassTest {
	String value();
}

【独自アノテーションを付与するクラス】 アノテーションに「true」の情報を保持させる

@GetAnnotationClassTest("a")
public class GetAnnotationTest {
}

【Class の getAnnotation メソッド利用クラス】 Class クラスの getAnnotation メソッドを利用

public class Test {

	public static void main(String[] args) {

		// 基本構文の例に沿って getAnnotation メソッドを利用
		Class<?> test = GetAnnotationTest.class;
		GetAnnotationClassTest sample = (GetAnnotationClassTest)test.getAnnotation(GetAnnotationClassTest.class);

		// アノテーションの情報が「a」だった場合に true を出力
		if(sample.value().equals("a")) {
			System.out.println("アノテーションの値が a のため true ");
		}
	}
}


Method クラスの getAnnotation

Class クラスの基本構文に Method クラスのインスタンス生成を追加します。

・Method クラスの getAnnotation 基本構文:

 Class< ? > 変数名① = 独自アノテーションを 付与したクラス名.class;

 Method 変数名② = 変数名①.getMethod(独自アノテーションを付与したメソッド名);

 独自アノテーション名 変数名③ = (独自アノテーション名)変数名②.getAnnotation(独自アノテーション名.class);


◆ Method クラスの getAnnotation 使用例

【独自アノテーション作成クラス】

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface GetAnnotationMethodTest {
	String value();
}

【独自アノテーション付与クラス】

public class GetAnnotationTest {

	@GetAnnotationMethodTest("b")
	public void name() {

	}
}

【Method の getAnnotation メソッド利用クラス】

import java.lang.reflect.Method;
public class Test {

	public static void main(String[] args) throws Exception {

		// 基本構文の例に沿って getAnnotation メソッドを利用
		Class<?> test = GetAnnotationTest.class;
		Method sample = test.getMethod("name");
		GetAnnotationMethodTest method = (GetAnnotationMethodTest)sample.getAnnotation(GetAnnotationMethodTest.class);

		// アノテーションの情報が「b」だった場合に true を出力
		if(method.value().equals("b")) {
			System.out.println("アノテーションの値が b のため true");
} } }

※ Method クラスを利用する場合は throws句もしくは try / catch が必要となります。


Field クラスや Constructor クラスなども例のような手順でアノテーションの情報を取得することができます。



まとめ

標準アノテーションに用意されていない機能をプログラミングで使いたい場合に

独自アノテーションを作成することになります。


関連記事リンク

アノテーションの基礎 / インターフェースとは?





【著者】

若江

30代で異業種となるIT業界へ転職した駆け出しのプログラマです。これまで主に Java や Ruby、HTML/CSS を使って学習を目的としたショップサイトや掲示板サイトの作成を行いました。プログラマとしての経験が浅いからこそ、未経験者の目線に近い形で基礎の紹介をしていきたいと思います。

よく読まれている記事
【Java】JSPでタグライブラリを使う(JSTL)

【Java】JSPでタグライブラリを使う(JSTL)

こんにちは。エンジニアの新田です!ここでは、システムエンジニアとして働いている私が、システム開発手法や開発言語について紹介していこうと思います。今回は、JSPの標準タグライブラリ「JSTL」について紹介します。Javaについて勉強している方、Webアプリケーションを構築したいと思っている方の参考になれば幸いです!関連記事リンク: 【Java】JSPの基本的な構文/【Java】JSPのアクションタグ

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!そもそもStringとは何?『 String 』... Java言語において文字列のデータ型を指します。基本デ

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!Stringクラスformatメソッドの文字列整形【java.utilパッケージ】Formatterクラスfo

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者にも✅、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!文字列を扱う3つのクラス【java.langパッケージ】java.langパッケージの文字列を扱うクラスにはS

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!プリミティブ型と参照型プログラム開発では型を持った変数を使ってデータのやり取りをしますが、データ型によって仕様