Slide 1

Slide 1 text

From Java to Kotlin sitting aft on a web app

Slide 2

Slide 2 text

github.com/ivan-osipov/repository telegram ivan_osipov twitter _osipov_ name Ivan Osipov viber > sudo rm -rf whatsapp > dev/null deprecated i-osipov.ru t.me/from_junior_to_senior from-java-to-kotlin

Slide 3

Slide 3 text

ARRIVAL Robotics a web app to connect mechanical designers and robofacturing collecting real-time feedback software defined robofacturing Kotlin ?: earlier TRA Robotics

Slide 4

Slide 4 text

Agenda 1. Motivation 2. Preparation (checkstyle, autoformatting, test coverage) 3. Java + Lombok vs. Kotlin 4. Java to Kotlin Converter 5. Bugs, rakes and steps to migrate

Slide 5

Slide 5 text

What Δ do you expect?

Slide 6

Slide 6 text

code is shorter more expressive have fun doing the migration less routine coding faster feature creation better code reading language features and stdlib

Slide 7

Slide 7 text

Minuses?

Slide 8

Slide 8 text

Minuses? yes :(

Slide 9

Slide 9 text

lost ternary operator lost a number of ide features structural search, AspectJ highlights nullability noize!! lost implicit widening conversions companion object { noise } third party idiomaticity

Slide 10

Slide 10 text

Current State

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Code Style

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

https://kotlinlang.org/docs/reference/code-style-migration-guide.html 1 Oct. 2018 Kotlin Coding Conventions

Slide 16

Slide 16 text

https://kotlinlang.org/docs/reference/code-style-migration-guide.html 1 Oct. 2018 Kotlin Coding Conventions ● Since Kotlin 1.3 by default for new projects ● For old projects: official pom.xml kotlin.code.style=official gradle.properties

Slide 17

Slide 17 text

Checkstyle

Slide 18

Slide 18 text

https://github.com/arturbosch/detekt https://github.com/pinterest/ktlint

Slide 19

Slide 19 text

Java 8 + Lombok -> Kotlin

Slide 20

Slide 20 text

Equivalents @Getters @Setters properties @NonNull nullability @SneakyThrows only unchecked exceptions @Cleanup .use { … } val/var val/var @*ArgsConstructor primary constructor

Slide 21

Slide 21 text

Equivalents @Getters @Setters properties @NonNull nullability @SneakyThrows only unchecked exceptions @Cleanup .use { … } val/var val/var @*ArgsConstructor primary constructor

Slide 22

Slide 22 text

Equivalents @Getters @Setters properties @NonNull nullability @SneakyThrows only unchecked exceptions @Cleanup .use { … } val/var val/var @*ArgsConstructor primary constructor

Slide 23

Slide 23 text

Equivalents @Getters @Setters properties @NonNull nullability @SneakyThrows only unchecked exceptions @Cleanup .use { … } val/var val/var @*ArgsConstructor primary constructor

Slide 24

Slide 24 text

Equivalents @Getters @Setters properties @NonNull nullability @SneakyThrows only unchecked exceptions @Cleanup .use { … } val/var val/var @*ArgsConstructor primary constructor

Slide 25

Slide 25 text

Equivalents @Getters @Setters properties @NonNull nullability @SneakyThrows only unchecked exceptions @Cleanup .use { … } val/var val/var @*ArgsConstructor primary constructor

Slide 26

Slide 26 text

Complete Manual Implementation @ToString @EqualsAndHashCode @Synchronized @Builder

Slide 27

Slide 27 text

@Data != data class

Slide 28

Slide 28 text

Nullability

Slide 29

Slide 29 text

@Log @Slf4j public class MyService { public void doSmth() { log.info(“my log entry”) } } class MyService { val log by slf4j fun doSmth() { log.info(“my log entry”) } } https://discuss.kotlinlang.org/t/best-practices-for-loggers/226/26

Slide 30

Slide 30 text

@Log val slf4j: ReadOnlyProperty get() = LoggerDelegate() class LoggerDelegate : ReadOnlyProperty { lateinit var logger: Logger override fun getValue(thisRef: Any, property: KProperty<*>): Logger { if (!::logger.isInitialized) logger = LoggerFactory.getLogger(thisRef.javaClass) return logger } } https://discuss.kotlinlang.org/t/best-practices-for-loggers/226/26

Slide 31

Slide 31 text

@Log val slf4j: ReadOnlyProperty get() = LoggerDelegate() class LoggerDelegate : ReadOnlyProperty { lateinit var logger: Logger override fun getValue(thisRef: Any, property: KProperty<*>): Logger { if (!::logger.isInitialized) logger = LoggerFactory.getLogger(thisRef.javaClass) return logger } } https://discuss.kotlinlang.org/t/best-practices-for-loggers/226/26

Slide 32

Slide 32 text

@Log @Slf4j public class MyService { public void doSmth() { log.info(“my log entry”) } } class MyService { val log by slf4j fun doSmth() { log.info(“my log entry”) } }

Slide 33

Slide 33 text

@Log @Slf4j public class MyService { public void doSmth() { log.info(“my log entry”) } } class MyService { companion object { val log by slf4j } fun doSmth() { log.info(“my log entry”) } }

Slide 34

Slide 34 text

@Log @Slf4j public class MyService { public void doSmth() { log.info(“my log entry”) } } class MyService { companion object { val log by slf4j } fun doSmth() { log.info(“my log entry”) } } https://www.reddit.com/r/Kotlin/comments/8gbiul/slf4j_loggers_in_3_ways INFO my.package.MyService$Companion - my log entry

Slide 35

Slide 35 text

@Log val slf4j: ReadOnlyProperty get() = LoggerDelegate() class LoggerDelegate : ReadOnlyProperty { lateinit var logger: Logger override fun getValue(thisRef: Any, property: KProperty<*>): Logger { if (!::logger.isInitialized) { val javaClass = thisRef.javaClass logger = LoggerFactory.getLogger( javaClass ) } return logger } } https://discuss.kotlinlang.org/t/best-practices-for-loggers/226/26

Slide 36

Slide 36 text

@Log val slf4j: ReadOnlyProperty get() = LoggerDelegate() class LoggerDelegate : ReadOnlyProperty { lateinit var logger: Logger override fun getValue(thisRef: Any, property: KProperty<*>): Logger { if (!::logger.isInitialized) { val javaClass = thisRef.javaClass logger = LoggerFactory.getLogger( if (javaClass.kotlin.isCompanion) javaClass.enclosingClass else javaClass ) } return logger } } https://discuss.kotlinlang.org/t/best-practices-for-loggers/226/26

Slide 37

Slide 37 text

Java to Kotlin Converter

Slide 38

Slide 38 text

CTRL + ALT + SHIFT + K

Slide 39

Slide 39 text

System.out.println( Integer.toHexString( 0xFF000000 ) ) FF000000 0 Compile error

Slide 40

Slide 40 text

FF000000 0 Compile error System.out.println( Integer.toHexString( 0xFF000000 ) )

Slide 41

Slide 41 text

println( Integer.toHexString( -0x1000000 ) ) Java to Kotlin Converter

Slide 42

Slide 42 text

println( Integer.toHexString( 0xFF000000 ) ) FF000000 0 Compile error Rewritten

Slide 43

Slide 43 text

FF000000 0 Compile error println( Integer.toHexString( 0xFF000000 ) ) Rewritten

Slide 44

Slide 44 text

FF000000 0 Compile error println( Integer.toHexString( 0xFF000000 ) ) Rewritten Long https://discuss.kotlinlang.org/t/when-does-bit-fiddling-come-to-kotlin/2249

Slide 45

Slide 45 text

FF000000 0 Compile error println( Integer.toHexString( 0xFF000000.toInt() ) ) Rewritten workaround

Slide 46

Slide 46 text

FF000000 0 Compile error println( Integer.toHexString( 0xFF000000u.toInt() ) ) Rewritten experimental workaround

Slide 47

Slide 47 text

FF000000 0 Compile error println( Integer.toHexString( 0xFF000000u ) ) Rewritten a future solution? https://discuss.kotlinlang.org/t/when-does-bit-fiddling-come-to-kotlin/2249

Slide 48

Slide 48 text

Before we start

Slide 49

Slide 49 text

No tests - No migrations at least cover your core functionality

Slide 50

Slide 50 text

Keep semantics

Slide 51

Slide 51 text

Let’s do it

Slide 52

Slide 52 text

Gradle Plugins plugins { ... id 'org.jetbrains.kotlin.jvm' version "1.3.50" id "org.jetbrains.kotlin.plugin.spring" version "1.3.50" id "org.jetbrains.kotlin.plugin.allopen" version "1.3.50" }

Slide 53

Slide 53 text

No Code - No Problems

Slide 54

Slide 54 text

Repository let’s do that

Slide 55

Slide 55 text

@JvmDefault

Slide 56

Slide 56 text

compileKotlin { kotlinOptions { freeCompilerArgs = ["-Xjvm-default=compatibility"] jvmTarget = "1.8" } } https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-default/index.html

Slide 57

Slide 57 text

First migrations as small as possible but not smaller than a class the 1st avice

Slide 58

Slide 58 text

Constants let’s do that

Slide 59

Slide 59 text

@JvmField const val @file:JvmName(“...”) object … { ... }

Slide 60

Slide 60 text

Keep backward compatibility even inside your team the 2nd advice

Slide 61

Slide 61 text

Configs & Props let’s do that

Slide 62

Slide 62 text

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html #boot-features-kotlin-configuration-properties @ConfigurationProperties when used in combination with @ConstructorBinding supports classes with immutable val properties since 2.2.0

Slide 63

Slide 63 text

First of all check docs docs of many libs/tools have a chapter called “Kotlin” the 3rd advice

Slide 64

Slide 64 text

Aspects let’s do that

Slide 65

Slide 65 text

The Converter Is Software can have bugs the 4rd advice

Slide 66

Slide 66 text

Model let’s do that

Slide 67

Slide 67 text

DTO & mappers let’s do that

Slide 68

Slide 68 text

Check compatibility of your libs with Kotlin before migration! the 5th advice

Slide 69

Slide 69 text

Be strong. Someday it will end probably not this month the 6th advice

Slide 70

Slide 70 text

Services let’s do that

Slide 71

Slide 71 text

Improve your code if changes are small but profit is great the 7rd advice

Slide 72

Slide 72 text

Controllers let’s do that

Slide 73

Slide 73 text

Check auto-generated* stuff manually if you are too lazy to write tests for it the 8th advice * not only, but at least

Slide 74

Slide 74 text

Global Steps 1. What Δ do you expect? 2. Code Style / Checkstyle 3. Migrate 4. Review

Slide 75

Slide 75 text

Global Steps 1. What Δ do you expect? 2. Code Style / Checkstyle 3. Migrate 4. Review

Slide 76

Slide 76 text

Migration Steps 1. Repositories 2. Constants 3. Config & Props 4. Delombok everything (at least one sub domain) 5. From the most abstract entity classes downwardly 6. Subdomains: Model + DTO + Mappers 7. Services & Another Domain Logic 8. Controllers

Slide 77

Slide 77 text

Go in small steps if you really ready to solve problems the final avice

Slide 78

Slide 78 text

github.com/ivan-osipov/repository telegram ivan_osipov twitter _osipov_ name Ivan Osipov viber > sudo rm -rf whatsapp > dev/null deprecated i-osipov.ru t.me/from_junior_to_senior from-java-to-kotlin