Clojure から Java の可変長引数をもつ関数の呼び出し
はてなブログ初めました。うおざです。
最初の記事に何を書こうか書こうかと考えていたら、いい感じに問題にあたったのでそれを書くことにしました。
それは Clojure で Javafx を呼びだしてファイルダイアログを表示させる際に、拡張子でフィルタをかけるようにしていたときのことです。
Clojure で以下のようなコードを書いていました。
(let [fileChooser (FileChooser.)] (-> fileChooser .getExtensionFilters (.add (FileChooser$ExtensionFilter. "Audio Files" "*.wav" "*.mp3" "*.aac"))))
しかし、これを実行すると
java.lang.IllegalArgumentException: No matching ctor found for class javafx.stage.FileChooser$ExtensionFilter, compiling:(scoreditor/application.clj:67:34) Exception in thread "main" java.lang.IllegalArgumentException: No matching ctor found for class javafx.stage.FileChooser$ExtensionFilter, compiling:(scoreditor/application.clj:67:34)
といったエラーがでます。
No matching ctor found for class javafx.stage.FileChooser$ExtensionFilter
クラスが見つからないようなことを言われています。
しかし、調べても Clojure でのインナークラスのコンストラクタの呼び出しは
(ClassName$InnerClass.)
で可能のはずなので不思議で不思議でした。Java で無理やり解決しましたが、やはりモヤモヤは消えず。
あまりにもわからないのでtwitterでつぶやいたら
なんでかわからないけれど結局
— うおざ (@p1scesCom) 2016年9月25日
FileChooser$ExtensionFilter のコンストラクタは Clojure から呼び出せなかったので java でFileChooser を受け取ってそれを操作して ExtensionFilter を追加する関数作って対処しました。
リプライがきました。
@p1scesCom どんなコード書いたんでしょう?
— つるふさの法則 (@_ayato_p) September 25, 2016
Clojure で調べたら日本語の情報で度々目にする @_ayato_p さんです。
最初のコード送ると以下の StackOverFlow の URL がおくられてきました。ありがとうございます。
stackoverflow.com
ふんふんとわからない英語を読むと、どうやら Clojure から Java の可変長引数の関数を呼ぶにはどうすればいいかという内容でした。
Clojure から Java の可変長引数を呼ぶ際には可変長引数の部分を vector で囲んでやらんといけんとのことでした。
FileChooser$ExtensionFilter のコンストラクタを確認してみると可変長引数になっていました。
そこで以下のように直すと
(let [fileChooser (FileChooser.)] (-> fileChooser .getExtensionFilters (.add (FileChooser$ExtensionFilter. "Audio Files" ["*.wav" "*.mp3" "*.aac"]))))
エラーなく実行できました。[] で囲っただけです。とっても単純。
こういった言語のルールをしらないと今日のように半日うんうん悩むことになってしまうので、しっかりと勉強しておきます。
これからもこういった記事を書いていきますので、よければ見ていただければと思います。よろしくお願いします。