メモ。公式ドキュメントにはv1の作り方しか書いてないのだが、v2も別のドキュメント読み解けばちゃんと作れるよ、ということを教えてもらった。
https://github.com/spotbugs/spotbugs-archetype/pull/7#issuecomment-320870124
メモ。公式ドキュメントにはv1の作り方しか書いてないのだが、v2も別のドキュメント読み解けばちゃんと作れるよ、ということを教えてもらった。
https://github.com/spotbugs/spotbugs-archetype/pull/7#issuecomment-320870124
過去にFindBugsプラグインの実装方法について記事にしたとおり、FindBugsプラグインの実装には複雑なハックが必要でした。特にfindbugs.xmlやmessages.xmlなどのメタデータ管理が煩雑でした。
これがSpotBugs 3.1.0-RC3ではある程度楽になっているので、シンプルになった方法をここにまとめておきます。
archetypeがコミュニティから提供されるようになりました。これを使えばプラグイン開発の知識がなくてもすぐにプロジェクトを作成できます。
使い方は他のmaven archetypeと同じで、archetype:generate
実行時にarchetypeのgroupId, artifactIdそしてversionを指定するだけです。現状バージョン0.1.0が最新なので、以下のコマンドを実行してください:
$ mvn archetype:generate \ -DarchetypeArtifactId=spotbugs-archetype \ -DarchetypeGroupId=com.github.spotbugs \ -DarchetypeVersion=0.1.0
プロジェクト生成に成功すると、src/test/java
に2つのクラスが見つかるはずです。
これらを実際に解析して結果を確認しているテストケースもあります。
このテストケースは、SpotBugsが出しているtest-harnessモジュールを使っています*1。SpotBugsRuleというクラスがキモで、これを使って実際の.classファイルを解析し結果を確認できます。assertion用のMatcherクラスも提供されているので、hamcrestを使ったテストも書きやすいです。
@Rule public SpotBugsRule spotbugs = new SpotBugsRule(); @Test public void testIssuesAreFound() { Path path = Paths.get("target/classes/my/company/AnalyzedClass.class") BugCollection bugCollection = spotbugs.performAnalysis(path); // There should only be exactly 1 issue of this type final BugInstanceMatcher bugTypeMatcher = new BugInstanceMatcherBuilder() .bugType("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE").build(); assertThat(bugCollection, containsExactly(bugTypeMatcher, 1)); final BugInstanceMatcher bugInstanceMatcher = new BugInstanceMatcherBuilder() .bugType("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") .inClass("AnalyzedClass") .atLine(25) .build(); assertThat(bugCollection, hasItem(bugInstanceMatcher)); }
以前はプラグインを実際に使ったテストをするためにはfindbugs-maven-pluginを使ってインテグレーションテストを回すしか方法がありませんでしたが、この手法ならより高速にテストを回せます。また test-driven-detectors4findbugsと違って公式なので、今後のSpotBugsの更新にも追随できるはずです*2。
まずbugrank.txtは現状必要ないようです。無くてもプラグインはビルドできます。そもそもBugRankという概念はこの論文でやこのページ紹介されている通り、SonarQubeのSeverityのようなもので、priority (confidence)とは全く別の概念です。が、果たしてそれがどの程度浸透しているのか……。SpotBugsが使うpriorityやpriority (confidence)のことは忘れてSonarQubeのSeverityだけ使うのが、運用も回しやすいと思います。
ので、全体的な情報を提供するfindbugs.xmlと、ユーザ向けメッセージを管理するmessages.xmlだけ作成すれば十分です。プロジェクトの雛形にはこれらが既に作成されているので、それを参考にコピペで要素を増やしてください。
SonarQubeプラグインは sonar-packaging-maven-plugin
を使ってパッケージできます。sonar-findbugsと拙作findbugs-slf4jが参考になります。
キモはfindbugs-pluginバージョン3.5への依存を宣言することです。このバージョンはSpotBugs 3.1.0-RC2を使っているため、SpotBugsに依存したプラグインを書くには必須です。
なおsonar-findbugsバージョン3.5はpre-releaseバージョンで、まだSonarQubeのUpdate Centerでは配布されていません。使用する際はGitHubのリリースページからjarを落としてきて手動インストールする必要があります。
またSonarQube用のrule.xmlを生成する必要があるのですが、これは雑ですがMavenプラグインを作ったので使ってもらえればと思います。Groovy好きな方はsonar-findbugsのコードを参照しても良いでしょう。
以上でSpotBugsプラグインを実装してSonarQubeも含めた運用を回すことができるはずです。 まだ各種親Detectorを学習する手間は必要ですが、5年前に比べてだいぶマシにはなりました。
追記:公式かつ英語のドキュメントもできました。
*1:find-sec-bugsからコードを持ってきて作られたもの
*2:test-driven-detectors4findbugsはFindBugs 1.3.9〜2.0.2にしか対応していなかった
前回のエントリでの宣言通り、本日のJJUG CCCでセッション発表してきました。発表のスライドと動画が後日、下記会社のアカウントから共有されると思います。公開されたらこの記事で紹介します。
昼休み明けすぐの発表でしたが、だいたい140名ほど参加いただけたようです。全日程では1,032名の参加があったそうですが、セッション発表時点では700名近く参加されていたらしいので、全体の2割近い方が参加されていたことになりますでしょうか。FindBugsの知名度を改めて感じました。
静的解析ツール初心者の聴講者はゼロだったので、最初の方の静的解析ツールのメリットについてはかなり端折り、突っ込んだ内容を厚めに話しました。プラグイン開発デモができなかったのは残念でしたが、spotbugs-archetypeを使っていただければある程度は伝わる……といいなぁと思います。
また懇親会でのLTでも2分ほど話してきました。こちらは純粋にSpotBugsの中の人としての参加です。SpotBugs 3.1.0 RC2はわりと安定していますので、皆さんも使えるところで試してフィードバックいただければと思います。
セッションのスライドが公開されました。
www.slideshare.net
最近ブログ熱が下がっていたのと、SpotBugsの中の人になってドキュメントとかいろいろ触っていたのとで更新が途絶えていました。
そろそろSpotBugs 3.1.0−RC2を出せるのではと思いますので、そのうち試してください。
なおJava8対応強化だけであればリリース済みのRC1でも試せます。RC2ではEclipse Plugin周りの強化が入る予定です。
さてFindBugsのフォークであるSpotBugsについて、今週土曜日に開催されるJJUG CCC 2017 Springでセッションをします。
勤め先がスポンサーをしている縁での参加となるため、SpotBugsの中の人としてのPRだけでなく、SpotBugsを業務利用している立場としての工夫や注意点、運用についても話す予定です。日本での発表はかなり久々ですが、面白い話ができればと思います。
お前誰?という方のために、過去の発表資料を載せておきます。最近やっているのはJavaとJavaScriptとDockerとMSAが多いです。
先週、FindBugsのメーリスに興味深い宣言が流れました。今のFindBugsはメンテ困難であり現体制での継続保守が難しいとするものです。
ただこれをもってFindBugsはおしまいだ、としてしまうのはちょっと違います。コミュニティ自体はまだ活発で、プロジェクトのあるべき姿について話し合っています。私はコミッタでもなんでもないのですが、1週間経ったこともあり日本語で簡単に経緯を紹介したいと思います。
出典明示のため細かくリンクを張りますが、リンク先を見ずとも本エントリだけで理解できるよう努めます。
1年以上前から、プロジェクトリーダーのBill Pugh氏はコミュニティ開発者からの連絡に返信しなくなりました。メールもそうですがGitHubやTwitterでのmentionにも返信しません。私もこの5月にTwitterで連絡を取ろうとしましたがやはり返信はありませんでした。
彼だけがSourceForgeとGitHubの管理者権限を持っているので、彼の協力なしにはウェブサイトの更新も新バージョンのリリースもTravis CIの導入もできません。これがプロジェクトを停滞させている最大の問題です。
なお上記のメールが流れた今でも返信がなく、Hacker Newsに「1週間時間をくれ」と一方的に声明を出しただけです。そしてその1週間が経過した今でも連絡はありません。コミュニティオフィシャルの場に現れないこの姿勢は、本当に戻ってくるつもりがあるのか不安にさせるものです。
このような状態ではプロジェクトのフォークが検討されると思いますが、上記メールではフォークは推奨されていません。確かにSpotBugsというフォークがありますが、これはFindBugsと決別したものではなく、プロジェクトリーダー不在でも開発を続けるための最後の手段です。今後のプロジェクトリーダーの行動次第では、FindBugsにマージされる可能性があります。
FindBugsにはプラグイン機構があり、その上にfb-contribやfind-sec-bugsなどの素晴らしいプロダクトが作られています。またビルドツールやIDEとの高い親和性もあり、幅広いユーザに利用されてもいます。互換を考慮した上でJava9対応などの新機能を入れ、バグやドキュメントの不備を直していければ理想的です。
以上のように、現行のFindBugsユーザはまだ静観して構わない状況と考えます。このままSpotBugsがFindBugsにマージされなくても、JARファイルの名前が変わる程度の影響で当面は利用できるはずです。むしろドキュメントの不備が直りやすくなったり、修正リリースがより頻繁になったりと恩恵のほうが大きいのではないでしょうか。
それでもFindBugs以外の選択肢を検討したい場合は、当該スレッドで言及されたHuntBugsを試してみてください。FindBugsの機能の40%がカバーされているそうです。もちろんHuntBugsには別の課題があることには留意してください。
他にはIntelliJ IDEAも推奨されています。IDEAはIDEですが、バッチ(CI)に組み込んでXMLを出力させることも可能とのことです。
また個人的にはGoogleの開発しているError Proneに期待しています。Eclipse統合はだいぶ難しそうですが、動作が軽いですしテスタブルなプラグイン開発が可能です。Google社内でも使われているそうですし、今後しばらくは改善されていくと期待できます。
以上、 簡単に経緯と現状をまとめました。
コントリビュートに関心のある方は、FindBugsではなくSpotBugsのリポジトリをご覧ください。ドキュメントを更新するなかで、英語→日本語の翻訳は今後求められるはずです。単にFindBugsを使いたいという方は、ひとまず従来通りで大丈夫です。
MSAは理屈が多く、手を動かさないとわからないことが多すぎるので作りました。
ついでに非同期I/OとサーバサイドReactiveを学ぶためにVert.xとRxJavaを採用しています。Spring Framework 5は別で学ぶ機会があるので一旦除外。ひとまず試行錯誤できる環境が用意できた状態です。
docker-compose scale
でのマイクロサービスごとのスケールイン・スケールアウト自分にとっての新技術を試すための個人プロジェクトでVert.xを使っているのだが、PostgresクライアントがTechnical Previewになったのでオンメモリに乗せていたデータをpostgresに乗せるようにしたところ、2重3重のネストがコードに現れるようになった。
本当にこのネスト地獄はすごい。JS以上だ。 https://t.co/z8XEuz0svq
— Kengo TODA (@Kengo_TODA) July 25, 2016
そこでRxJavaを利用することでコードの短縮化を図った。以前利用したReactive Streamsとは別物とのこと。
Handlerベースの実装だとClassがだいたい100行だが、Observableベースの実装だと40行強で済んだ。ネスト数も抑えられている。
コードの見通しを良くしたのは例外処理。 Handler
(コールバック)内で処理が失敗したかどうか毎回確認していたのが、Stream API同様のmap処理に置き換えられた。
サービスを書いているとよくある「getConnectionしてトランザクションを開始してSELECTしてINSERTしてCOMMITする」という処理が、Handler
で書くと5重ネストと5回の例外処理に化けてしまう。ネストをメソッドチェーンに置き換えたうえで例外処理を一本化(主にSubscriber
側の処理になる)できるのは非常に見通しが良い。
// before postgreSQLClient.getConnection(connected -> { if (connected.failed()) { future.fail(connected.cause()); handler.handle(future); } else { SQLConnection con = connected.result();
// after return postgreSQLClient.getConnectionObservable() .flatMap(con -> {
postgresクライアントのInstant
の扱いにバグがある模様。現時点ではString
として取り出す必要がある。Technical Previewだし仕方ない。
非同期APIなのでリソースの解放にtry-with-resourcesやLoanパターンが使えない点に注意が必要。例えばDB接続を使い終わった時点で接続を閉じるには、以下のように Observable#doAfterTerminate(Action0)
を使う必要がある。これなら処理が正常終了した時も異常終了した時も実行される。
return postgreSQLClient.getConnectionObservable().flatMap(con -> { return con.queryObservable( "SELECT id, uploaded_file_name, resolutions, generated FROM task") .doAfterTerminate(con::close); }).flatMap(selected -> {
なおリソース解放用に用意されているObservable#using()
を律儀に使おうとすると以下のようになってしまい、EclipseのJavaコンパイラだとうまくコンパイルできないことがある。第一引数にFunction0(Resource)
ではなくFunction0(Observable<Resource>)
を使えるなら、() -> con
などという無意味なコードを書かなくて済んだのだが……。
実装を見るとusing()
はdoAfterTerminate()
とは全く違う複雑な処理をしているので、doAfterTerminate()
で完全な代替になるとは思わないほうが良さそうだ。Observable#using()
を自然に使えるような書き方を探す必要があるが、Vert.xのサンプルプロジェクトには現状usingを使ったサンプルは無い。
return postgreSQLClient.getConnectionObservable().flatMap(con -> { return Observable.using( () -> con, connection -> connection.queryWithParamsObservable("SELECT uploaded_file_name, resolutions, generated FROM task WHERE id = ?", params), connection -> connection.close()); }).flatMap(selected -> {
今のところ更新系など「値を返す必要はないけど正常終了したかどうかだけ確認したい」場合にObservable<Void>
を返しているが、Single<Void>
を使うほうがシンプルかもしれない。複数の結果が帰ってくることがないとわかっている以上、それを型として明示したほうが何かと混乱がなさそう。
現在のプロジェクトではScheduler
を一切使っていないが、Vert.xと組み合わせて使う以上その必要性は薄そうなので、GUIアプリで試す必要があるかも。
自分が想像できるのは非同期I/Oを多く持つサーバで、多数のI/Oをマージしてクライアントにレスポンスを返すような処理を書くこと。もちろんブロッキングI/Oも混ぜることも可能(Vert.xの機能に寄せるかScheduler
を利用する)。Stream APIとほぼ同じ感覚で扱える。
またObserver
とSubscriber
で利用するスレッドを指定できるので、UI Threadを極力あけたい&イベントベースで書きたいAndroidのようなGUIアプリにおいても活躍が期待されているように見える。もうずっとSwingに触れていないがおそらくSwingでも使えるだろうし、JavaFxバインディングは公式に存在するようだ。