Engineで動かすためのMavenアーキタイプを作成しました。Connectという作法に従って、Webアプリケーション(Atlassian製品の外で動作する)をアドオンとしてつくって製品と連携するということになっています。BootベースのフレームワークがAtlassian公式として公開されています。https://bitbucket.org/atlassian/atlassian-connect-spring-bootJIRAアドオンを気軽に作ろうと思うとこれを動かすためのサーバーを見つけないといけません。ここで無料のサーバーで動かしたい...と思うと、今だとGCPのフリーティアーが候補になると思います。ConnectではHTTPS通信を必須としていることで、GCEの場合だと追加でドメイン取得が必要となります。Dataがない)という点が問題でした(appspot.comドメインはHTTPSが使えます)。(1)については最近までGAEスタンダード環境ではJava7のみだったのが最近Java8対応したことで解消されました。(2)については自分で作ることで解消しました。Datastoreがそれです。手順にしたがってMavenアーキタイプからプロジェクトを作るとサンプルアプリが動くようになっていて、このアプリはJIRAから課題を取得してDatastoreに保存し、それを集計して表示するということをやっています(なお、Datastoreは集約関数が利用できないため本来こうした集計には向いていません。使い方の例としてそのようにしています)。Datastoreを作った。DatastoreというJavaのライブラリを開発しました。DatastoreのデータをCRUDするものです。クエリメソッド(インターフェイスにfindByFooOrderByBarなどメソッド定義するとそのメソッド名に従った実装を提供する機能)にも対応しています。単独ではインストールに失敗する。NetBeansが.externalの中に書かれたURLからダウンロードして置き換える仕組みになっているからだ。そのようなnbmファイルでもオフラインでインストールできる。下記のサイトでそのような方法が紹介されている。NetBeans80にofflineでJUnitをインストールしかしこれを手動で行うのは面倒だ。いうことで自動で行うツールを作った。https://github.com/tkob/nbmtoolsこれを使うと上掲の記事の作業は次のようにすればよい。org-netbeans-libs-junit4.nbmなお作ってはみたものの.externalを含むnbmファイルはあまり多くない気もしている。テストのためにYokohamaUnitをドッグフーディングしている。ひさしぶりにScalaを書いた。そのアノテーションを元にしてPairwise法を使ってテストデータを自動生成して実行してくれる。}}テストケースジェネレータとなるのはTupleGenerator型のオブジェクトである。TupleGenerator.Builderのfluentなコンストラクタでオブジェクトを作る。IPOというのはPairwiseのアルゴリズムの一種のようだ。今回は何も制約をつけないのでNullConstraintManagerを与えている。Factorsはテストケースの元となる一連の変数(Factor)の集まりである。Factorは変数名と変数がとりうる値(level)から成る。ParamはTupleGeneratorの実装固有のパラメタである。ここでは何も指定しない(デフォルト)ので空の配列を与えている。普通はJUnitテストクラスに書かれたアノテーションがそのまま来るようだ。まどろっこしい書き方をすることになると思う。ここではforEachメソッドで生成結果を取得している。Object>を継承していて、キーが変数名、値が変数の値となる。上記のコードの実行結果は次のようになる。ここでは4通りのみ生成されている。その一方で、任意の2つの変数の組み合わせはすべて登場するようになっている。[Java]Javaでヘテロなリスト、たとえばIntegerかStringのどちらかが入るリストを作っておきたいとする。これをちゃんと静的に型付けされるように書くとしたらJavaではVisitorを使うしかない。string);}これを使うときはたとえば次のようなコードを書く。}}ここまでは(Javaの冗長さ以外は)なにも問題ないと思う。ところでこのリストに対して行いたい処理がチェック例外を投げる処理だったらどうするか。出力先が標準出力でなくてファイルだったらIOExceptionをどうにかしないといけない。IOExceptionと書かないといけない。IOExceptionと書かないといけない。IOExceptionをつける。これは明らかにおかしい。IntegerOrStringというデータ型は、そのデータにどのような操作がなされうるかとは独立に定義されるはずだ。データと操作をデカップリングするためにVisitorパターンを使ったのだから。「このデータに何かする操作はIOExceptionを投げうる」ということをどうやってあらかじめ知ることができるというのだろうか。IntegerOrStringVisitorの実装クラスが増えるたびにIntegerOrStringインターフェイスまで立ち戻ってthrows節にチェック例外を追加するのはナンセンスだ。いくつか案を検討してみよう。visitメソッドで例外処理させるvisitメソッド内で例外処理させることを要件にすれば最初のシグニチャのままでどうにかなる。これは明らかに強すぎる制約で、現実的ではないと思う。visitメソッドで実行時例外に変換するvisitメソッド内でIOExceptionなどのチェック例外を適当な実行時例外に変換して投げるようにすれば、やはりシグニチャを変えずに済む。この案の問題点は例外を捕捉する側で「より小さい例外を捕捉する」という原則に沿った例外処理ができなくなることだ。悪い言い方をすると元の例外を覆い隠す。捕捉側で受け取るのは変換後の例外なのでcatch節を分けることができない。いや、正確に言うとgetCauseを使えば処理を変えることはできるが、どっちにしても普通の素直なtry/catchではできない。いう思想なりコーディング規約なりがあるということだ。ExceptionにしておけばVisitorがチェック例外を投げたとしてもデータやVisitorインターフェイスに後から手を入れなくても済む。このやり方は例外変換を伴わないので案2の最初の問題も存在しない。問題となりうるのはやはり思想・コーディング規約上のものだろう。Exceptionはだめだけしからんと言って笛を吹かれる可能性が高い。Exceptionが意外に感染力が高いというのもすこしがっかりする点だ。これはあまり意味がない。Exceptionを消すことはできない。Exceptionにしなければならない。Exceptionが伝搬していく。visitメソッドで専用のチェック例外に変換する最後の案は案2のバリエーションで、例えば次のようなチェック例外クラスを定義する。IntegerOrStringExceptionにして、visitメソッドの中でチェック例外が発生するときはこれを生成して元の例外をcauseにする。...これは例外の捕捉に関して案2と同じ欠点を持つ。一方でチェック例外を実行時例外にロンダリングするわけではない。案3とは異なりExceptionのサブクラスを投げるに過ぎないので例外ポリスをも満足させる。Java)という考えから行われることがある。JNDIの実装がファイルを使うにしてもDBを使うにしてもlookupメソッドがIOExceptionやSQLExceptionを投げるのは実装の詳細を曝しすぎているのでNamingExceptionのサブクラスに変換して投げるべきだ、というように。Visitorの場合、この考えから案4を支持するのは無理がある。Visitorに実装される処理は「そのデータに対する何らかの処理」というだけだ。これは何か必然性のある抽象だろうか?Visitorパターンを使わなくてすむ言語なら名前を付ける必要すらなかったものだ。「インターフェイスを定義するときに、どういう実装になるかあらかじめわからないがthrowsをどうするか」というのはVisitorに限らずインターフェイス一般に生じる問題だ。それは結局「そのインターフェイス/パッケージ用に新しくチェック例外を定義してインターフェイスの全部のメソッドにthrowsをつけて回る」ということになっていることが多い。JMSExceptionがついている。「その抽象化に適した例外」を定義したのだと主張することはできる。Visitorは処理自体を切り離したわけだから、具体性のある処理と結びついていない。(抽象度が上がるほど「例外が表している内容」は苦し紛れになってくる。java.util.concurrent.Future#getはExecutionExceptionというチェック例外を投げるが、これは単に任意の非同期処理の中で投げられる例外をラップしているだけだ)そうして考えると案4は単にコーディング規約を満足させるためだけに不必要な例外クラスを定義したにすぎないと思う。Exceptioの伝搬を受け入れるのが妥当ではないか、と考えている。この書き方のコードはチェック例外のないJVM言語で実行時に起こっていることと同じ動作をするものでもある。勉強していてエキゾチックだと感じるのはやはりチェック例外だ。このチェック例外という仕組みは、便利か邪魔か、ということはひとまず置くとしてやはり非常に興味深いものだと思う。チェック例外を自分なりに理解しやすいように整理・言い換えをしてみた。節に書かれる例外クラスを戻り値の型と比べてみよう。される型と不整合があるとコンパイルエラーになる。節の例外クラスと実際にメソッドから投げられうる例外との間に不整合があるとコンパイルエラーになる。いずれもメソッドのクライアントに対する契約の一部をなしているから、宣言された型より小さい型を実際に返す/投げる分には構わないが逆は不可である。(なお、この記事では継承関係にあってサブクラスに向かうほど小さい、逆を大きいと呼ぶ。節と同じか、それよりも小さい型を指定しなければならない。オーバーライドできるが、逆は不可である。overriding)。戻り値とチェック例外の類似点は一応ここまでである。チェック例外は戻り値とは異なり互いに継承関係にない複数の型を指定することができる。投げないという約束になる。一方で戻り値の型は1つだけだ。いうのと同じことである。「一応ここまで」と書いたのは、次のように捉えなおすことで例外と戻り値の型とのアナロジーを引き続き維持しようという企みからである。戻り値の型とは別に、そして例外クラス(とその階層)とも別物として、メソッドの「チェック例外に関する型」(およびその階層)を考える。型」と呼ぶことにする。型」は単に継承関係にない例外クラスの集合として表現される型である。ように表記することにする。型は次のような規則で階層をなす。型が包含関係にあるとき、部分集合のほうの型のほうが小さい。オーバーライドできる。型の要素の一部を例外クラス階層においてより小さいものに置き換えるとより小さい型になる。オーバーライドできる。型の階層の間の関係をいくつか例をあげて示す。型の階層は以下のようになる。例外の階層が以下だったら、こうなる。型の階層は以下のようになる。(*)例外の階層が以下だったら、こうなる。空集合からなる型である。