20220201のJavaに関する記事は7件です。

M1 Mac も速くないことがある

これは何? 先日まで Mid 2015 の 15 inch MacBook Pro (Core i7 クアッド / 2.2 GHz) を使っていた。 先日 MacBook Pro 14 inch (M1 非Max) を手に入れたんだけど、あんまり速くないなと思うことがあったので、今日も楽しいマイクロベンチマーク。 計算内容 ruby で書くと短くていいね。 ruby N=10000 r=(1..N).max_by{ |x| ((N-x)**x/7) % 6074001001 } p r こういう内容。なんの意味もない。 出力は 8663 となれば正解。 これを、go, java, c++ with boost (clang, gcc), ruby, python3, node で試した。 以降、グラフで出てくる "m1", "rosetta", "amd64" の意味は下表のとおり。 記号 実行ハードウェア バイナリ m1 MacBook Pro 14 inch (M1 非Max) arm64 rosetta MacBook Pro 14 inch (M1 非Max) x86_64 amd64 MacBook Pro (Core i7, Mid 2015) x86_64 コンパイルするチーム go, java, c++ with boost (clang, g++-11)。 各コンパイラは下記の通り go version go1.17.5 darwin/arm64 openjdk 17.0.1 2021-10-19 LTS Apple clang version 13.0.0 (clang-1300.0.29.30) g++-11 (Homebrew GCC 11.2.0_3) 11.2.0 java と clang の rosetta はサボった。 結果は下記の通り。 time コマンドの real の値を出しているので棒が短いほど速い。 ちなみに、 real なのは並列実行を優遇するため。実際、 Java は user が real の 1.5倍ぐらいある。 結果は下図。 目盛りを見ると分かる通り、 go が速い。意外と clang が M1 を使いこなせてない感じ。 全体的にはまあそうだよねという結果だと思う。 コンパイルしないチーム 続いて、 ruby, python3, node。 各環境は下記の通り ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [arm64-darwin21] / for m1 ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [x86_64-darwin21] / for rosetta ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin21] / for amd64 Python 3.9.10 (main, Jan 15 2022, 11:40:53) / for m1 Python 3.9.10 (main, Jan 15 2022, 11:48:04) / for rosetta Python 3.9.10 (main, Jan 15 2022, 11:48:04) / for amd64 node v17.3.0 / for m1 and rosetta node v17.3.1 / for amd64 なんか ruby と node のバージョンが合ってないけど気にしない。 結果は下図。 こちらはわりと思いがけなかった。 node はまあまあそうだよねという内容。m1 と amd64 の差はもうちょっとあってもいいかなと思うけど。 python3 は、三者ほぼ同タイム。 そして ruby は m1 が一番遅いという意外な展開。よく見てみると、m1 が遅いというより、amd64 が速すぎる。amd64 の中では go と並んでほぼ最速。m1 が遅いと書いたもののそれは ruby 内の比較の話。m1 内での比較だと Java と同等、clang より速い。node には負けるけど。 ruby や python で m1 がふるわないのは、おそらく、x86_64 バイナリは SSEとかをたっぷり使っていて、ARM64 バイナリは NEONとかを使いこなせてないんだろうと想像する。調べてないので想像するだけ。 誤解なきよう ここでやっているのはマイクロベンチマーク。多倍長整数の特定の計算だけしかしていない。 「ruby は M1 でも遅いのか」という感想を持つべきではなくて「ruby は多倍長整数計算では M1 でも遅いことがあるのか」という感想が正解。 実際。 多倍長整数ではない計算をすると、私が試した範囲では全部、M1 は rosetta に圧勝する。 時間測定に使ったコード ruby # hash require "json" $ix=0 def foo(x) return { ($ix+=1).to_i=>($ix+=1).to_s } if x==0 foo(x-1).merge(foo(x-1)) end p foo((ARGV[0]||21).to_i).size ruby # json require "json" def foo(x) x.times.with_object({}){ |e,o| o[e] = JSON.parse(foo(x-1)) }.to_json end p foo((ARGV[0]||9).to_i).size ruby # eval long text def foo(s, n) return eval(s) if n==0 foo("(#{s})*2+(#{s})", n-1) end p foo("1", (ARGV[0]||21).to_i) ruby # many delete_at def foo(n) a=[*1..n] (1..).each do |ix| return a[0] if a.size==1 a.delete_at(ix % a.size) end end p foo((ARGV[0]||200000).to_i) ruby # float calc def foo(n) n.downto(1).sum{ |e| x=e.to_f (x+1)/(x**(x**0.1)) } end p foo((ARGV[0]||10000000).to_i) ruby # regexp def foo(n) s = "___"+(1..n).map{ |x| "o"*x }.join("___")+"___" s.scan(/(_(o(o+))(\2+)_)/).sum{ |e| e[0].size-2} end p foo((ARGV[0]||4096).to_i) ruby # deep flatten def foo(n) return [1] if n<1 [foo(n-1)*n]*n end p foo(ARGV[0] || 7).flatten.sum ruby # recursive fibo def foo(n) return n if n<2 foo(n-1) + foo(n-2) end p foo(ARGV[0] || 37) 上記の折りたたんであるコードを実行すると、下図のとおり、 M1 が勝つ。 まあそりゃそうだ、という話。 result.png まとめ M1 ネイティブでも rosetta 2 より遅いこともあるよ。 とはいえ。ほとんどの場合は M1 ネイティブは速いし、今遅いものもそのうち早くなるんじゃないかと思うよ(思うだけ)。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[IntelliJ IDEA] 静的セキュリティーチェックツール

概要 ここ記事は下記のgithubを参考し、作成しました。 immomoのgithub immomoとは 静的javaコード、sqlコードをチェックし、セキュリティー上の問題が発見すると、エラーをを表示し、改修案を提示してくれるIntelliJ IDEAのプラグインです。 requirement 下記によって、IntelliJ IDEAのバージョンは>= 2018.3 https://github.com/momosecurity/momo-code-sec-inspector-java#%E7%89%88%E6%9C%AC%E6%94%AF%E6%8C%81 インストール プラグインマーケットでimmomoを検索すれば良い。 https://github.com/momosecurity/momo-code-sec-inspector-java#%E5%AE%89%E8%A3%85%E4%BD%BF%E7%94%A8 試して、使ってみる sqlインジェクション問題が発生しそうなSQL文を書いた。 表示したproblem fix案を採用する。 下記の観点で、セキュリティー問題をチェックしている 参考↓ https://github.com/momosecurity/momo-code-sec-inspector-java#%E6%8F%92%E4%BB%B6%E8%A7%84%E5%88%99
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Testcontainersでデータアクセスロジックのテストを行う方法

はじめに Testcontainersを使ってMySQLへのCRUDを行うデータアクセスロジックのテストコードを書いてみたので備忘録を残します。本記事内では抜粋したサンプルコードを掲載していますが、完全なソースコードはGitHubリポジトリで閲覧可能です。 Testcontainersとは 公式リファレンスでは以下のように説明されています。 Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container. (訳:TestcontainersはJUnitテストをサポートするJavaライブラリで、一般的なデータベースやSeleniumウェブブラウザなど、Dockerコンテナで実行可能なあらゆるものの軽量で使い捨てのインスタンスを提供します。) つまり、データベースのような外部へのアクセスを伴うテストを行う際、そのアクセス先をテスト実行時のみ有効なDockerコンテナで代用することができるようになり、以下のようなメリットが得られます。 アクセス先を開発用ローカルマシン内に立ち上げたり、ローカルネットワーク内に立ち上げたりする必要が無くなる テストコードや設定ファイルを共有するだけで同じテスト環境を共有できる テスト実施時はアクセス先が毎回同じ状態であることが保証される テスト終了後はコンテナが破棄され、テストの影響が残らない 今回は、単体テストコードからTestcontainersにより生成されたDockerコンテナ内のMySQLにアクセスし、実際のMySQLデータベースを用意することなくテストを実施できるようにします。 ここで解説する内容の多くは、JDBCを用いる場合であればMySQL以外のDBイメージにも共通の内容です。また、TestcontainersではDB以外にも、多くのDockerイメージに対応しています。利用可能なイメージの一覧は、公式リファレンスの「Modules」を参照してください。 環境 Java Junit5 Spring Boot MyBatis Maven Windows10(※Testcontainers実行時はDocker Desktopを起動しておく必要があります) 依存関係 JUnit5でTestcontainersを利用するための依存関係としてorg.testcontainers:junit-jupiterを、TestcontainersでMySQLイメージを利用するための依存関係としてをorg.testcontainers:mysqlそれぞれ<dependencies>に追加する必要があります。また、Testcontainersで使用するDBイメージを依存関係に追加していても、そのDB用のJDBCドライバは別途クラスパス上に存在する必要があるため、MySQL用のJDBCドライバも<dependencies>に追加します。 pom.xml(抜粋) <dependencies> ... <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <version>1.16.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>mysql</artifactId> <version>1.16.2</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <!-- Spring Boot利用のためバージョンは省略 --> </dependency> ... </dependencies> 公式リファレンスではそれぞれの依存関係で個別に<version>を明示する代わりに、<dependencyManagement>にTestcontainersのBOMを追加することを推奨しています。 pom.xml(抜粋) <dependencyManagement> <dependencies> ... <dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers-bom</artifactId> <version>1.16.2</version> <type>pom</type> <scope>import</scope> </dependency> ... </dependencies> </dependencyManagement> <dependencies> ... <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <!-- <version>1.16.2</version> BOM利用時は省略可--> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>mysql</artifactId> <!-- <version>1.16.2</version> BOM利用時は省略可--> <scope>test</scope> </dependency> ... </dependencies> BOMを追加することで、それぞれのTestcontainers依存関係のバージョンはBOMのバージョンに対応するものが自動的に選択されます。 コンテナの生成方法 Testcontainersでテストコードからアクセス可能なMySQLコンテナを生成するための方法として、公式リファレンスでは以下の2つが提示されています。 1. Testcontainers用JDBC URLを使用しコンテナの生成を指示する方法 2. Database container objectsを使用しテストコード内で明示的にコンテナを生成する方法 公式リファレンスでは1.Testcontainers用JDBC URLを用いる方法をまず検討し、その方法が採用できない制約がある場合や、DBコンテナを細かく設定したい場合に2.Database container objectsを用いる方法を採用するよう推奨しています。 今回は1.Testcontainers用JDBC URLを用いた方法を採用しました。 また、詳細は後述しますが、1.Testcontainers用JDBC URLを用いる方法ではテストコード内にコンテナを生成するための処理を記述する必要が無く、Testcontainers用JDBC URLを実際に接続するDB用のJDBC URLに変更すれば、そのまま実際のDBを使用したテストに切り替えることもできます。 Testcontainers用JDBC URLの形式 実際のJDBC URLを以下の手順で修正することでTestcontainers形式のJDBC URLになり、テスト実行時に指定したイメージのDBコンテナが生成されるようになります。Spring Bootを使用している今回の例であれば、spring.datasource.urlプロパティにTestcontainers用JDBC URLを指定すると、Testcontainersが有効になります。 jdbc:の後ろにtc:を挿入する ドライバ名をDockerイメージ名:タグ名に置き換える - jdbc:mysql://localhost:3306/databasename + jdbc:tc:mysql:8.0://localhost:3306/databasename (「tc」を挿入し、「mysql」というドライバ名を「mysql:8.0」というDockerイメージ名に置換) また、Testcontainers用JDBC URL内ではホスト名:ポート番号/データベース名は無視されるので、最終的に以下のように短縮できます。 - jdbc:tc:mysql:8.0://localhost:3306/databasename + jdbc:tc:mysql:8.0:/// (「ホスト名:ポート番号/データベース名」を除去) この短縮形式をhost-less URIsと呼びます。 jdbc:tc:[Dockerイメージ名]:[タグ名]/// JDBC URLを見たとき、Testcontainersを使用していることがすぐに分かるため、テスト用のJDBC URLにはhost-less URIsを使うことをお勧めします。 TestcontainersではJDBC URLの短縮有無によらず、生成されるコンテナのデータベース名,使用されるユーザー名やパスワードは一律testに固定されます。これらを変更したい場合は、前述のDatabase container objectsによりコンテナを生成してください。 公式リファレンス内の解説では、 Note that the hostname, port and database name will be ignored;(訳: ホスト名,ポート番号,DB名は無視されます) と明記されているにもかかわらず、jdbc:mysql:8.0:///databasenameのようにDB名のみを指定したJDBC URLが例示されていますが、2022/02現在、指定したDB名は生成されるコンテナに反映されません。GitHubのissueでこの点について議論されています。 オプションの指定方法 Testcontainers用JDBC URLには、クエリパラメータ形式でオプションを指定することができます。複数のオプションを指定する場合もクエリパラメータの形式同様に&で連結します。 オプションの種類はいくつかありますが、ここではTC_INITSCRIPTについて解説します。その他のオプションについては公式リファレンスを参照してください。DBイメージで固有のオプション等も存在します。 TC_INITSCRIPT テストコードの実行前に、生成されたDBコンテナを初期化するためのSQLファイルを実行させるためのオプションです。Testcontainersにより生成されたDBコンテナは空っぽの状態で、テーブルもテスト用データも含まれていません。そのため、このオプションを用いてDDLやテストデータの投入を行うSQLをあらかじめ実行しておくよう指示します。 このオプションを使用するためには、Testcontainers用JDBC URLにクエリパラメータとして TC_INITSCRIPT=[初期化用SQLファイルのパス] を付加します。パスは「クラスパスルートからの絶対パス」で指定してください。 jdbc:tc:mysql:8.0:///?TC_INITSCRIPT=path/to/ddl.sql (DBコンテナ生成後に、「ddl.sql」というSQLファイルを実行させる場合の例) テストコードの記述方法 実際にTestcontainersにより生成されるDBコンテナを使用するテストコードを記述する方法について解説します。 初めにサンプルテストコードを掲載し、それぞれのポイントについて解説していきます。 UserDaoTest.java(抜粋) @Testcontainers // (1) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // (2) @MybatisTest // (3) @Sql("classpath:path/to/testdata.sql") // (4) class UserDaoTest { @Autowired private UserDao dao; @Test void testUserDao() { // (5) } } (1) @​Testcontainers テストクラスでTestcontainersにより生成されるDockerコンテナを使用することを宣言するためのアノテーションです。テストクラスにこのアノテーションを付与することで、テスト実行前にJDBC URLに基づき、DBコンテナが生成・初期化されます。 @Testcontainers(disabledWithoutDocker = true) のようにdisableWithoutDockerパラメータにtrueを指定すると、テスト実行時にDockerが利用できなかった場合はテストがスキップされるようになります。(WindowsPCを使っている場合、Docker Desktopを起動せずにテストを実行するとテストがスキップされることが確認できます。) (2) @​AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) Spring Bootでデフォルトで有効になっているテスト用組込DBを無効化するためのアノテーションです。本アノテーションを付与する代わりに、spring.test.database.replaceプロパティにnoneを指定することでも同様の効果があります。 (3) @​MybatisTest 今回はO/RマッパーとしてMyBatisを使用するため、テストコード内でMyBatis関連のAutoConfigureクラス,MapperクラスのBeanのみが有効になるよう本アノテーションを付与しています。 @MyBatisTestについては、こちらの記事を参照してください。 (4) @​Sql 各テストメソッド前に、指定されたSQLファイルを実行してくれるアノテーションです。DBコンテナにテストデータを投入する用途で使用しています。 前述のTC_INITSCRIPTオプションでもSQLファイルを用いたDBコンテナの初期化を行うことができますが、TC_INITSCRIPTオプションではSQLファイルを1つしか指定することができません。そのため、DDLとテストデータ投入を1つのSQLファイル内に記述する必要があります。 DDLとテストデータ投入は別のSQLファイルで管理したい場合や、テストケースに応じて投入するテストデータを切り替えたい場合は、本サンプルのように@Sqlアノテーションでテストデータの投入を行っています。その他、DBUnitなどのツールもTestcontainersと併用可能です。 (5) テストメソッドの実装 各テストメソッド内ではTestcontainersを意識することなく、実際のDBを用いる場合と全く同じようにテストコードを記述することができます。 プロパティファイルの記述方法 本サンプルではSpring Bootを用いているので、Testcontainersに関するプロパティファイルの記述についても解説します。 spring.datasource.url=${DATASOURCE:jdbc:tc:mysql:8.0:///?TC_INITSCRIPT=path/to/ddl.sql} spring.datasource.username=${DATASOURCE_USER:} spring.datasource.password=${DATASOURCE_PASSWORD:} spring.test.database.replace=none spring.datasource.url Testcontainers用JDBC URLを指定します。 このサンプルでは${環境変数:デフォルト値}の形式でプロパティ値を指定しており、環境変数DATASOURCEに値が設定されていればその値をJDBC URLとして使用し、設定されていなければTestcontainers用JDBC URLを使用するようになっています。 JDBC URLがTestcontainers用の形式でなければ、テストクラスに前述の@Testcontainersアノテーションが付与されていてもDBコンテナの生成は行われません。そのため、ステージング環境などでは環境変数を設定しておくことで実際のDBを用いたテストを行い、ローカル環境ではDBコンテナを用いたテストを行うというようなことが、テストコードを修正したり複数用意したりすることなく実現できます。 spring.datasource.username,spring.datasource.password こちらも${環境変数:デフォルト値}の形式ですが、デフォルト値を指定していません。前述のとおり、Testcontainers用JDBC URL使用時はユーザー名やパスワードはtestで固定され、指定することができないのでこのようにプロパティ値を指定しています。 spring.test.database.replace 前述した@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)アノテーションを使う代わりに、プロパティファイルで設定する場合の記述です。 テスト実行 通常のテストと同様に、EclipseやMavenで実行することができます。 以下はテストを実行した際に出力されるログです。(指定したDockerイメージをTestcontainersで初めて使用する場合は数分以上時間がかかります。) . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.6.2) 2022-01-31 10:55:26.500 INFO 16468 --- [ main] com.example.UserDaoTest : Starting UserDaoTest using Java 17.0.1 on with PID 16468 (started by) 2022-01-31 10:55:26.502 INFO 16468 --- [ main] com.example.UserDaoTest : No active profile set, falling back to default profiles: default 2022-01-31 10:55:27.819 INFO 16468 --- [ main] com.example.UserDaoTest : Started UserDaoTest in 1.891 seconds (JVM running for 3.261) 2022-01-31 10:55:27.868 INFO 16468 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2022-01-31 10:55:28.130 INFO 16468 --- [ main] o.t.d.DockerClientProviderStrategy : Loaded org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first 2022-01-31 10:55:28.723 INFO 16468 --- [ main] o.t.d.DockerClientProviderStrategy : Found Docker environment with local Npipe socket (npipe:////./pipe/docker_engine) 2022-01-31 10:55:28.725 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : Docker host IP address is localhost 2022-01-31 10:55:28.779 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : Connected to docker: Server Version: 20.10.11 API Version: 1.41 Operating System: Docker Desktop Total Memory: 4711 MB 2022-01-31 10:55:28.784 INFO 16468 --- [ main] o.t.utility.ImageNameSubstitutor : Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor') 2022-01-31 10:55:29.215 INFO 16468 --- [ main] o.t.utility.RegistryAuthLocator : Credential helper/store (docker-credential-desktop) does not have credentials for index.docker.io 2022-01-31 10:55:32.569 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : Ryuk started - will monitor and terminate Testcontainers containers on JVM exit 2022-01-31 10:55:32.570 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : Checking the system... 2022-01-31 10:55:32.571 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : ✔︎ Docker server version should be at least 1.6.0 2022-01-31 10:55:32.706 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : ✔︎ Docker environment should have more than 2GB free disk space 2022-01-31 10:55:32.725 INFO 16468 --- [ main] ? [mysql:8.0] : Creating container for image: mysql:8.0 2022-01-31 10:55:32.879 INFO 16468 --- [ main] ? [mysql:8.0] : Starting container with ID: 466df4de50fe211466427c0c56d673ba8ebb9b4edbf8f124eb654560614bb8a2 2022-01-31 10:55:33.253 INFO 16468 --- [ main] ? [mysql:8.0] : Container mysql:8.0 is starting: 466df4de50fe211466427c0c56d673ba8ebb9b4edbf8f124eb654560614bb8a2 2022-01-31 10:55:33.325 INFO 16468 --- [ main] ? [mysql:8.0] : Waiting for database connection to become available at jdbc:mysql://localhost:62119/test using query 'SELECT 1' 2022-01-31 10:55:48.318 INFO 16468 --- [ main] ? [mysql:8.0] : Container is started (JDBC URL: jdbc:mysql://localhost:62119/test) 2022-01-31 10:55:48.318 INFO 16468 --- [ main] ? [mysql:8.0] : Container mysql:8.0 started in PT15.6056995S 2022-01-31 10:55:48.353 INFO 16468 --- [ main] org.testcontainers.ext.ScriptUtils : Executing database script from META-INF/mysql/ddl.sql 2022-01-31 10:55:48.406 INFO 16468 --- [ main] org.testcontainers.ext.ScriptUtils : Executed database script from META-INF/mysql/ddl.sql in 52 ms. 2022-01-31 10:55:48.420 INFO 16468 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2022-01-31 10:55:48.430 INFO 16468 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@3576ddc2 testClass = UserDaoTest, testInstance = com.example.UserDaoTest@cd1e646, testMethod = testDelete@UserDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@35b74c5c testClass = UserDaoTest, locations = '{}', classes = '{class com.example.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.mybatis.spring.boot.test.autoconfigure.MybatisTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@2e570ded key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61001b64, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@26e356f0, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@272113c4, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@3f6f6701, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@9647a2c9, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@13e344d, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.jdbc.support.JdbcTransactionManager@73608eb0]; rollback [true] 2022-01-31 10:55:49.394 INFO 16468 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@3576ddc2 testClass = UserDaoTest, testInstance = com.example.UserDaoTest@cd1e646, testMethod = testDelete@UserDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@35b74c5c testClass = UserDaoTest, locations = '{}', classes = '{class com.example.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.mybatis.spring.boot.test.autoconfigure.MybatisTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@2e570ded key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61001b64, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@26e356f0, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@272113c4, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@3f6f6701, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@9647a2c9, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@13e344d, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]] 2022-01-31 10:55:49.411 INFO 16468 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@3576ddc2 testClass = UserDaoTest, testInstance = com.example.UserDaoTest@266da047, testMethod = testSelect@UserDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@35b74c5c testClass = UserDaoTest, locations = '{}', classes = '{class com.example.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.mybatis.spring.boot.test.autoconfigure.MybatisTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@2e570ded key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61001b64, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@26e356f0, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@272113c4, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@3f6f6701, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@9647a2c9, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@13e344d, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.jdbc.support.JdbcTransactionManager@73608eb0]; rollback [true] 2022-01-31 10:55:49.456 INFO 16468 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@3576ddc2 testClass = UserDaoTest, testInstance = com.example.UserDaoTest@266da047, testMethod = testSelect@UserDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@35b74c5c testClass = UserDaoTest, locations = '{}', classes = '{class com.example.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.mybatis.spring.boot.test.autoconfigure.MybatisTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@2e570ded key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61001b64, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@26e356f0, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@272113c4, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@3f6f6701, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@9647a2c9, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@13e344d, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]] 2022-01-31 10:55:49.468 INFO 16468 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2022-01-31 10:55:50.017 INFO 16468 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. 参考 https://www.testcontainers.org/ https://b1a9idps.com/posts/test-containers/ https://zenn.dev/kentama/articles/aa7bbe728845da ご意見・ご指摘等あればコメントいただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Springで自動生成されるBean名をFQCNに変更する方法

はじめに デフォルトBean名をFQCNにするための方法について解説します。すでに同様の内容を解説したページがいくつかありますが、独自のBeanNameGenerator実装クラスを定義する内容のものが多く、標準で用意されているBeanNameGenerator実装クラスを利用する例や複数の設定方法を網羅している解説は無かったため、備忘録として残しておきます。 概要 SpringでアノテーションベースのBean定義を行う場合、特にBean名を明示しない限り、暗黙的にLower Camel Caseのクラス名がBean名として与えられます。パッケージ名は無視されてしまうので、状況によってはBean名が重複しConflictingBeanDefinitionExceptionが発生してしまうことがあります。 package com.example.demo.package1 @Service public class UserService { /* Bean名:userService */ } package com.example.demo.package2 @Service public class UserService { /* Bean名:userService */ } クラス名を変更したり、アノテーションにBean名を渡したりすれば回避できますが、クラス数が多いとその管理も面倒になります。 package com.example.demo.package1 @Service("userService1") public class UserService { /* Bean名:userService1 */ } package com.example.demo.package2 @Service("userService2") public class UserService { /* Bean名:userService2 */ } デフォルトで与えられるBean名をパッケージ名まで含めたFQCNにすることで、この問題を回避することができます。 BeanNameGeneratorの指定 Springのコンポーネントスキャン時に使用されるBeanNameGeneratorインターフェースの実装クラスをFullyQualifiedAnnotationBeanNameGeneratorクラスに変更することで、デフォルトで与えられるBean名をFQCNに変更することができます。 BeanNameGeneratorインターフェースは、コンポーネントスキャン時にBean名を自動生成するために使われるインターフェースで、Bean名の生成ロジックはその実装クラスに依存します。デフォルトで使用される実装クラスはAnnotationBeanNameGeneratorクラスです。 コンポーネントスキャン時に使用されるBeanNameGenerator実装クラスを指定する方法はいくつか存在します。 ※FullyQualifiedAnnotationBeanNameGeneratorクラスはSpring Framework 5.2.3 (Spring Boot 2.2.3)で追加されたため、それ以前のバージョンを使用する場合はこの記事等を参考に、独自のBeanNameGenerator実装クラスを定義して使用してください。 @​SpringBootApplication で指定する SpringBootを使用している場合には、メインクラスに付与する@SpringBootApplicationアノテーションのnameGeneratorパラメータにBeanNameGenerator実装クラスを指定することで、コンポーネントスキャン時にその実装クラスが使用されるようになります。 @SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class) public class DemoApplication { /*...*/ } @​ComponentScan で指定する SpringBootを使用せず、JavaベースでBean定義を行っている場合は、@ComponentScanアノテーションのnameGeneratorパラメータにBeanNameGenerator実装クラスを指定することで、コンポーネントスキャン時にその実装クラスが使用されるようになります。 @Configuration @ComponentScan(basePackages = "com.example.demo", nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class) public class AppConfig { /*...*/ } XMLで指定する SpringBootを使用せず、XMLベースでBean定義を行っている場合は、<context:component-scan>タグのnameGenerator属性にBeanNameGenerator実装クラスのFQCNを指定することで、コンポーネントスキャン時にその実装クラスが使用されるようになります。 <context:component-scan base-package="com.example.demo" name-generator="org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator" /> MyBatis を使用する場合 MyBatisのMapperクラスなどのように、Springのコンポーネントスキャン以外の方法でBean登録されるBeanについては、前述の設定とは別の設定が必要になることがあります。 MyBatisでは、以下の方法でMapperに適用されるデフォルトBean名の生成に使用されるBeanNameGenerator実装クラスを指定することができます。 @​MapperScan で指定する SpringBootを使用している場合や、JavaベースでBean定義を行っている場合は、@MapperScanアノテーションのnameGeneratorパラメータにBeanNameGenerator実装クラスを指定することで、マッパースキャン時にその実装クラスが使用されるようになります。 @SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class) @MapperScan(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class) public class DemoApplication { /*...*/ } XMLで指定する SpringBootを使用せず、XMLベースでBean定義を行っている場合は、<mybatis:scan>タグのnameGenerator属性にBeanNameGenerator実装クラスのFQCNを指定することで、マッパースキャン時にその実装クラスが使用されるようになります。 <mybatis:scan base-package="com.example.demo" name-generator="org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator" /> 参考 https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/FullyQualifiedAnnotationBeanNameGenerator.html https://mybatis.org/spring/ja/mappers.html#Mapper_.E3.81.AE.E8.87.AA.E5.8B.95.E6.A4.9C.E5.87.BA https://qiita.com/yu_bookstore/items/07e905cb5b645781bc43 https://ocs.hatenadiary.org/entry/20101129/1291034951 ご意見・ご指摘等あればコメントいただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

mybaits-spring-boot-starter-testの使い方

はじめに MyBatis-Spring-Boot-Starter-Testを使ってMapperクラスのテストコードを書いてみたので備忘録を残します。 概要 Spring BootでMyBatisを使用しており、MyBatisにより自動生成されたMapperクラスのテストを行う場合は、SpringのDIコンテナを使ってテストを行う必要があります。しかし、単に@SpringBootTestアノテーション等でSpring Bootの機能を有効にするだけでは、Mapperクラスのテストに不要なAutoConfigureクラスが有効になったり、不要なBeanが生成されたりしてしまいます。 MyBatis-Spring-Boot-Starter-Testを使用することで、このような問題を回避できます。 環境 Java Junit5 SpringBoot MyBatis Testcontainers Maven Windows10 依存関係 MyBatis-Spring-Boot-Starter-Testを使用するためには、以下の依存関係を<dependencies>に追加してください。 <dependencies> ... <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter-test</artifactId> <version>2.2.0</version> <scope>test</scope> </dependency> ... </dependencies> その他、Spring BootやMyBatisを利用するための依存関係も適宜追加してください。 テストコードの記述方法 MyBatis-Spring-Boot-Starter-Testを有効にするための@MybatisTestアノテーションをテストクラスに付与することで、MyBatis関連のAutoConfigureクラスのみが有効になり、MapperクラスのみがDIコンテナにBean登録されるようになります。 @MybatisTest // MyBatis-Spring-Boot-Starter-Testの有効化 class UserMapperTest { @Autowired private UserMapper mapper; // Mapper実装クラスがインジェクション可能になる @Test void testUserMapper () { /* ... */ } } また、@MybatisTestアノテーションのincludeFiltersパラメータやexcludeFiltersパラメータを指定することで、DIコンテナに登録されるBeanを追加したり減らしたりすることも可能です。 @MybatisTest(includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { UserService.class, AppConfig.class })) // Mapperクラス以外にも、指定したBeanやJavaConfigもDIコンテナに登録されるよう指定 class UserDaoTest { @Autowired private UserDao dao; @Autowired private UserService dao; // 指定したBeanもインジェクション可能になる @Autowired private PasswordEncoder encoder; // 指定したJavaConfigで定義されているBeanもインジェクション可能になる /* ... */ } } Beanのフィルタリングについては、このページ等を参照してください。 クラスによるフィルタリング以外に、アノテーションの有無によるフィルタリングや正規表現によるフィルタリングも存在します。 参考 http://mybatis.org/spring-boot-starter/mybatis-spring-boot-test-autoconfigure/index.html https://qiita.com/kazuki43zoo/items/ea79e206d7c2e990e478#mybatistestmybatis-spring-boot-starter-test%E3%81%AE%E5%88%A9%E7%94%A8 ご意見・ご指摘等あればコメントいただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring + lombokでコンストラクタインジェクションする際にBean名を指定する方法

はじめに Lombokの@AllArgsConstructorアノテーションや@RequiredArgsConstructorアノテーションを使用してコンストラクタインジェクションを行う際に、Springの@QualifierアノテーションでインジェクトするBean名を明示する方法について解説します。 すでに同様の内容を解説しているページがいくつかありますが、設定ファイルの配置位置や設定内容自体についての解説はあまり無く、追加で調べる必要があったので備忘録として残しておきます。 概要 コンストラクタインジェクションでインジェクトするBean名を明示したい場合は、以下のようにコンストラクタの引数に@Qualifierアノテーションを付与する必要があります。 MyController.java @Controller public class MyController { private final MyService service; public MyController(@Qualifier("myServiceImpl")MyService service) { this.service = service; } } しかし、Lombokの@AllArgsConstructorアノテーションや@RequiredArgsConstructorアノテーションを使用してコンストラクタを自動生成する場合、そのままでは引数に@Qualifierアノテーションは付与されません。 このような場合、lombok.configファイルを作成することで、自動生成されるコンストラクタに@Qualifierアノテーションが付与されるよう設定することができます。 lombok.configファイルの作成・配置 lombok.configファイルは、Lombokの挙動をデフォルトから変更したい場合に作成する設定ファイルです。通常は、プロジェクトルートやソースフォルダのルートにlombok.configファイルを作成します。 lombok.configファイルによる設定内容は、lombok.configファイルを配置したディレクトリ内と、そのサブディレクトリ内に存在するソースコードに適用されます。また、サブディレクトリ内に別のlombok.configファイルを配置することで、そのディレクトリとそのサブディレクトリに対して適用される設定を変更することも可能です。 lombok.configファイルの記述 今回は、設定項目のひとつであるlombok.copyableAnnotationsプロパティに設定を行います。 lombok.config lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier このプロパティは、フィールドに付与されるアノテーションのうち、そのフィールドに対するセッターやコンストラクタの引数にも付与しておきたいアノテーションを指定するための項目です。このプロパティには複数のアノテーションを追加できるよう、=ではなく+=でアノテーションを指定します。 このプロパティに@QualifierアノテーションのFQCNであるorg.springframework.beans.factory.annotation.Qualifierを追加しておくと、インジェクト対象のフィールドに@Qualifierアノテーションを付与しておけば、Lombokにより生成されるコンストラクタの引数にも同じ内容の@Qualifierアノテーションが付与されます。 MyController.java(delombok前) @RequiredArgsConstructor @Controller public class MyController { /* インジェクト対象フィールドに@Qualifierアノテーションを付与しておく */ @Qualifier("myServiceImpl") private final MyService service; } MyController.java(delombok後) @Controller public class MyController { @Qualifier("myServiceImpl") private final MyService service; /* 生成されたコンストラクタの引数にも@Qualifierアノテーションが付与された */ @java.lang.SuppressWarnings("all") public MyController(@Qualifier("myServiceImpl") final MyService service) { this.service = service; } } 参考 https://projectlombok.org/features/configuration https://qiita.com/hrkt/items/e7c67c4d4de53bcb613b https://stackoverflow.com/questions/38549657/is-it-possible-to-add-qualifiers-in-requiredargsconstructoronconstructor ご意見・ご指摘等あればコメントいただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring + lombokでコンストラクタインジェクションする際に、Bean名を指定する方法

はじめに Lombokの@AllArgsConstructorアノテーションや@RequiredArgsConstructorアノテーションを使用してコンストラクタインジェクションを行う際に、Springの@QualifierアノテーションでインジェクトするBean名を明示する方法について解説します。 すでに同様の内容を解説しているページがいくつかありますが、設定ファイルの配置位置や設定内容自体についての解説はあまり無く、追加で調べる必要があったので備忘録として残しておきます。 概要 コンストラクタインジェクションでインジェクトするBean名を明示したい場合は、以下のようにコンストラクタの引数に@Qualifierアノテーションを付与する必要があります。 MyController.java @Controller public class MyController { private final MyService service; public MyController(@Qualifier("myServiceImpl")MyService service) { this.service = service; } } しかし、Lombokの@AllArgsConstructorアノテーションや@RequiredArgsConstructorアノテーションを使用してコンストラクタを自動生成する場合、そのままでは引数に@Qualifierアノテーションは付与されません。 このような場合、lombok.configファイルを作成することで、自動生成されるコンストラクタに@Qualifierアノテーションが付与されるよう設定することができます。 lombok.configファイルの作成・配置 lombok.configファイルは、Lombokの挙動をデフォルトから変更したい場合に作成する設定ファイルです。通常は、プロジェクトルートやソースフォルダのルートにlombok.configファイルを作成します。 lombok.configファイルによる設定内容は、lombok.configファイルを配置したディレクトリ内と、そのサブディレクトリ内に存在するソースコードに適用されます。また、サブディレクトリ内に別のlombok.configファイルを配置することで、そのディレクトリとそのサブディレクトリに対して適用される設定を変更することも可能です。 lombok.configファイルの記述 今回は、設定項目のひとつであるlombok.copyableAnnotationsプロパティに設定を行います。 lombok.config lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier このプロパティは、フィールドに付与されるアノテーションのうち、そのフィールドに対するセッターやコンストラクタの引数にも付与しておきたいアノテーションを指定するための項目です。このプロパティには複数のアノテーションを追加できるよう、=ではなく+=でアノテーションを指定します。 このプロパティに@QualifierアノテーションのFQCNであるorg.springframework.beans.factory.annotation.Qualifierを追加しておくと、インジェクト対象のフィールドに@Qualifierアノテーションを付与しておけば、Lombokにより生成されるコンストラクタの引数にも同じ内容の@Qualifierアノテーションが付与されます。 MyController.java(delombok前) @RequiredArgsConstructor @Controller public class MyController { /* インジェクト対象フィールドに@Qualifierアノテーションを付与しておく */ @Qualifier("myServiceImpl") private final MyService service; } MyController.java(delombok後) @Controller public class MyController { @Qualifier("myServiceImpl") private final MyService service; /* 生成されたコンストラクタの引数にも@Qualifierアノテーションが付与された */ @java.lang.SuppressWarnings("all") public MyController(@Qualifier("myServiceImpl") final MyService service) { this.service = service; } } 参考 https://projectlombok.org/features/configuration https://qiita.com/hrkt/items/e7c67c4d4de53bcb613b https://stackoverflow.com/questions/38549657/is-it-possible-to-add-qualifiers-in-requiredargsconstructoronconstructor ご意見・ご指摘等あればコメントいただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む