Javaにおけるアノテーションについて学ぶ

Javaにおけるアノテーションについて学習ついでにまとめてみました。
アノテーションの基本的な構文や使い方について説明する記事です。
割とchatGTPくんに質問しながら理解していった節があるので、サンプルなどはGPTが生成したものが多いです。

# 基本的なアノテーションの使用法と概要
## そもそもアノテーションとは
直訳すると「注釈」という意味。
注釈とは「語句や文章をわかりやすく解説したもの」である。

## Javaにおけるアノテーションとは
アプリケーションのロジックに直接関係しない付随情報（メタデータ）をコードに追加することできる。
Javaには最初から用意されている「標準アノテーション」や、自作のオリジナルアノテーションを作成することもできる。

Spring Frameworkにおいて提供されるアノテーションも存在する。
これはフレームワーク自体の拡張機能に対して、特定の振る舞いや動作をさせたい場合にアノテーションを利用することもある。

## 使い方
基本的なアノテーションの構文は @ から始まり、その後にアノテーションの名前が続く。
アノテーションを追加する際は、クラスやインターフェース、メソッドなど要素の先頭に記載する。
具体的な記述例は後述する。

## アノテーションを使うことによるメリット
### コードの意味を明示化できる
@overrideなどはメソッドが親クラスでオーバーライドしていることを明示し、
コードの読み手にコードの意味を提供する。

### 静的解析を使った問題の早期解決
静的解析ツールやIDEを活用して、エラーや問題の警告を早期に発見することが出来る。
これにより開発の効率を上げることが出来る。

# 標準アノテーションについて
ライブラリに標準で組み込まれているアノテーションのことを標準ライブラリという。
全てを挙げていくとキリがないので、代表的なアノテーションを紹介する。

## @override
メソッドが親クラスでオーバーライドしていることを示す


```java
class MyBaseClass {
    public void myMethod() {
        // メソッドの実装
    }
}

class MyDerivedClass extends MyBaseClass {
    @Override
    public void myMethod() {
        // オーバーライドしたメソッドの実装
    }
}
```

## ＠Deprecated
メソッドやクラスが非推奨であることを示す
```java
class DeprecatedExample {
    @Deprecated
    public void oldMethod() {
        // 古いメソッドの実装
    }
}
```

## @SuppressWarnings
特定の警告を抑制するためのアノテーション
以下の例だとdeprecationの警告がコンパイル時に発生しないように抑制している。
アノテーションのパラメータは「（）」内に記載することで指定することが出来る。
```java
class SuppressWarningExample {
    @SuppressWarnings("deprecation")
    public void useDeprecatedMethod() {
        // 非推奨のメソッドを使用するが、警告を抑制
        DeprecatedExample deprecatedExample = new DeprecatedExample();
        deprecatedExample.oldMethod();
    }
}
```

# カスタムアノテーションの利用
独自のアノテーションを作成することが出来る。
ただし、乱用するとコードが読みにくくなり可読性が下がってしまうこともあるので注意。

## カスタムアノテーションの作成
アノテーションを自作するには、以下の「メタアノテーション」を使う必要がある。

### @Retention :アノテーションが保持される期間を指定する
Javaには以下の3つのポリシーが存在している
 - RetentionPolicy.SOURCE（ソースレベル）
    ソースコード内でのみ有効であり、コンパイル時に取り除かれる。実行時には利用できない。
    主にコード生成などのツールが使用する場合に適しているらしい。
 - RetentionPolicy.CLASS（クラスレベル）
    コンパイルされたクラスファイルに保持されるが、実行時には利用出来ない。
    リフレクションを使用せずにアノテーションプロセッサがクラスファイルを処理する際に利用するらしい。
- RetentionPolicy.RUNTIME（実行時）
    コンパイルされたクラスファイルに保持され、実行時にも利用出来る。
    リフレクションを使用して実行時にアノテーションを取得する場合、このリテンションポリシーが必要らしい。

※リフレクションとは
　プログラムが自分自身の構造を調査し、または操作するためのメカニズムを指す。
 
### @Target :アノテーションがどの種類の要素に適用できるかを指定する
- ElementType.METHOD
    メソッドに対して適用する際に指定する
- ElementType.TYPE
    クラスに対して適用する際に指定する
- ElementType.FIELD
    フィールドに対して適用する際に指定する
- ElementType.CONSTRUCTOR
    コンストラクタに対して適用する際に指定する

### 「MyCustomAnnotation」というアノテーションを作成する際の例
chatGPTに理解の手助けをしてもらった時の例。


```java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// カスタムアノテーションの定義
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyCustomAnnotation {
    String value() default "Default Value";
    int count() default 1;
}
```

自作アノテーションを使用する
mainメソッドでは、リフレクションを利用してmyAnnotatedMethodを動作させている。
myAnnotatedMethodに付与された値を動的に出力している。

```java
import java.lang.reflect.Method;

public class MyClass {
    @MyCustomAnnotation(value = "Custom Value", count = 3)
    public void myAnnotatedMethod() {
        System.out.println("Executing myAnnotatedMethod");
    }

    public static void main(String[] args) {
        // リフレクションを使用してアノテーションの情報を取得
        try {
            // myAnnotatedMethodメソッドに付与されたアノテーションを取得
            Method method = MyClass.class.getMethod("myAnnotatedMethod");
            MyCustomAnnotation annotation = method.getAnnotation(MyCustomAnnotation.class);

            // アノテーションの情報を表示
            if (annotation != null) {
                System.out.println("Value: " + annotation.value());
                System.out.println("Count: " + annotation.count());
            }

            // アノテーションの情報を利用して動的な振る舞いを実現
            if (annotation != null && annotation.count() > 1) {
                for (int i = 0; i < annotation.count(); i++) {
                    System.out.println("Executing myAnnotatedMethod iteration " + (i + 1));
                    method.invoke(new MyClass()); // メソッドの実行
                }
            }

        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
    }
}
```

# Spring Frameworkにおけるアノテーションについて
フレームワーク自体の拡張機能に対して、特定の振る舞いや動作をさせたい場合に活用する。
これも全て挙げるとキリがないので、業務でよく見かけるアノテーションを羅列していく。

## @Controller
コントローラークラスであることを示す

## @Service
サービスクラスであることを示す

## @Repository
リポジトリクラスであることを示す

## @RequestParam
HTTPリクエストのパラメータを取得するために使用される。

## @RequestMapping
HTTPリクエストとコントローラーメソッドをマッピングするために使用される。
これにより、どのURLがどのコントローラーメソッドに対応するかを指定することが出来る。

## @GetMapping
HTTP GETリクエストとコントローラーメソッドをマッピングするために使用される。
@RequestMappingの簡略版。@RequestMappingよりも簡潔なコードを実現できる。

## @PostMapping
HTTP POSTリクエストとコントローラーメソッドをマッピングするために使用される。
@RequestMappingの簡略版。@RequestMappingよりも簡潔なコードを実現できる。

## @Component
Spring Frameworkのコンポーネントスキャン対象のクラスに付与される。
コンポーネントスキャンとは、クラスローダーをスキャンして特定のクラスを自動的にDIコンテナに登録することである。このことをBeanという。
@Componentを記載したクラスが検出されると、Springコンテナに登録される。
その後、他のクラスでこのコンポーネントを利用する場合、DIによって自動的にインスタンスが提供される。

### 余談）Beanのライフサイクル
こちらの記事が非常にわかりやすかった

https://qiita.com/asksaito/items/2c854065e5803463ebfd#bean%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB

## @Autowired
Spring FrameworkにおいてDIを実現する際に使い、コンポーネントやBeanへの自動的な依存性の注入を行う。
@Autowiredをフィールド、セッターメソッド、コンストラクタに付与することで、Springは対象のクラスのインスタンスに依存性を注入する。








# 参考
https://atmarkit.itmedia.co.jp/ait/articles/1105/19/news127.html

https://workteria.forward-soft.co.jp/blog/detail/10172

https://qiita.com/suema0331/items/0e6f7865a498c6e0b176

https://qiita.com/yasushi-jp/items/fca645778d44fd228864

https://qiita.com/asksaito/items/2c854065e5803463ebfd#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%B9%E3%82%AD%E3%83%A3%E3%83%B3%E3%81%AE%E5%AF%BE%E8%B1%A1