ジェネリクスの型宣言付きの型の可変長引数って何がダメなんだっけ?
ジェネリクスの宣言付きの可変長引数を受け取るメソッドを定義したときにlintに怒られて「あれ?これってダメなんだっけ?」ってなったのでメモ。
やりたいこととしては、ORMを作っていてupdate文を作るときにvoid update(UpdateValuePair<E, ?>... pairs)
というメソッドを作りたい。
呼び出し側はUsers.all().update(Users.NAME.set("hoge"), Users.ACTIVE.set(true))
のように書けるのが理想。
呼び出し側はこういうのやりたいお気持ち pic.twitter.com/AjncV2VT1Z
— 俺九番 (@orekyuu) 2018年5月19日
危険な操作をしてみる
これを書いた時「Possible heap pollution from parameterized vararg type」という警告が出てくる。どのように危険な操作ができるのかサンプルを書きました。
public class Main { public static void main(String[] args) { hoge(Arrays.asList("aaa"), Arrays.asList("bbb")); } public static void hoge(List<String>... args) { Object[] objArray = args; // List<Integer>を入れる objArray[0] = Arrays.asList(1); // List<String>として取り出せてしまう List<String> stringList = args[0]; // 実はIntegerが入っているのでClassCastExceptionが出る String str = stringList.get(0); } }
Object[]を経由してargsの最初の要素にList
対策
取れる対策は2つで
- 可変長引数を使わず専用の型を用意する
- SafeVarargsを使って警告を抑制する
理想としては可変長引数をやめるのが一番安全。ただ、今回はUpdate文を作るときに可変長引数で更新する値を受け取りたいので、更新するたびに新しいインスタンスを作って組み立てて…とすると使いづらいのでSafeVarargsを使うことにした。
SafeVarargsで警告を抑制する
方針としては呼び出し側は問題なくて実装側が気をつければ良さそう(気を付けるだけはもにょるけど…)なので警告を抑制する。
警告を抑制するにはfinal or staticメソッドにして@SafeVarargsアノテーションをつければ良い。
最終的にはMocoのコードは以下のようになりました。
@SafeVarargs public final void update(UpdateValuePair<E, ?>... pairs) { createUpdate(pairs).executeQuery(ConnectionManager.getConnection(), ConnectionManager.createSqlVisitor()); }
JetBrains IDEのLive Templateを使い倒す
はじめに
この記事はピクシブ株式会社 Advent Calendar 2017の15日目の記事です。
17新卒で、普段はpixiv PAYのサーバーサイドの開発でRailsを書いています。
入社まではJavaをメインに書いていました。昔からIntelliJ IDEAが好きなので、JetBrains IDEのLive Template機能について書きます。
Live Templateとは
よくあるコードのテンプレート機能です。 この機能の面白いところはテンプレート内に変数を置いて、入力を促したり式を埋め込むことができるというところです。
うまく使えば効率的にコードを書くことができるのではないでしょうか!?
新しいテンプレートを追加する
Preferences > Editor > Live Templates
から設定できます。 右上の+ボタンからLive Templateを選択すると新しいテンプレートを作成できます。
設定項目 | 説明 |
---|---|
Abbreviation | テンプレートを展開するための文字列 |
Description | 補完候補ポップアップに表示される説明文 |
Template Text | テンプレート |
Applicate in ... | Live Templateを使える場所 |
Edit variables | テンプレート内の変数を編集するウィンドウを開く |
1. 単純なテンプレートを展開する
まずは固定の文字列を展開するテンプレートを作ってみます。
Abbreviation: hello
Description: Hello Worldを出力
Applicate in ...: Java > Statement
Template Text:
System.out.println("Hello World!");
2. 変数を使ってn回任意の文字列を標準出力
次はn回の部分と出力文字列を変数にしてみます。テンプレート内で $VARIABLE_NAME$
と言った形式で変数を定義できます。また、同じ変数名を使えば同時に同じ文字列が入力されます。
$END$
は特殊な変数で、すべての変数の入力が終わったあとにキャレットが$END$の位置に移動します。次に入力したくなるであろう場所に$END$
を書いておくとキャレットの移動が減って便利です。
Abbreviation: each_sout
Description: n回任意の文字列を出力
Applicate in ...: Java > Statement
Template Text:
for (int $VARIABLE_NAME$ = 0; $VARIABLE_NAME$ < $LOOP_COUNT$; $VARIABLE_NAME$++) { System.out.println("$TEXT$"); $END$ }
3. 関数を使って補完をサジェストを出す
Edit variablesからダイアログを開くとテンプレート内の変数に対しての設定をするためのダイアログが開きます。ここでIntelliJが用意してくれている関数を使って決められた候補内からサジェストを出したり、変数名を提案させることができます。
どのような関数があるかは公式ドキュメントに説明があるのでそちらを確認してください。
Springで使われるAutowiredを使ったフィールドを作るテンプレートを作ってみます。
Abbreviation: autowired
Description:
Applicate in ...: Java > Decration
Template Text:
@Autowired private $TYPE$ $VARIABLE$;
Edit variables:
Name | Expression | Default value | Skip if denfied |
---|---|---|---|
$TYPE$ | className() | false | |
$VARIABLE$ | suggestVariableName() | false |
4. enum関数を使ってサジェストする
Javaのような静的型付けの言語ではIntelliJのサポートが手厚くサジェスト系の関数が豊富ですが、RubyMineではサジェストはあまり効きませんし、サジェスト系の関数もほぼありません。しかし、FactoryBotで作ったfactoryやtraitの名前を覚えるのは大変です。
そこでtraitのバリエーションをLive Templateに書いておいて良い感じに補完してくれるようにしました。決められた候補から選択させる場合、enum関数を使うと便利です。JetBrainsのIDEは中間マッチングをしてくれるので「たぶんhogeという文字列含んでたよな・・・」のような状態でもサジェストを出してくれるので、人間が考えることを減らしてくれます。
Abbreviation: create_user
Description: ユーザーを作成
Applicate in ...: Ruby
Template Text:
FactoryBot.create(:user, $trait$)
Edit variables:
Name | Expression | Default value | Skip if denfied |
---|---|---|---|
$trait$ | enum(":admin", ":anonymous") | false |
5. groovyスクリプトを使う
より高度な補完を行いたくなったときにgroovyScript関数を使うことでgroovyのコードを実行することができます。
第一引数にgroovyスクリプトもしくはスクリプトファイルのパスを指定し、スクリプトに渡したい値があれば第二引数以降に渡します。第二引数以降は$1、$2のような変数に順に割り当てられます。また_editorという変数にcom.intellij.openapi.editor.Editor
のインスタンスが入っているので、ここから編集中のファイルの情報やプロジェクトの情報が取得できます。
サンプルとして標準関数ではとれない現在編集中のファイルのプロジェクト内でのパスを展開するテンプレートを作ってみました。雑スクリプトなのですが、きちんと書けばrequest specのコメントをうまく補完することができそうです。
Abbreviation: relative_file_path
Description: ファイルのパスを展開
Applicate in ...: Ruby
Template Text:
"$relative_file_path$"
Edit variables:
Name | Expression | Default value | Skip if denfied |
---|---|---|---|
$relative_file_path $ | groovyScript("長いので下に書きました") | true |
com.intellij.psi.PsiDocumentManager.getInstance(_editor.getProject())
.getPsiFile(_editor.getDocument())
.getVirtualFile()
.getCanonicalFile()
.getPath()
.minus(_editor.getProject().getBasePath())
育てたLive Templateを別PCと共有する
実際にコーディングで育てたテンプレートは自宅PCと職場PCの両方で使いたくなります。JetBrainsが出しているプラグインのIDE Settings Syncを使うことで同じアカウントに紐付けされた複数のIDEで設定を共有できます。
おわりに
Live Templateは書いて終わりではなく、使いながら不満を感じたら手を加えていくといった運用をすると使い勝手の良いものになっていくかと思います。
明日は@tadsanさんがPHPとEmacsの話をしてくれます。2日連続のエディタ記事ですね!お楽しみに!
ピクシブ株式会社ではではエディタにこだわりのあるエンジニアを募集しています!
痛IntelliJプラグインを作った話
この記事はJetBrains Advent Calendar 2017 11日目の記事です。
前日はKotlinでプラグインを作る話でまさかの2日連続プラグインの話…!
僕は萌え系のイラストが好きなオタクエンジニアなんですが、オタクエンジニアをやっているとエディタやIDEを痛くしたくなることってありますよね…!?
EclipseにはMoeclipseという選択肢があったりします。JetBrains IDEの場合数年前までSexy Editorというプラグインでエディタの背景を変える必要がありました。
その後、本体にSet Background Image
というアクションが追加され、そこからプラグインを入れることなく背景を変更することができるようになりました。(Shift+Cmd+Aのアクション検索からしか設定に飛べないです
@いなむ先生 これで許してください pic.twitter.com/gluvtXllol
— 俺九番 (@orekyuu) 2017年4月30日
背景を痛くすることは簡単にできる時代になりましたが、痛IDEを名乗るにはまだ早いですよね。もっと痛くしましょう。
痛IDEプラグインを作ってみた
これがプロのエディタ pic.twitter.com/AsCK2PgLKv
— 俺九番 (@orekyuu) 2017年8月7日
このプラグインはエディタの背景にキャラクターを表示して操作によっていろいろなリアクションをしてくれます。
ということでJetBrainsPluginRepositoryに公開しようと思ったんですが審査でリジェクト…。頑張って絵も描いたのにどうやら公開はできなさそう…。しかし、せっかく作ったので使ってもらいたい!うちの娘を可愛がってもらいたい!
プラグインリポジトリを作る
Plugin Repositoryを各自で用意することができるようになっているので自分で用意することにしました。
ドキュメントに設定が書かれていたりするので簡単にサッっと立てることができました。
おわりに
これで最高の痛IDE環境になりました。痛IDEを作るならもうJetBrains IDEしか選択肢はないのではないでしょうか…!?
実装に関しての話は別記事に書いているので興味のある方はそちらも読んで頂けると!
いますぐダウンロード
女の子がリアクションしてくれるいんてりじぇープラグイン作りました
— 俺九番 (@orekyuu) 2017年8月7日
Plugin一覧からBrowse repositories>Manage repositoriesで出てきたダイアログにhttps://t.co/7nRml7CV9z
を追加してから"riho"で検索してください pic.twitter.com/UgvQSUwbkU