OK, now let’s actually work with project. There are 2 recommended ways for 1st commit of Kotlin.
Adding documentation or comment is one of best ways to start contribute any OSS including Kotlin. My first commit is also fixing URL of README
JetBrains says that they want the documentation for standard library. Find a class or a function which are not documented well from https://kotlinlang.org/api/latest/jvm/stdlib/index.html You may think there are not much function that is not documented. Trust me, you can find at least 10 undocumented functions within 1 min!
If you are not good English writer like me, then providing samples are the better way to start contributing Kotlin. https://youtrack.jetbrains.com/issue/KT-20357 is the issue for samples. This issue is especially for new Kontributors.
There are 4 steps to provide sample codes
Comment the target API to the issue
Then, write sample code.
1 2 3 |
|
The method name can be anything but don’t add test
as prefix/postfix because it is not test. Then add sample code inside the method.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
There are no hard restriction for writing samples. You can add comment if it is helpful for other developers.
After that, in order to connect with sample code and target method, comment to the target method with @FQN of the sample method
1 2 3 4 5 |
|
Now, you are ready. Send Pull Request. Then, update you comment with pull request URL
That’s it! Easy! Now, if you want to provide the sample code, please read README for sample code, too. https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/samples/ReadMe.md
After the pull request get merged, in some point, you can see your sample code in official documentation http://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/group-by.html
]]>Communication is one of the key success factor for Kontribution.
I will introduce 3 tools that Kontributors usually use.
Slack is one of most important communication tool for Kontributors. In case you are not join Kotlinlang
team, get the invitation from http://slack.kotlinlang.org
There is public channel kontributors
. This is the one that most of contributors and JetBrains stuff are staying.
If you have trouble building Kotlin project or anything that is related to Kontribution, ask those questions at this channel.
Normally, people respond within one business day.
The second one is YouTrack. YouTrack is the issue management tool that JetBrains developed.
Kotlin’s public issues are listed https://youtrack.jetbrains.com/issues/KT
You can work any issues if there is no assignees or no progress.
In case you are not sure which issue you want to work with, check for up-for-grabs
tag or https://youtrack.jetbrains.com/issues/KT?q=tag:%20%7BUp%20For%20Grabs%7D%20%23Unresolved These issues are free to contribute.
After you find the issue you want to work with, the first thing you should do is comment “I’m going to do this”. Since we are external contributors, JetBrains staff are not able to assign our name as assignee. However, once you comment the issue, you are treated as assignee.
The last one is GitHub. GitHub is where JetBrains staff give us a feedback of your pull request. GitHub are not used for a lot of communication, except KEEP.
After sending pull request, I recommend to write pull request URL to YouTrack’s issue. This is because JetBrains staff don’t look at GitHub. They constantly check YouTrack but not GitHub. If you comment URL to the issue, the issue goes to top of the list. So, they can easily notice there is some progress for the issue.
]]>I’ve been kontributors since July 2016. I made more than 60 commits by now. I love Kotlin, my beautiful wife and lovely son.
I talked about this topic a few times in different places. After speaking at DroidKaigi 2018 and Kotlin Night Kolkata, some people gave me feed back that it is also helpful for new Kontributors if I make a blog post in English. I am too lazy to write this from scratch, so I re-used some of contents from those presentation.
This blog entry does not explain how to use git/github and how to write Kotlin.
Since I mainly contribute to Kotlin plguin features, this blog post focus on how to contribute kotlin plugin. However, once you undersntand how to do it, it is really easy to contribute to Kotlin Languages, Kotlin JS or Kotlin Native because it is in the same repository.
It “was” the hardest part but not anymore. This is the reason I updated this topic as v3. There are “only” 4 parts of setups
The first one is JDK.
You need to install 3 differenct versions of JDKs.
In order to use those JDK, you must setup environment variables like this
It’s quite annoying to set each environment variables. Here is what I did.
1 2 3 4 |
|
As for Intellij IDEA, you can use both community and ultimate version.
To make sure you are using latest kotlin plugin, check the following gif.
After setup Intellij IDEA, you can open kotlin plugin. First time you open the project, Intellij downloads all dependencies using gradle. It took me about 50 mins. Just wait.
After downloading dependencies, you will notice that there is no source code in Project view. To fix this problem, you will need to do the followings:
build.gradle.kts
fileImport Module from Gradle
dialog popup. Select use default gradle wrapper
The following gif visually describes the steps
Setup is done. Let’s run it. To run it, select IDEA
run configuration and hit run button.
After waiting a few minites, the child IDEA shows up. What does this do is if you change your Kotlin project, the change is bundle to this child IDEA. You can test your new feature in this child IDEA.
If you cannot build or run the project, ask other kontributors! In next blog post, I will talk about how to intract with other Kontributors or JetBrains team.
]]>なおこのエントリーはKotlinPoet v0.6.0を利用しています。
KotlinPoetはKotlinのコードを生成することを手助けするライブラリです。JavaPoetのKotlin版というイメージです。
以下のコードが
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
このコードを出力します。
1 2 3 4 5 6 7 8 9 |
|
KotlinPoetの紹介はKotlinConfの動画を観ると良いです。
実は上記のコード一点、非常に面白い点があります。
1
|
|
primary constructorの生成です。KotlinPoetの以下の部分で生成しています。
1 2 3 4 5 6 7 8 |
|
valのname
をprimary constructorに入れるだけなのですが、KotlinPoetでは3回もname
と記述しています。
せっかくなので、一つずつ見ていきましょう。まずPropertyを生成する場合、以下のコードになります。
1 2 3 4 |
|
以下のコードが生成されます。
1 2 3 |
|
次にprimary constructorにname
入れたい為、primary constructorの設定を記述します。
1 2 3 4 5 6 7 |
|
そうするとこんなコードが生成されます。
1 2 3 |
|
最後にprimary constructorとpropertyを連結するため、初期化方法を記述します。
1 2 3 4 5 6 7 8 |
|
これでようやく以下のコードが生成されるようになります。
1
|
|
これは、記述されたコードは全て生成する。最適化はKotlinPoetがする。というKotlinPoetの考えからきているそうです。
KotlinConfの動画でも解説されていますので確認して見てください。 https://youtu.be/_obNBSldffw?t=20m40s
若干文法が違ったり、上記のような隠れた癖がある為、JavaPoetに慣れている方は最初戸惑うことがあるかもしれませんので、生成後のコードをしっかり確認した方が良いです。
ちなみにPermissionsDispatcherはKotlinPoetのこの挙動を知らず、誤って外に出てしまったpropertyをコンストラクタに詰める為の修正をv3.0.1で入れています:joy:
その時の開発者のつぶやきです。
parameterとproperty作成して、property側のinitializerに変数名を入れるというまじかよ!って方法で達成した。なぜできるのか?という疑問は後で調査しよう。
— shiraji (@shiraj_i) 2017年9月17日
ファイル、クラス、クラスメンバー、プライマリコンストラクター、トップレベルの関数に関しては上記サンプルコードをみてください。
それ以外のよく使いそうなコードの生成方法をメモしておきます。
kotlinpoetのコード
1
|
|
生成されるコード
1 2 |
|
FileSpec.Builder
のaddComment
を利用している為、ファイル上部にコメントしていますが、Builderの種類(TypeSpec.Builderなど)によりコメント位置が調整されます。
1 2 |
|
1 2 |
|
フォーマットはJavaPoetと違い%
を利用します。その他のフォーマットはこちらを参照してください。
これ以降のコードはあまりフォーマットを利用していませんが、本来はこのフォーマットを使う方が良いです。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 |
|
1 2 3 4 |
|
1 2 3 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1
|
|
1 2 |
|
アンインデントされるまでインデントされ続けます。
1
|
|
1 2 |
|
その他知りたければ、KotlinPoetのAPIドキュメントを確認して下さい。(v0.x系以降のドキュメントはURLが変更されるかも?)
PermissionsDispatcherのこの辺りを眺めるとKotlinPoetの実装の参考になると思います。
]]>PermissionsDispatcher v3が今年の9月にリリースされました🎉
Finally PermissionsDispatcher 3.0.0 is out😄 We added fully @kotlin support and a few improvements🎉Enjoy✌️ https://t.co/3a1SQ17AWb
— hotchemi (@hotchemi) 2017年9月16日
結構大きな修正であったので、これに関して書きます。
PermissionsDispatcherのコミッターの一人です。今年はそれほどコードでの貢献が出来なかったので、この記事を書くことで何か貢献したいと思います。
まずv2を使っている人はv3への移行をする必要があります。移行手順は以下にあります。
簡単に解説すると以下の二点の修正が必要になります。
XxxPermissionsDispatcher
クラスが無くなり、Activity
/Fragment
の拡張関数として提供されるようになったXxxWithCheck
メソッドがXxxWithPermissionCheck
メソッドに変更になった実際に生成されるKotlinのソースを見てみましょう。sample-kotlinモジュールでは以下のコードが生成されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
|
REQUEST_*
やPERMISSION_*
はv2ではMainActivityPermissionsDispatcher
クラス内で定義されていましたが、privateのトップレベルでの定義に変わりました。
また、showCameraWithPermissionCheck
やonRequestPermissionsResult
はMainActivity
の拡張関数になっています。その為、MainActivityPermissionsDispatcher
クラスがなくなりました。(Javaの方では存在しています。)
KotlinPoetの出現から、これを使ってKotlinコードの生成してみよう->どうせならKotlinっぽく拡張関数にしてみよう!という流れで拡張関数を使うことになりました。
詳細は以下のIssueを確認してみて下さい。
https://github.com/permissions-dispatcher/PermissionsDispatcher/issues/320
以下のIssueで問題提起されました。
https://github.com/permissions-dispatcher/PermissionsDispatcher/issues/355
このIssueでは漠然とした質問でしたが、Kotlinユーザに対して、拡張関数として提供する場合、WithCheck
では意味がわからないのではないか?という話から一気にv3.0に導入する流れになりました。
PermissionsDispatcherはカスタムlintを提供していますが、Kotlin実装向けのlintの対応がまだ終わっていません。(実際の問題はUASTのKotlin対応)
この件に関するIssueは以下
https://github.com/permissions-dispatcher/PermissionsDispatcher/issues/373
permissions-dispatcher-pluginと言うIntellijプラグインですが、メイン開発者の @shiraji がサボっている為、v3対応がされていません。またもうv2の対応しなくて良くね?と言っており、誰からも反論がない為、急にv3のみのサポートになる予定です。
そんなにいないと思いますが・・・このプラグインを使っていて、v2のみしか使っていない人はこれを機にv3へのアップグレードをよろしくお願いいたします。多分今年度中にはプラグインの方も対応します。
@hotchemiさんからの提案で、permissions-dispatcher orgが出来ました。おかげ様で、ますますメンテナとして頑張りたい!と思えるように。以下がそのIssue
https://github.com/permissions-dispatcher/PermissionsDispatcher/issues/353
数日前にあったPermissionsDispatcherのプロダクトマネジメントにも同じようなことが記述されていました。
7月に書いたTesting Against Annotation Processingに詳細書いてあるので、読んでください!!!
PermissionsDispatcherのこの辺りを眺めるとKotlinPoetの実装の参考になると思います。Kotlin Advent Calendar の16日目にKotlinPoetに関する投稿がされるので、そちらも参照して下さい。
PermissionsDispatcherは非常に良いライブラリで、新しい仕組みも積極的に取り入れています。一緒に開発しませんか?
また、最近、ビルド出来ない。使い方がわからない。などなどREADME読んでません的なissueに上がってきます。これの対応に時間を割いてしまい、開発が滞りガチです。もし、PermissionsDispatcherに対して何か貢献したい!と言う方は、 このようなissueの対応や調査などなどお手伝いして頂けると非常に助かります。
]]>Add integration test cases for checking the behavior of generated code https://github.com/hotchemi/PermissionsDispatcher/pull/339
このPRについて語ってみます。
Annotation Processingのテストで検索するとだいたいcompile-testingを使えと書かれています。
compile-testingとは
A library for testing javac compilation with or without annotation processors
です。annotation processingのライブラリでよく使われる手法として、コードを読み込ませ、compile-testingを利用し想定通りのコードを出力しているかを確認しています。
こんな感じで書いています。
このテストを実行し、JUnitが全てパスした場合、思った通りのコードが生成され、コンパイルも問題なしです。私はこれだけで安心していました。
compile-testingが通りました!OKです!・・・でも本当にそうなんでしょうか?
テストしたのはcompilerが思った通りのコードを生成したことを確認しただけです。
本当に必要なテストは、生成したコードが実際に思った通り動くかどうかの挙動の確認であるはずです。
ライブラリ利用者からすれば、極論、生成されるコードなんてどんな形でも良いのです。挙動さえ正しければ良いはずです。(メソッド数や容量とか気になるけど。) が、その挙動の確認はcompile-testingでは行っていません。
実際に生成したコードに対してテストを書けば良いはずです。
冒頭のPermissionsDispatcherのPRでやったこととして
PermissionsDispatcherはDelegate to generated classにある通り、2つのpublicメソッドを生成します。そこで、この2つのメソッドに対し、PowerMockito、Robolectricなどフル活用してテストを書きました。
このテストのメリットとして、今後PermissionsDispatcherはKotlinはKotlinらしいコードを生成しようぜ!という話が上がっており、Kotlinらしいコードを生成したとしても、このテストが通りさえすれば、あくまで理論上ですが、どんなコードを生成しても問題ないと言えるはずです。
捨てちゃダメです。冒頭のPRでは生成コードが必須になるため、正常系のテストしか行うことが出来ません。コンパイルエラーが発生した場合のエラーハンドリングが適切に行われているか?の確認としては非常に有効に活用できます。
compile-testingが何をテストしているのかをしっかり把握し、適材適所でのライブラリの選定が一番だと思います。
]]>Here is the visuals that illustrate the differences between these methods.
substringAfter
tries to find the character(s) from “beginning”, and substrings “after” the characters
substringAfterLast
tries to find the character(s) from “last”, and substrings “after” the characters
substringBefore
tries to find the character(s) from “beginning”, and substrings “before” the characters
substringBeforeLast
tries to find the character(s) from “last”, and substrings “before” the characters
The following list is the summary of these methods.
Intellij IDEAだけではないのですが、Alt+Enter(Intention)は自分で拡張したものを作ることが可能です。
自分のページにリストされているIntellijプラグインページがページングされたらプラグイン開発辞めようと誓っていて、最近中の人と話したらページング機能ないけど?wと生涯現役プラグイン開発者としてやっていくことが決定した人間です。
Intentionだけではなく、Inspectionなども作成しており、Kotlinのコントリビュートもしています。Kotlinの主なコントリビュートもInspection/Intentionなので、ある程度説明出来るレベルだと思います。
今回サンプルとして、Intention周りのプラグインをリリースしました。 https://plugins.jetbrains.com/plugin/9271
ソースコード https://github.com/shiraji/databinding-support
これをベースにXMLファイルに対してのIntentionの説明をします。
今回はレイアウトファイルであり、<layout>
タグがrootタグではなかった場合、<layout>
タグでラップするというIntentionを作成します。
プラグインの作成方法などは参考リンクにまとめてありますので、そちらを参照して下さい。
IntentionAction
を継承します。以下のメソッドを実装する必要があります。
getText(): String
popupで表示される時の文字列
getFamilyName(): String
よくわからねw(intellij-community/kotlin repo内でもgetText呼び出してるだけのところが多い。)
startInWriteAction(): Boolean
Write Action内で実行するかどうか。
isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean
そのIntentionを利用可能かどうか判定する
invoke(project: Project, editor: Editor?, file: PsiFile?)
Intentionが選択時に実行されるメソッド。
今回は実際に以下のようなイメージになりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
このrootタグかどうかとか、androidのレイアウトファイルかどうかの判定とか、何をどう書き換えるのかとかがたぶん一番難しい部分だと思います。ただ、ここはそれぞれのIntentionやプラグインで違うのでコード読んで頑張れwとしか言えません。。。
唯一ある共通点としてはファイルなどの読み込みや解析はPsiを使います。例えば、xmlタグだったらXmlTag、XmlAttributeを使います。PsiElement#replace()
でソースコードの置換することが出来ます。
それぞれのElement作成それぞれのファイルタイプ毎にFactoryが用意されています。XmlならXmlElementFactory
で作成しています。Javaの場合だとPsiElementFactory
だし、KotlinならKtPsiFactory
を使います。
Intentionクラスをplugin.xmlに定義します。
1 2 3 4 |
|
自分はちょくちょく忘れるのですが・・・(実際これを忘れて、1.0.1->1.0.2のバージョン更新をした。)
こんな感じで設定画面に説明文を書くことが可能です。
以下の3つのファイルを作成します。
それぞれが表示されるのはここです。
例えば、JavaファイルののIntentionだった場合、after.java.template
のようにファイル名をafter.{拡張子}.template
とすれば良いです。before
のほうも同じです。
配置箇所はresourcesフォルダ/intentionDescriptions/INTENSION名/
に配置します。
ConvertToDatabindingLayoutIntention
の場合、こんな感じ。
Happy alt+enter
life!
IntelliJ IDEAクイックスタート – インテンション
http://samuraism.com/products/jetbrains/intellij-idea/quickstart/intentions
プラグインプロジェクトの作成手順
http://www.jetbrains.org/intellij/sdk/docs/index.html
gradleを使う場合
http://www.jetbrains.org/intellij/sdk/docs/tutorials/build_system.html?search=gradle
このgradleプラグインのセットアップウィザードはないので、gradle-intellij-plugin wizardを使うと便利だよ(ステマ)
]]>kotlinでやるとAndroid簡単に書ける手法まとめとかないかな。extentionでbindingadapter書くとか、custom viewのコンストラクタをJvmOverloadsで省略とか。
— しらじ (@shiraj_i) 2016年8月23日
8月23日にこんなつぶやきをして、今日まで溜めたAndroid開発をしていて、こう書くと簡単でキモチイイ!!!というKotlinの文法を紹介したいと思います。
(あくまで自分が気持ちいいってだけだからね!)
Kotlin 1.0.4, Kotlin 1.0.5で名前が載ったExternal Contributorsの一人です(嬉しいから自慢)。主にKotlin Pluginの静的解析にコントリビュートしています。Kotlinで書かれているPermissionsDispatcherの開発にも参加しています。
Android開発経験3年ほどで、今はAndroidをJavaでもKotlinでも開発しています。
少しくらいならブログでAndroid/Kotlinネタ書いてもいいレベルかな?と思います。
Kotlinの文法はJavaコードと比較すればだいたいわかる感じで記載していきますが、もしわからなければ、@shiraj_iにメンションいただければ答えますので、お気軽に質問して下さい。
Kotlinは書きやすいとよく耳にしますが、実際どういうところでどういう文法にすると「書きやすい」になるのかJavaとの比較があまりありません。そこで独断と偏見で気持ちいい文法だこれ!と思った文法や書き方を紹介したいと思います。
Kotlinで一番有名であろう機能、Null安全やセミコロンレスに関しては多くのドキュメントやブログがありますので割愛します。
ある特定のテキストを返すだけのメソッドを作る時、Javaで書くとこんな感じになります。
1 2 3 |
|
Kotlinでも同じように書けます。
1 2 3 |
|
ただ、Kotlinは一行でreturn出来る場合、=
をつけて{}
を省略することが出来ます。
1
|
|
さらに、戻り値の型が明らかな場合、型の指定しなくても良いので
1
|
|
短くてだいぶ気持ちいいですね。
こんな感じで、以下もJavaの例文を出して、Kotlinで気持ち良くなっていきます。それではどんどんいきます。
例えば、パラメータがnullだった場合、即メソッドを抜けるという処理を書くとします。Javaの場合、結構色々書かなきゃいけません。
1 2 3 4 5 6 |
|
Kotlinはnull時にこれをしてくれという?:
文法が用意されています。それを使うと一行で書けちゃいます。
1 2 3 4 |
|
null時に別値を代入ということも可能です。
1 2 3 4 |
|
Javaでは空クラスだろうと、{}
を書かなくてはなりません。特に目印用のinterfaceとかであると思いますが
1
|
|
Kotlinではボディが空のクラスの場合、{}
を書かなくて良いので
1
|
|
もちろん、classでも可能です。
1
|
|
空メソッド。Javaの場合、{}
を書かなくてはなりません。
1 2 |
|
Kotlinの場合、一行メソッドと同じように書けます。
1
|
|
あれ?ながk…気持ちいいですね!
Kotlinでは、getter/setterがあった場合、propertyとしてアクセス可能になります。AOSPに書いてあるgetter/setterも同様です。
Activity#getLayoutInflater()
を使うようなメソッドを定義する場合
1 2 3 |
|
Kotlinで書くと以下のように書けます。
1
|
|
実際にはActivity内にlayoutInflater
というプロパティは存在していませんが、Kotlinが解釈してくれます。
もちろんですが、以下のようにも書けます。
1
|
|
ただ、Android Studioさんが「これプロパティアクセスに変えな?」というサジェストが出ます。
Javaっぽいコードを書くとこのようにワーニングを出してくれるので、都度修正していくとKotlinらしい文法の勉強も捗ります。(platform typeにはご注意下さい)
ここのパラメータだいたい同じ値なのだけど、時々違うから、overloadメソッドを用意するか!ってことありませんか?
1 2 3 4 5 6 7 |
|
かの有名なu2020にもありました。
Kotlinはパラメータのデフォルト値を定義出来ます。
1 2 3 |
|
パラメータのデフォルト値に関連して、カスタムViewのコンストラクタの定義って大変だと思います。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Kotlinはデフォルト値を定義したメソッドを上記のようにJavaから見たら複数あるようにする@JvmOverloads
というアノテーションがあります。
これを使うと、カスタムViewのコンストラクタは一行定義するだけで書けます。
1 2 |
|
(Kotlinのコンストラクタ自体は気持ちよくないので説明省略します。)
Javaでキャストする場合、括弧が多くなりがちです。PagerAdapterのdestroyItem
を実装してみます。
1 2 3 |
|
Kotlinだとas
を使ってキャストします。文法的にも括弧が減り、どこで括弧が終わっているのかがわかりやすくなります。
1 2 3 |
|
null時に何する?との組み合わせることでキャスト失敗時に何するかの定義も簡単にできます。
1 2 3 4 |
|
また、readonlyの変数のキャストに成功すると自動的にその変数をキャストしてくれます。メソッドパラメータはreadonly。各所に出てくるval
と定義されている変数もreadonlyです。(余談ですが、immutableではありませんので注意して下さい。)
1 2 3 4 5 |
|
mutable変数var
の場合、as?
後に変更可能なので、自動的にキャストしてもらえないので注意。Kotlinでは理由がない限り、var
を使わないほうが良いです。
XxxUtilsとか作って、全メソッドをstaticにして、privateコンストラクタを作って・・・みたいなやり方をJavaではちょくちょくしていました。
1 2 3 4 5 6 7 |
|
kotlinではTopレベルにメソッドを書けば、このようなUtil系のメソッドを書くことが出来ます。
1
|
|
使い方もJavaのときと変わりません。
1 2 3 4 5 |
|
JavaでStringの結合をする場合、こんな感じになります。
1 2 3 |
|
KotlinにはStringテンプレートとしてString内に${}
で変数を書くことが出来ます。
1 2 3 |
|
変数一つだけである場合、{}
の省略も出来ます。
1 2 |
|
JavaのStringで複数行を生成する場合、結構辛いです。
1
|
|
Kotlinでは"""
を使うことで複数行のStringの定義を出来ます。
1 2 3 |
|
.trimMargin()のこととか、マージンの開始位置とか複数行のStringは結構多機能ですが、詳細知りたければ公式のstring-literalsを確認してね。
Javaではifが複数ある場合、ちょっとつらいです。
例えば以下のようなコードがあったとします。(Javaでbehaviorを独自実装したときに使っていたコード)
1 2 3 4 5 6 |
|
これをKotlinでもそのままif/else書けます。
1 2 3 4 5 6 |
|
しかし、もう少し簡単にwhenでまとめることも可能です。
1 2 3 4 5 |
|
whenはJavaでいうSwitch文に近いですが、上記のようにwhenの後に条件を付けなかったり、変数の型のcase文に出来たりとめちゃくちゃ気持ちよくなれます。
Kotlinではifやwhenなど諸々が式です。
例えば、ifの結果を変数に代入する場合、
1 2 3 4 5 6 |
|
kotlinではこんな感じになります。
1 2 3 4 5 |
|
単純な場合、{}
は省略するので一行で書くことが多いです。
1
|
|
条件により違った値を代入しているのですがval
で定義出来るのがポイントです。
ちなみに、PermissionsDispatcherさんでも利用していて、メソッドの引数として使ったりもしています。
1
|
|
ネストさせることも出来るのですが、複雑になるので見にくい場合はローカル変数に切り出すのが良いと思います。
Dagger2を使う場合、ActivityやFragmentスコープを作るために独自Annotation作ったりします。
1 2 3 4 |
|
@interface
というキーワードを使っていましたが、Kotlinではannotation
と表現します。直感的で良いです。
1 2 3 |
|
Retention
のデフォルト値がRetentionPolicy.RUNTIME
なので、指定を省略出来るのもスッキリしていて気持ち良いです。
Javaでは(簡易的な)シングルトンを作成する場合、以下のように書く必要がありました。
1 2 3 4 5 6 7 8 9 10 |
|
Kotlinでは、object
として定義すればアプリ内でシングルトンとして利用可能です。
1 2 3 4 5 |
|
使い方もJavaの時と同じです。
1
|
|
ちょこっとしたことなのですが、Rxの実行スレッド方法の指定も気持ちよく書けるようになります。
1 2 3 4 |
|
Kotlinの拡張プロパティを利用し、スレッドの指定方法を定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
この拡張プロパティを利用すると以下のように書けます。
1 2 3 4 |
|
DatabindingのBindingAdapterの公式ドキュメントのコードをKotlinで書いてみます。
1 2 3 4 |
|
これがこんな感じになります。view
が消えました。
1 2 3 4 |
|
これも拡張メソッドでいきます。
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 |
|
kotlinではこんな感じ。Toast表示用の拡張メソッドも定義しています。
1 2 3 |
|
ちょっと手が滑ると
1 2 3 4 5 6 7 |
|
topレベルの拡張メソッドは用法・用量を守って正しくお使い下さい。
自分はcreateIntent/newInstanceパターン大好きです。
これも気持ちよくなれます。
1 2 3 4 |
|
applyを使って、一行に。
1 2 3 |
|
newInstanceもやってみます。
1 2 3 4 5 6 7 |
|
パラメータセットしたインスタンスを作りたいだけなのですが、結構冗長的で辛い。。。
Kotlinで短くしてみます。
1 2 3 4 5 6 |
|
nestが激しいのでバラしていきます。まずはこの部分。
1 2 3 |
|
これをメソッド化すると
1 2 3 4 5 |
|
bundle変数に関する処理なので、Bundleの拡張メソッドと考えると良さ気。
1 2 3 4 5 |
|
return文一文なので、省略。thisも必要ないので、省略。
1
|
|
イマココ
1 2 3 4 5 6 |
|
SimpleDialogFragmentの部分も同じように拡張メソッドを使って書くと。
1 2 3 4 5 |
|
だいぶシンプルになりました。ヨイヨヨイヨ。
Databinding前には結構使うことが多かったのですが、今となっては・・・でも一応。
Viewを消してしまうか表示するかをBoolean値で判別するようなUtil系のメソッドを書くとすると
1 2 3 4 5 6 7 8 9 10 11 |
|
これをkotlinで書くと一行でいけます。
1 2 3 |
|
nullableのViewの拡張メソッド、null安全、setter/getterの省略、if式利用と色々Javaにはない機能を利用しています。
公式にある、以下のコードをKotlinで気持ちよく書いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Kotlinで書く前に、そもそも具体的にやることは以下
@Bindable
をつけるnotifyPropertyChanged(BR.firstName);
を呼ぶ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
setter/getterを書かなくて良いのでシンプルになってます。
もうちょいキレイになればいいですが、わざわざメソッド書かなくて良いというだけでも気持ちいいです。
継承するな!移譲しろ!と言われてもJava使ってると継承しちゃいガチなのですが、KotlinのDelegateがあるとこれを積極的に利用したいなと思えるようになります。
ViewModelにRxのSubscriptionの機能を実装し、Activity#onDestroy
時にunsubscribe()
したいという時
1 2 3 4 5 6 |
|
Kotlinでdelegateするとunsubscribe()
は書かなくて良くなります。
1 2 3 |
|
Activityではこんな感じ。MyViewModel
で実装していないのにunsubscribe()
を呼ぶことが出来る。
1 2 3 4 5 6 7 8 9 10 11 |
|
droidkaigi2016のArrayRecyclerAdapterを以下のようなにすることもできるけど、余計なメソッドも生えるので、用法と用量を(省略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Javaで簡単にやる場合、getterを作成し、propertyアクセスは禁止し、そのgetter経由で値を取得するというルールの下かろうじて出来る遅延初期化処理です。
例えば、DatabindingのsetContentView
を利用して、binding
変数を初期化します。
1 2 3 4 5 6 7 8 |
|
Kotlinではby lazy
を利用して書きます。一旦binding
変数にアクセスしたらby lazy
内の処理が実行され、初期化されます。
1 2 3 |
|
valであるのも良いです。
ちなみに、enumにordinal
ではない数値のidを振ることがあって、そのidから逆引きしたい時にキャッシュしたSparseArray
を利用して逆引きしますが、この時もby lazy
使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Javaではそもそも出来ないのですが、こんなPOJOクラスがあったとします。
1 2 3 4 5 6 7 8 9 10 11 |
|
1 2 |
|
第一引数と第二引数がfirstなのか、lastなのかわからなくなります。ランタイムでしか検知できないのが辛いです。
1
|
|
引数に名前を設定して、メソッドを呼び出せます。こんなことしても叱られませんし、間違った挙動を起こしません。同じような型が多いメソッド呼び出しでは積極的に使うと気持ち良いです。
1
|
|
リストアップしてみたら結構出てきました。。。
落選した項目はgistで公開しています。
]]>これはiOS Advent Calendar 2016の12/3の記事です。
Swiftでprintlnを書いてハマるレベルのエンジニアが一週間(実稼働時間 約8時間)でR.swiftにコントリビュートしたお話。(だったけど、メンテナさんが別プロジェクト始めちゃってまだマージされていない。-> この記事の翌日2016/12/04にマージされましたー!)
Swift開発している人にとっては常識な話が多数だと思いますが、Android開発やKotlin触っていて、Swiftもやってみたい!とかSwiftのライブラリ開発してみたい!という人向けです。R.swiftのコントリビュート方法として紹介していますが、他のライブラリも同じ感じなのではないかなーと思ってます。
申し訳ないですが、iOS/Swift開発経験が長い人は想定外です。
Kotlinが好きなAndroidエンジニアです。
iOS開発は素人に毛が生えた程度のレベルの人間ということです。
プルリク駆動開発のルールは以下です。
これに則って、勉強できそうな星多いライブラリを探してみました。
名前 | ライブラリ概要 | 検討した理由 | 検討結果 |
---|---|---|---|
Himotoki | タイプセーフなJSONデコードライブラリ | メンテナーが日本人のikesyoさんという安心感から。 (恐れ多くて関わったことがないのですが・・・) |
issueなし!(スゲェ・・・ |
Kingfisher | Imageのダウンロード・キャッシングライブラリ | なんか名前がかっこよかった | 開発活発○ ラベリングがない☓ |
Alamofire | Swift版HTTPネットワーク | Swiftやるならこれでしょという短絡的な発想 | 開発活発○ ラベリングあり○ メインテナー多そう○ HTTP周りの知識必須っぽい△ |
R.swift | コンパイルタイムでコード生成 Androidで言うRクラスを使えるようにするライブラリ |
自分がAndroid出身者だから | 開発活発○ ラベリングがしっかり○ メインテナーが複数いるっぽい○ 自分が持っている知識でいけるっぽい○ |
ということで今回はR.swiftを選択しました。
今回のコントリビュートで以下の項目を勉強しました。
なかなか濃い一週間でした。
ここをrswiftに変える。
Runではなく、BuildでOK
ここをResourceAppに変える。
ライブラリのコード内にprint()
を書けばrswift.log
というところにログが出力されるように設定されています。これを利用して、変更を確認していきます。
自分は本を読んで勉強するというタイプではなく、try-errorで実際に触って勉強するタイプです。
Swiftの文法も書きながら覚えていきましたが、ちょくちょくこれどうやればいいの?っていうのにぶつかりました。特にKotlinのsmartcastの知識が邪魔してきました。。。if let guard
などは文法が結構特殊なので最後まで慣れませんでした。あと、一番の問題はSwift3を調べたいのですが、大量にSwift2などの古い日本語ドキュメントが出てきます。iOS開発者辛いなーという感じでした。OptionalもコンセプトはKotlinと似ているのですが・・・。この辺りでKotlinとSwiftが似ていると言っていた人を罵りたくなってました。
コレクション処理に関してはRubyやJava8、Kotlinなど他の言語でもよくあるものなので、そこまで苦しまなかったです。
残念ながら今回採用はしなかったのですが、Cコードの導入を試みました。
Androidであれば、NDKを入れて、Cコードとjnlを用意してーと本当に多くのことをやらないとCコードを利用することは出来ません。iOS開発のこれは強みで、比較的簡単に利用出来ます。
導入方法としては
wildmatch.h
/wildmatch.c
#import "wildmatch.h"
wildmatch.h
にあるメソッドを呼び出しますこんなことで利用出来てしまうんか!と驚愕しました。Xcodeのコンテントアシストにも即時反映されるし、驚きっぱなしでした。
SwiftにもJavaのリフレクションがありました。Mirror
というクラスを利用します。実はこれ使い方が間違っていたのかうまく動きませんでした。
1 2 |
|
ちなみにこのコードであれば動きます。
1 2 |
|
たぶんselfとかのせいだろうなーと思いましたが、深追いはせず。
ざっくりですが、JUnit3とほぼ同じです。
setup
/tearDown
メソッドが存在しているtest
prefixをそれぞれのテストメソッドにつけるBuildしたところにTestという選択肢があるので、それを選らんで実行。Java開発に慣れているなら特に問題なかったです。
ある程度開発した後に気づいたので、今回は利用しなかったのですが、XCTestでのTDD開発も可能です。たぶんそちらのほうが推奨されているのではないでしょうか。
メンテナさんにも指摘を受けたのですが、やっぱりところどころSwiftらしくない書き方をしてしまっているようです。たぶんKotlinの癖が出ているのではないかと。まだSwift力が低すぎてどこのことを言っているのか不明でした。
また、Swiftのif let
やguard
には結構苦戦しました。例えば今回こんな感じで、ignoreFile
という変数を初期化するコードを書きました。
1 2 3 4 5 |
|
let rswiftignoreURL
が
1 2 3 |
|
このスコープ内で使えることに違和感がありました。
Kotlinの場合は?.let
を利用した場合、lambdaの{}
内で変数定義します。(上記Swiftコードはelse
もあるので再現するには、?.let
ではだめだけど。あとit
もあるけど、それは省略。)
1 2 3 |
|
メインテナさんがPR投げてから、昇華していこうぜスタイルの自分にとって理想的な人でした。彼?のおかげで、わかる点までやってみて結果を貼って、質問するスタイルで勉強しつつコードを完成させることが出来ました。
みんな使ってね!
]]>This entry is focus on tips for creating intellij plugin in Kotlin. (But I still believe it is useful for Java developers.)
For more basic tips, please read Tips for Creating Intellij Plugin
Finding parent is just calling PsiElement#getParent()
. However, in most case, I want to find a specific type of parent. In that case, using extension methods in psiUtils.kt
is the best way to do it. psiUtils.kt provides variety of useful extension methods.
For instance, if I want to find the function that the element belong,
1
|
|
This method return null
if there is no applicable element. (In the example, if the element is not located inside a function, it will be null.)
For Java developers, use PsiTreeUtil.getParentOfType()
After finding psiUtils.kt
, I was expected to find children using something like getStrictChildrenOfType
or something. Guess what. I was wrong. There are more useful methods in psiUtils.kt. The reason why it is not getStrictChildrenOfType
is I guess it requires to recursive tree visiting.
To find all children of specific types, use collectDescendantsOfType
1
|
|
To find existance of children of specific type, use anyDescendantOfType
1
|
|
To find the one child of specific type, use findDescendantOfType
1
|
|
When I want to iterate though all resource files in my project, following one liner archive it
1
|
|
(Watch out .idea/
folder. It is also include as “Project” so this line also grabs all xml files in “.idea”.)
This method find all files in specific types of specific scope. The above line finds all xml files in my project.
]]>kotlinにcontributeし始めました。ドキュメントに書いてない部分があったので、主に自分用になりますが、書いておきます。
この文章は2016/07に書かれたので、その後、contribute方法が変わっているかもしれません。
contributeする前にREADMEは必ず読み込んでください。
特に、JDKの設定は複雑です。jdk1.6, 1.7, 1.8全てが必要で、それらをドキュメント通り指定します。
1
|
|
こんな感じで設定していきました。
自分はWindowsでの開発をしていないのですが、Windowsで開発する場合、JDKはOracleさんが出しているものが良いようです。
Macであれば、OpenJDKでもOrableのやつでもどちらでも問題なくビルドできるそうです。
buildコマンドは2017/09/20にgradleを利用する大きな変更が入りました。時間が出来たら反映します。
pullには結構時間かかります。buildコマンドはドキュメントにある通り、
1 2 |
|
kotlin開発用プラグインのインストールも必要です。
全てが揃わない限り、ビルド出来ません。このあたりで断念するのはもったいないので、わからなければ、slackのkotlinlangのkontributorチャンネルで聞いてください。
kotlinlangのslackはhttps://kotlinlang.org/community.html%E3%81%93%E3%81%93%E3%81%AB%E8%A9%B3%E7%B4%B0%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82
よくハマるのが、antの設定です。Heapサイズを増やさないとビルド出来ないことが多々発生します。
以下のようにANT_OPTS
を設定して下さい。Xmxの数値は任意。
1
|
|
.idea/runConfigurationを見てもらうとわかるのですが、かなり多くのrun設定が含まれています。
ビルドが成功すれば、それらをrunするだけで、動きます。IDEAをrunすると自分の修正を取り込んだIntellijが立ち上がります。
UnitテストもIDEAなどと同じでrun設定から起動します。
一つ一つのテストを起動することも出来ますが、working directoryがプロジェクトrootを指定しない限り動かないので注意。All IDEA Plugin Testsの設定を参考にしてください。
ideaSDK/config-idea
の中身を全て消せばいいらしい。
でもそれで動くマシンと動かないマシンがあった。これに関しては謎。動かないマシンはもう一回環境構築しなおしてみます。
理由がわかりました。テスト時にSDKに設定されているプラグインを全て読み込みます。
File > Project Structure > 1.8 > Classpath
私の場合、ここに、CE版のgithubプラグインのパスが設定されていました。これを削除すると動くようになりました。
別プラグイン開発で使っていたものが残っていました。
READMEにもありますが、kotlinにはまだまだいっぱいやることがあるので、contributeし放題です。
YouTrackからやりたいものを選んで下さい。
そのスレッドにやるわこれ!とコメントすると良いです。やっていいのかわからない場合は、kontributorチャンネルでやっていいか?という質問を投げて下さい。JetBrainsの営業時間になればだいたい回答が来ます。
特にルールないらしい。なんでも良い。masterはさすがにマナー違反だと思う。
あんまりルールがあるように見えない。#KT-12345 Fixed
はつけたほうが良さ気。
基本書いたコードに対して考えられるケースのテストを書くことになる。XxxTestGenerated
という名前のクラスはRun ConfigurationのGenerate Testsで自動生成されたテストケース。これらのテストケースは編集しない。
例えば、Inspectionのテストの場合、InspectionTestGeneratedがあり、これにテストを追加するにはidea/testData/inspections
配下にフォルダを作成し、その下にテストデータを作成する。その後、"Generate Tests"を起動させると、テストケースが追加される。
新規のUnit Testを書くことになるIssueもある。
その場合、通常通り、JUnitでテストを作成してもいいのだけど、KotlinCodeInsightTestCase
を継承した、abstract classを作成し、GenerateTests.ktに追記すると、上記"Generate Tests"の対象となり、abstractクラスで作ったロジックに則った自動テストを作成することが出来る。
例えば、このPRではAbstractConcatenatedStringGeneratorTest
を作成して、ConcatenatedStringGenerator
クラスをテストする自動テストケースを作成している。
特に気にせず投げてOK。
投げた後に、そのURLを対象のYouTrackのissueのコメントに貼り付けて欲しいとのこと。
マージはcherry-pick?でマージ先をJetBrainsの中の人がやってくれる。微修正までしてくれる。Authorは自分になる。(CommiterがJBの中の人。)
こんな感じ。
https://github.com/JetBrains/kotlin/commits?author=shiraji
kotlinプラグインは結構な頻度で更新されていきます。
急にビルド出来なくなった場合、まず、kotlinプラグインを最新のバージョンにしているのか確認して下さい。
また、masterにマージされているものが時々ビルドエラーを起こしたりします。こうなるとその修正が入るまで特に何も出来ません。我慢して待ちましょう!
ただ、2~3日ビルド出来ないというのは何かしら環境がおかしい場合があります。その時は以下の作業をしてみます。
ideaSDK/config-idea
以下を削除する(Run時に使うプラグインを削除)ant -f update_dependencies.xml
を実行するant dist
を実行するそれでもだめならkontributorチャンネルで聞いてみましょう。
殺伐としておらず、やりたい!と手をあげたらやらせてくれる。ちょっとわかんね。となっても質問すれば教えてくれる。
kontributorチャンネルで聞けばだいたい問題は解決する。やってほしいIssueとかも聞けば答えてくれる。非常にやりやすい感じでした。
IDE周りは今まで結構コード書いてたり読んでたりしているので、引き続きcontributeしていこうかなと考えています。
]]>When I created Intellij custom wizard called gradle-intellij-plugin wizard, I read JetBrains official documentation. They explains how to support module types and how to add new steps. However, what I want to know is how to add custom fields, how to add custom files, and how to customize files based on custom fields.
There is no such documentation at this point, so I decided to write this entry for me.
ModuleWizardStep
To add custom views, it really simple.
1 2 3 4 |
|
Add custom views to JComponent
and return getComponent()
.
If you make a form file which binds to your ModuleWizardStep
, then just return root panel.
In my case, I created GUI form file Then, bind the form file to IPGWizardSupportLanguageStep.
It ends up
In order to add “Project SDK” field, you need to override getModuleType()
in your ModuleBuilder
For instance, to pick standard Java sdk, write following code in kotlin.
1
|
|
ModuleWizardStep
If a user click “Next” button, ModuleWizardStep#updateDataModel()
will be called. You should pass/save the user input in the method.
In my case, it looks really bad design, but it directly passes the language to builder.
1 2 3 4 |
|
To create a file for new project, You can use VfsUtil.saveText(VirtualFile, text)
.
I found really great method in intellij-community repo.
I wish they open this method.
Use file template. You can check official documentation of File and Code Templates
One thing I want to add is condition. The file template support conditions in following syntax.
1 2 3 4 5 |
|
Watch out the indentation. You will generate useless spaces.
日本語
Intellijのカスタムwizard gradle-intellij-plugin wizardを作った時、JetBrainsの公式ドキュメントを読みました。
ただ、この公式ドキュメントはsupport module typesとhow to add new stepsしかなく、カスタムフィールドの作成方法や、ファイルの追加方法、ファイルの編集方法などがありませんでした。
そこで、このエントリーでその辺りの説明をしたいと思います。
ModuleWizardStep
内での入力情報の取得方法カスタムビューの追加方法は正直言うとかなり簡単です。
1 2 3 4 |
|
このメソッド内でカスタムビューを作成し、returnすればOKです。
もし、カスタマイズしたModuleWizardStep
をformファイルにバインドしているのであれば、ルートのpanelをreturnするだけです。
自分の場合、フォームファイル これをこっちにバインドしています。 IPGWizardSupportLanguageStep.
最終的に出来上がるのが
“Project SDK"フィールドを作成するには、getModuleType()
を継承する必要があります。
例えば、スタンダードなJava SDKを追加したい場合、以下のようにKoltinで記述します。
1
|
|
ModuleWizardStep
内での入力情報の取得方法ユーザが"Next"ボタンをクリックすると、ModuleWizardStep#updateDataModel()
が呼ばれます。このメソッド内で値を取得したり、保存したりします。
自分の場合、かなり設計がクソだけど、builderに直接設定しちゃってます。(動けばええやろ?)
1 2 3 4 |
|
ファイルを新しいプロジェクトに追加するには、VfsUtil.saveText(VirtualFile, text)
を使います。
intellij-communityのレポジトリにめっちゃ良いメソッドがありました。
これ公開してくれたらいいのにね。
IntellijのFile templateの仕組みを使います。File templateのFile and Code Templatesを読むと良いです。
一つ、条件文に関して記載がなかったので、追加で説明します。条件文の文法は以下です。
1 2 3 4 5 |
|
spaceいっぱい生成しちゃうのでインデント気をつけて下さい。
]]>I am a maintainer of PermissionsDispatcher Plugin which generates Java and Kotlin for PermissionsDispatcher Since Kotlin is getting famous for Android developers, I thought IntelliJ plugins, which generate Android code, should support both Java and Kotlin. (By the way, Kotlin 1.0.2 now supports Android lint! This definitely will lead more developers use Kotlin!)
However, while I was developing this plugin, I found really hard to generate both Java and Kotlin code.
So, this blog post describes what are the differences between generating Java and generating Kotlin using IntelliJ plugin.
Before start taking about the differences, the followings are the environment for this blog post.
getClasses
for PsiJavaFile
vs KtFile
1
|
|
returns PsiJavaFile
or KtFile
. Both of them implements PsiClassOwner
which means both of them has the method PsiClass[] getClasses()
.
This method is useful for PsiJavaFile
, it lets access classes of the file. The plugin can read/write contents of the classes.
For KtFile
, I expected the same. I want to read/write code of classes. Yes, you can read .class
file. It is not classes inside .kt
file. So, even though, it has methods add
, addBefore
or addAfter
, KtFile#classes#add
throw an exception says the plugin won’t be able to write contents to .class
file!
If you want to get objects for generating code of Kotlin, then use KtFile#getDeclarations
.
PsiFactory
This could be because I could not find the best way to generate code…but PsiFactory of Java and Kotlin is different
1
|
|
1
|
|
PsiMethod
has modifierList
1
|
|
On the other hand, KtNamedFunction
has addAnnotationEntry
1
|
|
To insert new line after annotation, you need to add new line manually.
1 2 |
|
PsiClass
is easy to add method. Use createMethodFromText
and add
to PsiClass
1 2 3 4 |
|
For kotlin, it’s almost the same.
1 2 3 4 |
|
There are tips for creating intellij plugins
This is note for myself. I won’t add description if the sample is clear enough for me.
Simply use Sys-out
1
|
|
However, sys-out shows logs on the console. If you want to show pop up, use notification
1 2 3 4 |
|
1
|
|
1
|
|
To use kotlin, IDE version should be higher than 143.
1
|
|
1
|
|
1
|
|
To decide show the action or not, I need to override the update method.
This method should be less than 0.1 sec to complete.
1 2 3 4 5 6 7 8 9 |
|
ForwardingAstVisitor
has life cyclevisitCompilationUnit
, End afterVisitCompilationUnit
The past few weeks, I am working on creating custom lints for PermissionsDispatcher.
Using ForwardingAstVisitor
is the easiest way to implement custom lint. I found there are 75 “visit” methods in the class. For instance, visitMethodDeclaration
is called for iterating all method declarations. visitIdentifier
is for all identifiers. Trust me, there is even visitIf
and visitSwitch
that are called for each if
and switch
.
However, I could not find any documentations that describes which “visit” method comes first. So…this is the post that describes what is the “lifecycle” of ForwardingAstVisitor
.
There are 4 types of methods, visit
, visitNode
, afterVisit
, endVisit
for ForwardingAstVisitor
.
visitXxx
comes firstvisitNode
comes second for dive into the nodeafterVisitXxx
comes if there is no more method call inside visitXxx
endVisit
comes for wrap up.For instance, followings are the method call for checking @Override
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Now, let see what’s happens if I want to lint check for a Java file.
Assuming I am going to check following class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Here is the debuging code. It’s basically Sys-out method name and node
parameter. And the output is this
OK, Too long…let me summarize idea.
visitCompilationUnit
visitPackageDeclaration
for package pkg;
(Meaning, it starts from the first line of the class)afterVisitCompilationUnit
Now, we know the lint checks goes the top to the bottom. However, there is an exception, Annotation.
@RuntimePermissions
which is located the above of the class declaration in the example above.
Actually, when we run the lint checks, visitClassDeclaration
comes first and then visitAnnotation
comes later.
It seems that the lint handles annotation as a node inside of method declaration.
For example, if we want to store class declaration object which @RuntimePermissions
, we cannot do followings:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Instead, I would use afterVisitClassDeclaration
and call requestRepeat
to run other detector which uses class declaration objects.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
First of all, I am one of collaborators of PermissionsDispatcher which makes developers handle runtime permissions very easily.
PermissionsDispatcher now have a custom lint for its library. Initial issue came from this comment.
The library requires the developer to define a method with @NeedsPermission
. Like this
1 2 3 |
|
However, this method should not directly access. Instead, the developers must use a method that PermissionsDispatcher generated.
1 2 3 4 5 6 7 |
|
In order to make sure the developers did not call this method, we decide to provide custom lint for this library.
To create custom lint for Android application, check links below
Custom lint for library needs extra settings to inject lint.jar
to its .aar file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Basically, if there is compileLint
task, then make the task depends on copyLintJar
task which copies lint.jar
to build/intermediates/lint/
The user of this library doesn’t need to put lint.jar to .android/lint/
. Just sync library and then run ./gradlew lint
Just don’t.
Check this code
1 2 3 4 |
|
This is the code that reads from $ROOT/tools/base/lint/libs/lint-tests/src/test/java/PACAKGE-NAME-REPLACE-DOT-WITH-SLASH
.
I believe most developers doesn’t want to put project in the specific directory in order to pass the test cases.
Actually, current version of LintDetectorTest
has a lots of problems with loading resources, java source and “class” file. (Yes! you need to supply .class file to run the test)
In order to use the LintDetectorTest
, the developer must override protected InputStream getTestResource(String relativePath, boolean expectExists)
like what AOSP did
LintDetectorTest
is still Beta. I assumed there are a lot of work to make it production release.
If it comes to production, I hope it does not require me to pass .java/.class file like this way.
1
|
|
I don’t know.
The only way I came up is manual testing.
So, someone who know better way to test lint, please let me know!
]]>privateアクセス修飾子をつけると条件次第で勝手にメソッド余分に生成されるから気をつけてね!
Jakeさんがこのpull requestを投げていて、察するに$accessorというメソッドが生成されてしまうので、それを生成しないようにしたぜ?ってことだと思う。が、なんでそうなるのかわからない。 他にも、コンストラクタの修飾子を変更しているんだけど、これもなんのためなのかわからない。 そこで、コードを書いてみて、実際にやってみました。
このpull requestでは以下の4つを修正しています。
この変更がわかりやすいようにサンプルコードを作成してみました。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
違いは、PrivateConstructor内にある、AbstractInnerClassのコンストラクタにprivateがあるかどうかです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Javaファイル内では違いはprivateだけでしたが、classファイル内では、以下のメソッドが出来ています。
1
|
|
これが生成されることで、メソッド数がDefaultConstuctor.javaでは3つなのに、PrivateConstructor.javaでは4つになってしまいます。 なぜこうなるのかというと、PrivateConstructor$InnerClassが継承するために必要なコンストラクタを定義する必要があるためです。
実際こんなクラスを定義してみるとわかります。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 |
|
PrivateConstructor$AbstractInnerClassだけしか定義されておらず、privateのコンストラクタにアクセスする必要がないため、PrivateConstructor$AbstractInnerClass(PrivateConstructor, PrivateConstructor$1);
は生成されません。
今回の修正で一番おもしろいのがこれです。
1 2 3 4 5 6 |
|
これをコンパイルすると、以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
コンストラクタが生成されています。
1 2 |
|
Javaではコンストラクタを定義していない場合、デフォルトコンストラクタが生成されます。 しかし、そのデフォルトコンストラクタはclassのアクセス修飾子と同じものが定義されます。
AbstractClass
はprivateで定義されているため、privateのデフォルトコンストラクタが定義されます。それがこれ
1
|
|
それで、このコンストラクタにアクセスするためのコンストラクタを定義する必要があるので、
1
|
|
これが生成されます。
メソッドを0で定義していますが、実は4つのメソッドが出来ていました。 少なくともprivateのデフォルトコンストラクタはいらないので、空のデフォルトコンストラクタの変更を入れているわけです。
この変更も面白いです。
サンプルコードはこんな感じです。
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
こんなのが出来ています。
1
|
|
これは、Innerクラスからflagにアクセスするためのメソッドです。 privateアクセス修飾子のため、アクセス出来ないので、accessというprefix付きのメソッドが生成されflagにアクセス出来るようにしています。
パターンパターン!ですけどメソッドのアクセス修飾子も同じです。
サンプルコードはこれ。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 |
|
これでprivateを外すとこうなります。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 |
|
static void access$000(PrivateMethod);
が減りました。
これもアクセスするために生成されたメソッドです。
Javaのアプリケーションではそこまで影響度はないですが、Androidはメソッド65K問題があるので、メソッド数には注意が必要です。特に利用しているライブラリではメソッド数を減らそうという狙いがあったのだと思います。
Jakeさんは他にもこの自動生成されるメソッドの検出方法をコメントしています。
Androiderは盲目的にprivateのアクセス修飾子にすればいいという考えは辞めたほうがいいようです。
ちなみにJakeさんは一つどうしようもない例も出してくれてます。
これはメソッドを減らすことがどうやっても出来ないそうです。
]]>勉強出来そうなプロジェクトを選らんで、pull requestを投げて、レビューしてもらうと勉強になるよ。
30歳を超えて、会社では中堅になりました。昔は会社から与えられた仕事をこなすことによって成長を感じられていました。ここ数年は後輩に教えたり、リソース管理などをすることが多くなり、エンジニアとしての成長を感じられなくなってしまいました。(マネージメント力の成長は感じています。)このままではいかん!ということで、考え出したのがプルリク駆動勉強です。
プルリク駆動勉強とはpull requestを投げるためにそのプロジェクトを学んだり、英語でのコミュニケーションをしたり、その言語のベストプラクティスを体で覚えたりすることです。
とにかくpull requestを投げてレビューされることを目的にします。
pull request投げるなんて出来ない!怖い!って思うかもしれません。 確かに急に新しい機能の提案するのは中々通らないし、レビューすらしてくれないこともあります。しかし、すでにあるIssueのうち、プロジェクトオーナーが「これはやりたいけど、時間が〜」と言っているようなものはくそコードを投げつけてもしっかり受け止めてくれ、そのコードをより良いものに仕上げるようにアドバイスくれます。
このレビューが非常に良く、凄腕のエンジニアが無料でコードを見てくれてアドバイスまでくれるのでスキルアップに最適です。こっちは勉強のつもりなんですが、pull requestを送っただけで感謝されることだってあります。もしそのコードがマージなんてされちゃえば、有名どころのプロジェクトの一部が自分のコードで動くことになるわけです。これは嬉しい。
かといって、無闇やたらにpull requestを投げてもいいことはないので自分の経験からこれなら勉強出来る!というものを説明していきます。
自分は以下の条件でpull requestを投げるプロジェクトを選定をします。
GitHubのスターが多いものは注目度が高く、利用価値が高いです。またこういうプロジェクトの開発に関わっている人は技術レベルが高く、pull requestへのレビューもかなり厳しくなります。こういうプロジェクトにコントリビュート出来るとモチベーションアップにも繋がるため、有名どころを積極的に狙います。
ただし、有名どころだと「バグ報告はありがたいけど、いきなりコードのコントリビュートはしなくていい」と言うところもありますので、CONTRIBUTING.mdは注意して読んで下さい。
1年以上放置されているライブラリだとマージどころかレビューされない可能性が高くなります。それでは意味がないので、コードレビューがされているかどうかの確認は絶対行います。
マージ権限があるユーザ(Collaborator)が複数いるとかなり良いです。マージしているコミッターが複数いるかどうかをコミット履歴から追ってみるとわかります。
有名どころのプロジェクトはリソースがないから対応していないIssueが結構あります。新参者がいきなりそういうIssueに対してpull requestを送るのは怖いと感じるはずです。(pull request投げるのに慣れると特段気にならなくなりますが。。。)
Issueが整理されているプロジェクトでは、誰がコントリビュートしてもいいよ!というラベルが貼ってある場合があります。例えば、自分がちょくちょくコントリビュートしている、AndroidAnnotationsではContributionWelcomeがそれに当たります。 こういうラベルがあれば、いつでもバッチコイやと宣言しているので、新参者だろうと特に気にせず、pull request投げてしまいます。大抵の場合、何をするべきかということがしっかりIssueに記載されていますので、その通りに実装すれば良いだけです。
ラベルが管理されていないところでも、Issueにこれやってもいいかね?というコメントをしてしまうのもありです。マージしている人が上げているようなIssueは特に狙い目で質問もしやすく、レスポンスも早いです。
一ヶ月以上前に上げられたpull requestが10件以上放置されているようなプロジェクトは危険です。
大抵、pull requestはマージしてほしいから出しているわけで、コントリビューター側の問題で放置されるというのは稀です。プロジェクトオーナーがレビューしてくれない、マージする気がない、忙しいことが多く、そういうプロジェクトにpull requestを投げても放置されるだけで勉強出来ません。時間の無駄です。
GitHub内で完結していないプロジェクトは避けます。Issueが別サイトであったり、sourceがcloneで一発取得できなかったりするものです。そのプロジェクト特有のローカルルールはラーニングコストが高いわりに学んでもそのプロジェクトでしか使えないためです。
どうしてもそのプロジェクトのコントリビュートがしたい!という人であれば、全力で推奨しますが、そういうプロジェクトは新参者に対しかなり壁が高く、最初からそういうのを狙ってしまうと続けられなくなります。
ビルドやテストが通る環境が出来てしまえさえすれば、そのプロジェクトを使ったことあるなしは特に問題ありません。
自分の場合、今直近で出しているpull requestは全て使ったことがないプロジェクトだったりします。 (ぶっちゃけると使ったことがないほうがマージされて壊れちゃっても業務に支障出ないし、気楽だったりします。)
プルリク駆動勉強で必要なスキルは以下です。
pull requestを投げるまでの流れはググればすぐ出てくるので、説明省略。
それ以外でもgit/githubの問題はやっているとちょくちょく出てきますが、都度やりたいことをググれば出てきます。勉強して下さい。どうしてもわからない場合は直接聞いてしまってもいいです。
fork元のブランチとの同期方法が最初の壁だと思います。面倒であれば、forkしたリポジトリを消して再度forkして同期を取るのもありです。 (ただし、マージ前のpull requestがあったりすると面倒なので、注意。) これも勉強だと思って、わからないのであればググッてみて下さい。「fork 更新 追随」とかで検索すれば出てきます。
特に経験の少ない人や潰れていった人に多いのがコードレビューの指摘点がその人に対して言っているのでは?と勘違いしていることです。
コードレビューはコードに対して言っているのであって、そのコードを書いた人に対しては言っていないです。
この考えになってない人は早めに切り替えないと精神的に病みやすいので気をつけて下さい。 辛辣な意見があるかもしれませんが、あなたを否定しているわけではないです。 (逆にコードを書いた人を否定するような意見をするレビュアーがいる場合、さっさとそのプロジェクトから離れるなり、転職するなりしたほうがいいです。そういう人と一緒にコード書いても精神的に疲れるだけです。)
プルリク駆動勉強で一番問題なのが、「自分のスキルではまだ出来ない」と思う心の壁です。
どれほどしょぼいコードでもpull requestを投げることで、そのプロジェクトに関わっている人に指摘してもらい、コードをどう書けばいいのかがわかってきます。
自分の場合、一度も書いたことなかった言語を触りたいからということで、コード読んでpull request投げたこともあります。
最終的に良いアウトプットになればいいわけで、最初から完璧を目指す必要がないです。また最初からほぼ完璧なコードが作れるのであれば、プルリク駆動勉強はもう卒業しています。
会社でのプログラミングは社内の特殊なルールがあったりし、社外で通じないことが多々あります。有名どころのプロジェクトではベストプラクティスを求められるため、じっくり設計し、自分が考えたさいきょうのコードを作り上げることが出来ます。どんなことでもコントリビュートしてくれたことに感謝してくれるプロジェクトが多いです。無料で世界レベルのエンジニアに教えてもらい、さらに感謝までしてもらえます。そのコードがマージまでされれば、世界で使われるような有名なプロジェクトが自分のコードで動くことになります!
まだ3ヶ月ほどですが、これをやるようになって、Java8, Groovy/Gradle, Kotlinの勉強が出来ました。Rubyや英語のスキルも上がったことを実感しています。
また、gitの知識もかなり深まりました。他人の途中のpull requestを自分のpull requestとして取り込み、修正し、投げるみたいな貴重な経験も出来ました。小さいアイコンと大きいアイコンが一度に出るようなコミット見たことありますか?
時間をかければかけるだけ勉強は出来ますが、業務に支障が出たり、最悪体を壊してしまいます。
以前はブログを書いたり、本を読んだりと夜遅くまでダラダラをやっていました。でもいまいち成果が出なかったです。今は短い時間で集中して結果を出していくことを心がけています。夜12時には寝ます。お昼休みの食後30分と子供が寝た後の1時間だけやっています。無理は絶対にしません。だって、納期はありませんから。
一日多くの時間がないので、毎日コミットは出来ません。Issueやコードを読むだけで過ぎてしまう日もあります。でも週1くらいのペースでpull requestを投げられています。
スケジューリングに時間を使うのも無駄なので、一個終わったら次のIssueへという流れにしています。
そんなこといってもお前スキルあるからやれるんでしょ?みたいな人がいるかと思うので、実際に自分がつい最近送ったくそpull requestを晒しておきます。
https://github.com/excilys/androidannotations/pull/1673
すでに指摘を受けて修正していますが、最初のpull requestを投げたタイミングで、「It’s ready for review.」(ドヤア)と言っておきながら、 AndroidManifest.xmlのActivityタグにViewクラスを指定するという意味不明な行動をしていたり、newInsanceVarというtypoをかましていたりといろいろひどいです。それでも罵られたりすることはないです。(いい加減罵られたほうがいいんじゃねーか?というレベルなのですが・・・)
この勉強法を使って経験が浅い若手や学生がどんどん世界で腕を磨いてくれたらと思います。特に時間のある人は積極的にコードを公開し、レビューを受けて腕を磨いて下さい。早ければ早いほど学べることが多いと思います。
自分もスキルに自信がついたら・・・とGitHubでpull requestをほとんど送ってこなかったのですが、そんな自信はやらない限り絶対につかないです。どんどん他人のプロジェクトで失敗して、腕を磨いて下さい。
]]>http://shiraji.hatenablog.com/entry/2015/09/06/225204
この文章は以下に該当する方へ、なぜエンジニアにリファクタリング(リファクタ)させるべきなのかを記載しています。
リファクタリングの話をする前に、一般的な職場に関する質問があります。
全ての人に当てはまるわけではないと思います。しかし大抵の方は両方回答がYesになると思います。
職場を綺麗にするのはそこで働く人の健康維持やモチベーション向上に役立ちます。職場を綺麗にしてくれる専門のスタッフがいる企業もあるのではないでしょうか?また整理整頓された机で仕事することにより、ムダを省略することが出来ます。仕事をするスペースが増えることにより効率もあがります。大抵の出来る人は机を整理整頓している傾向があるそうです。著名な会社の研修でも同じようなことを説いていました。
汚い環境で働くということは、モチベーションを下げ、ムダな作業を発生させ、効率を下げるということです。汚い環境で働くのは非常に辛く、可能であれば、人はその環境から離れていきます。
さて、本題のリファクタリングについてです。wikipediaでは以下のように説明されています。
リファクタリング (refactoring) とはコンピュータプログラミングにおいて、プログラムの外部から見た動作を変えずにソースコードの内部構造を整理すること。((“リファクタリング (プログラミング)”. wikipedia. https://ja.wikipedia.org/wiki/%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0))
もう少しサービス開発に絡めて切り込んだ説明にすると、
「リファクタリングするということは、サービスの機能の追加や削除は一切行わず、コストをかけて、今まで動いていたコードに対して修正を加える作業です。」
リファクタリングをすることにより、バグを埋め込んでサービスを止めてしまう可能性も含まれることになります。もちろんそれを避ける術はいくつかあるのですが、手段はエンジニアが考えればいいのでここでは省略させていただきます。
なぜこんなムダな作業を行うのでしょうか?エンジニアはアホなんでしょうか?
(実際、アホなことやる人は多いですが・・・)事自分たちが行っているサービス開発に関して言えば、プライドを持って行っているはずです。サービスに携わっている以上、そのサービスがより良くなることを望んで開発しています。そのエンジニアがコストがかかることを承知で、リファクタリングさせて欲しいという理由があります。それはエンジニアはコード上で仕事をしているということです。
私が非エンジニアにリファクタリングの重要性を説明する時は以下のように説明します。
ではエンジニアはコード上で仕事をしているということなので、デスクを「コード」、置かれていく資料を「追加機能」と読み替えてみます。
エンジニアが作業しているコードを綺麗にすることにより、将来的にバグを作り出さなかったり、効率良く作業が出来る環境を作ることが出来ます。
汚い環境で働くということは、モチベーションを下げ、ムダな作業を発生させ、効率を下げるということです。汚い環境で働くのは非常に辛く、可能であれば、人はその環境から離れていきます。
この文章も同じように読み替えることが出来ます。
汚いコード上で働くということは、モチベーションを下げ、ムダな作業を発生させ、効率を下げるということです。汚いコード上で働くのは非常に辛く、可能であれば、エンジニアはそのコード(会社)から離れていきます。
エンジニアが働く場所の環境を良くすることとそのエンジニアを魅了するためにリファクタリングをさせる猶予を与えてあげてください。この魅力的な余裕があることでエンジニアとしてやる気が向上し、整理されたコードで仕事が出来るためパフォーマンスが上がります。働きやすい職場(コード)で最高のパフォーマンスを出すことが出来るのであれば、エンジニアが離職するのを引き止めるのに役立つはずです。
汚い場所で人を働かせることが辛いということがわかるのであるなら、ぜひ汚い環境で働かされているエンジニアに掃除をする猶予を与えてあげてください。それが長期的に見るとサービスを改善を早くし、技術力のあるエンジニアを定着させ、変化に柔軟なサービスを提供させることが出来るようになるからです。
]]>