Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Java→Kotlinの移行率を算出するコマンドラインツールをKotlinで実装してみた話...
Search
yu mitsuhori
December 20, 2018
Technology
1
310
Java→Kotlinの移行率を算出するコマンドラインツールをKotlinで実装してみた話.pdf
- コマンドラインツールをKotlinで実装してみた話です
- 2018.12.20 Kotlin愛好会で発表したスライドです
yu mitsuhori
December 20, 2018
Tweet
Share
More Decks by yu mitsuhori
See All by yu mitsuhori
【DroidKaigi版】ReactNativeとKotlinで叶える夢のリアルタイム音声配信
youmitsu
1
3.1k
ReactNativeとKotlinで叶える夢のリアルタイム音声配信
youmitsu
1
800
stand.fm(Android)におけるreact-native-track-playerの改善
youmitsu
1
2k
TargetSdkVersion29で BottomNavigationが点滅する件
youmitsu
1
1.5k
リリース前のリグレッションテストをUIテストで自動化、1年間運用した話
youmitsu
2
350
New features in RemoteConfig, Analytics at Google I/O 2019
youmitsu
1
660
FirebaseNotification,RemoteConfigでユーザセグメントごとにプッシュ通知を実装する
youmitsu
8
1.5k
Report from Google I/O 2019
youmitsu
1
86
OSSにコントリビュートした話
youmitsu
1
81
Other Decks in Technology
See All in Technology
E2Eテスト自動化入門
devops_vtj
1
100
【内製開発Summit 2025】イオンスマートテクノロジーの内製化組織の作り方/In-house-development-summit-AST
aeonpeople
2
1.1k
開発組織を進化させる!AWSで実践するチームトポロジー
iwamot
2
490
JAWS DAYS 2025 アーキテクチャ道場 事前説明会 / JAWS DAYS 2025 briefing document
naospon
0
2.6k
データベースの負荷を紐解く/untangle-the-database-load
emiki
2
540
Exadata Database Service on Cloud@Customer セキュリティ、ネットワーク、および管理について
oracle4engineer
PRO
2
1.5k
事業モメンタムを生み出すプロダクト開発
macchiitaka
0
100
ABWG2024採択者が語るエンジニアとしての自分自身の見つけ方〜発信して、つながって、世界を広げていく〜
maimyyym
1
190
LINE NEWSにおけるバックエンド開発
lycorptech_jp
PRO
0
330
いまからでも遅くない!コンテナでWebアプリを動かしてみよう!コンテナハンズオン編
nomu
0
170
Snowflake ML モデルを dbt データパイプラインに組み込む
estie
0
110
【5分でわかる】セーフィー エンジニア向け会社紹介
safie_recruit
0
19k
Featured
See All Featured
Designing on Purpose - Digital PM Summit 2013
jponch
117
7.1k
Producing Creativity
orderedlist
PRO
344
40k
StorybookのUI Testing Handbookを読んだ
zakiyama
28
5.5k
How to Ace a Technical Interview
jacobian
276
23k
The Cult of Friendly URLs
andyhume
78
6.2k
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
Git: the NoSQL Database
bkeepers
PRO
428
65k
Measuring & Analyzing Core Web Vitals
bluesmoon
6
260
Building Flexible Design Systems
yeseniaperezcruz
328
38k
Designing Experiences People Love
moore
140
23k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
Mobile First: as difficult as doing things right
swwweet
223
9.5k
Transcript
Java→Kotlinの移行率を算出する コマンドラインツールを Kotlinで実装してみた話 Yu Mitsuhori
自己紹介 三堀 裕 Android Developer 女性向けのヘルスケアアプリを担当してます。 Twitter: @1013Youmeee GitHub: https://github.com/youmitsu
Qiita: https://qiita.com/youmeee
Question 皆さんKotlinで何を作りますか?
None
None
None
コマンドラインツールも作れます
Java→Kotlinの移行率を算出する コマンドラインツール を Kotlin で 作ってみました
KotlinReplaceSupporter
作ったもの 計算対象となるファイ ル一覧を出力 Projectルートで、 コマンド叩く 移行率の表示
本日のアジェンダ 1. 経緯 2. デモ 3. 実装方法 a. 環境構築 b.
実装 c. jarの実行 4. まとめ
経緯 ・会社の評価の際にKotlin→Javaのリプレース率を出さなければいけな い時があった ・一つ一つ手で計算するのもあれだし、Kotlinで書けるなら勉強も兼ねて やってみよう!どうせならツール化もしてみよう! (シェルとか書けば一発な気もしますがそこはスルーでお願いしま す。。)
デモ
開発環境 ・Mac Book Pro Sierra 10.12.6 ・IntelliJ IDEA Community 2017.3
・Kotlin 1.2.10
環境準備 1. File > New > Projectを押下 2. 左メニューからGradleを選択後、Kotlinのチェックを入れる 3.
そのまま必要項目を入力してプロジェクトを作成する ↑2の選択画面 3の 作成されるプロジェクト →
おおまかな処理フロー 1. 言語情報を保持するクラスを定義し、初期化する 2. 計算対象に入れたくないファイルをignoreするための Readerクラスを定義し、ロードする 3. ディレクトリの探索 4. 移行率の計算、ログの出力
実装①:言語情報を保持するオブジェクトの作成 /** * 言語の情報を保持するクラス * */ data class Language( val
name: String, //言語名 val extension: String //拡張子 ){ override fun toString() = name }
各言語のファイルリスト、移行元/先情報のクラス /** * 言語のlistを保持するクラス */ class SourceList( val language: Language,
val isReplaceTarget: Boolean, val list: MutableList<File> = mutableListOf()) { fun add(file: File){ list.add(file) } }
Main.kt(SourceListの初期化) val javaList = SourceList(Language("Java", "java"), false) val kotlinList =
SourceList(Language("Kotlin", "kt"), true) SourceListを初期化する 移行元がfalse, 移行先がtrue
実装②:計算対象に入れたくないファイルを無視する ・Androidだと自動生成されたファイル (R, DataBindingのファイルなど)を無視したい時あると思います。 ・.krsignoreというファイル名でProjectルートからの相対パスで記述する ことで、計算対象から外すように実装する
ignoreファイルを読み取るためのReaderクラスの作成 class IgnoreFileReader(ignoreFilePath: String, private val cd: String) { private
var fileReader: FileReader? = null var files: List<File> = mutableListOf() init { try { fileReader = FileReader(ignoreFilePath) } catch(e: FileNotFoundException) { } } fun read() { fileReader?.let { val filesStr = it.readLines() files = filesStr.map { File("$cd/$it") } } } }
Main.kt(ignoreファイル読み込み) val homeDir = System.getProperty("user.home") ?: "" val cd =
File(".").absoluteFile.parent val ignoreFileReader = IgnoreFileReader("$homeDir/.krsignore", cd) ignoreFileReader.read() .krsignoreファイルを参照して、プロジェクトのルートディレクトリ から初期化したFileオブジェクトを渡す
実装③:ディレクトリ探索用のクラス class SearchHandler( private val path: String, private val langList:
Array<SourceList>, private val ignoreDirList: List<File>) { lateinit var result: Result fun execute() { var sizeAll = 0 val rootDir = File(path) rootDir.walkTopDown() .filter { isNotIgnoreFile(it) }.forEach { file -> langList.map { langList -> if(isTargetFile(file, langList.language.extension)){ langList.add(file) println(file) sizeAll++ } } } result = Result(langList, sizeAll) } private fun isTargetFile(file: File, extension: String): Boolean = file.extension == extension /** * 対象外ファイルを無視する */ private fun isNotIgnoreFile(file: File): Boolean = ignoreDirList.none { file.startsWith(it) } }
ファイルを再帰的に探索する File.walkTopDown() Fileクラスに拡張関数として実装されている。 FileTreeWalkというクラスが返却される。これがSequenceイン ターフェースを実装しているためforEachで各Fileオブジェクトを ループで取得できる https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-fil e/walk-top-down.html
Main.kt(探索処理及び結果表示) val handler = SearchHandler(cd, arrayOf(javaList, kotlinList), ignoreFileReader.files) handler.execute() val
logger = ResultLogger(handler.result) logger.log() 画面表示についての説明は割愛します
最終的なmain.kt fun main(args: Array<String>) { val homeDir = System.getProperty("user.home") ?:
"" val cd = File(".").absoluteFile.parent val javaList = SourceList(Language("Java", "java"), false) val kotlinList = SourceList(Language("Kotlin", "kt"), true) val ignoreFileReader = IgnoreFileReader("$homeDir/.krsignore", cd) ignoreFileReader.read() val handler = SearchHandler(cd, arrayOf(javaList, kotlinList), ignoreFileReader.files) handler.execute() val logger = ResultLogger(handler.result) logger.log() }
jarをビルド task packJar(type: Jar) { manifest { attributes 'Main-Class': 'jp.co.youmeee.app.MainKt'
} from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } with jar } $ ./gradlew packJar 1. jarファイル生成のtaskを書いてあげて、 2. gradlew wrapperでタスク実行 3. build/libs配下にjarができる
jarを叩きやすくする ・生成されたjarを実行するには`java -jar krs.jar`みたいな感じで打つのは面 倒。。 ・今回は、homebrewで配布する方法で簡単に叩けるようにしました。(方法は 割愛します) $ ./AndroidStudio/HogeApp> krs
完成! 計算対象となるファイ ル一覧を出力 Projectルートで、 コマンド叩く 移行率の表示
まだKotlinにできるものがありますね、、? せっかくなので、、 build.gradle→build.gradle.kts にしてみました
build.gradle.ktsへの移行 ・GradleのビルドスクリプトをKotlinのDSLで書ける! ・既存のbuild.gradleファイルを消して、新たにbuild.gradle.ktsファイルを作成 ・こちらのマイグレーションガイドが参考になりました。 https://guides.gradle.org/migrating-build-logic-from-groovy-to-kotlin/
build.gradle buildscript { ext.kotlin_version = '1.2.10' repositories { mavenCentral() }
dependencies { classpath "org.jetbrains.kotlin: kotlin-gradle-plugin:$kotlin_version" } } plugins { id 'org.jetbrains.kotlin.jvm' version '1.1.51' id 'com.github.johnrengelman.shadow' version '2.0.1' } apply plugin: 'application' apply plugin: 'java' group 'jp.co.youmeee' version '1.2' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" testCompile group: 'junit', name: 'junit', version: '4.12' compile 'org.slf4j:slf4j-api:1.7.25' compile 'org.slf4j:jcl-over-slf4j:1.7.25' compile 'org.slf4j:jul-to-slf4j:1.7.25' compile 'ch.qos.logback:logback-classic:1.2.3' } task packJar(type: Jar) { manifest { attributes 'Main-Class': 'jp.co.youmeee.app.MainKt' } from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } with jar }
build.gradle.kts buildscript { val kotlinVersion = "1.2.10" repositories { mavenCentral()
} dependencies { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin: $kotlinVersion") } } group = "jp.co.youmeee" version = "1.2" plugins { java application `kotlin-dsl` id("org.jetbrains.kotlin.jvm") version "1.1.51" id("com.github.johnrengelman.shadow") version "2.0.1" } java { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } repositories { mavenCentral() } dependencies { val kotlinVersion = "1.2.10" compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion") testCompile(group = "junit", name = "junit", version = "4.12") compile ("org.slf4j:slf4j-api:1.7.25") compile("org.slf4j:jcl-over-slf4j:1.7.25") compile("org.slf4j:jul-to-slf4j:1.7.25") compile("ch.qos.logback:logback-classic:1.2.3") } task("packJar", type = Jar::class) { archiveName = "krs.jar" manifest { attributes["Main-Class"] = "jp.co.youmeee.app.MainKt" } from(configurations.runtime.map({ if (it.isDirectory) it else zipTree(it) })) with(tasks["jar"] as CopySpec) }
全てKotlinで書くことができました!
まとめ、感想 ・Kotlinでもコマンドラインツールは作れる!! ・File系のクラスはAndroid書いてるとあまり触らないし、便利な拡張関数もあって、 勉強になりました。 ・エラーハンドリングとか甘い部分あるので、その辺りfixしていきたい。 ・もう少し汎用的にして、外からオプションで、言語の識別子を与えるようにすれば、 Java→Kotlinのようなこともできる(需要はない) https://github.com/youmitsu/KotlinReplaceSupport er
参考資料 ・Migrating build logic from Groovy to Kotlin https://guides.gradle.org/migrating-build-logic-from-groovy-to-kotlin/ ・JVMベースのコマンドラインツールをHomebrewで配布する
https://int128.hatenablog.com/entry/2015/02/27/220907