Migrate from Java to Server Side Kotlin + Spring-boot

With Google's adoption as the official language for Android, the Kotlin commune is expanding. Meanwhile, I moved from Java, which is adopted as Server Side Language, to Server Side Kotlin.

Advantages and disadvantages of adopting Kotlin: baby_chick:

Here are some of the benefits of migrating to Kotlin. It is a light introduction because it is a language specification of the part that is often talked about.

merit

Demerit

--The Server Side Kotlin ecosystem is weak at this stage

Kotlin does not allow nulls to be assigned to variables of type non-Optional. It's very safe because the compiler guarantees it's not null. Also, if it is Optional, a check is required when retrieving the value.

fun main(vararg args: String) {
    val user: User? = null
    println(user?.fullName ?: "unknown")
}

data class User(val familyName: String, val firstName: String) {
    val fullName: String
    	get() = "${this.familyName} ${this.firstName}"
}

Kotlin has a when expression similar to Scala's match. It corresponds to a switch in Java, but the difference is that it returns a value and guarantees the completeness of the enumeration.

fun method(license: License) {
    val service = license.createService()
}

enum class License {
    FREE,
    ENETERPRISE;
    
    fun createService(): Service {
        return when (this) {
            FREE -> FreeService()
            ENETERPRISE -> EnterpriseService()
        }
    }
}

interface Service { ... }
class FreeService: Service { ... }
class EnterpriseService: Service { ... }

This (License) is passed in the when expression. We know that the License is FREE or ENTERPRISE, so we don't have to write default (or else in kotlin) processing in the when expression. Also, ** If there is an omission in the enumeration pattern, a compile error will occur, so completeness can be guaranteed *. ( There are some restrictions)

・ ・ ・

The system takes a long time to scale and take over. Kotlin comes with a valid language specification to carry them out safely. I think it's a noteworthy feature to adopt Kotlin, as the features mentioned in the benefits provide stronger support than Java.

As an aside, since the existing system was built with Spring-boot + Mavan, being able to use it as it is was also a major factor in the transition because the learning cost was significantly reduced.

Problems with adopting Server Side Kotlin + Spring-boot: feet:

Even with the benefits, there were some stumbling blocks in actual development. I would like to introduce some of them.

Can't find the static run method for SpringApplication

In Java, it is SpringApplication described as follows, but it did not work if it was generated by Spring Initializr and used.

@EnableAutoConfiguration
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

Kotlin's static is implemented via Companion (as well as Scala), so write: Also, add the JvmStatic annotation so that it can be called from Java.

@SpringBootApplication
@EnableAutoConfiguration
class MyApplication {
    companion object {
        @JvmStatic fun main(vararg args: String) {
            SpringApplication.run(MyApplication::class.java, *args)
        }
    }
}

Mockito's any or anyObject throws an exception

Mockito's any / anyObject is implemented internally to return null. When I try to use this in Kotlin, I get an IllegalStateException exception ** when passed to a non-null argument **.

As a solution, it seems that it is possible to bypass the null check by using Kotlin's Generics. You can use the following Helper class.

class MockitoHelper {
    companion object {
        fun <T> any(): T {
            return Mockito.any() ?: null as T
        }
    }

    fun <T> eq(value: T): T {
        return if (value != null) Mockito.eq(value)
               else null ?: null as T
    }
}

I referred to the article here. Thank you: bow: *** Please take into account that this solution may no longer be available **.

Can't find Primary Constructor for data class with RequestBody annotation

Even if I just dropped the Java code as usual into Kotlin, Json couldn't map it to the DataClassResource and threw an exception.

data class DataClassResource(val key: String, val value: String)

@RestController
@Component
class DataClassController {
  
    @ResponseStatus(HttpStatus.OK)
    @RequestMapping(value = "/update", method = arrayOf(PUT), produces = arrayOf(APPLICATION_JSON_VALUE))
    fun update(@RequestBody resource: DataClassResource) {
        ...
    }
}

I call the constructor of a class with the RequestBody annotation to initialize it, but I can't seem to find the primary Kotlin constructor.

This issue can be resolved by adding a Kotlin-enabled version of the Jackson module as a dependency. Let's add the following package as a dependency.

<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-kotlin</artifactId>
    <version>2.8.0</version>
</dependency>

Tips :cookie:

Java classes cannot be extended because the static method Extension can only be a class with a Companion Object

When extending static methods in Kotlin, implement them through Companion. However, Java classes do not have Companion Objects, so they cannot implement extension functions or properties such as:

fun JavaClass.Companion.extensionMethod() {
    ...
}

There is also an Issue on YouTrack. I want you to implement it. https://youtrack.jetbrains.com/issue/KT-11968

Java methods that may be null are supported by Optional

Java methods can be null even if they are not Optional. If you want to ensure security in the Kotlin area, it seems better to receive the result of Java method as Optional.

val maybe: String? = javaClass.method()

Bean Injection defined as val

When defining the property to be injected with the Autowired annotation, if you define it normally, a compile error will occur due to uninitialization, so define it with lateinit for delayed initialization.

@Component("sample")
class Sample {
    @Autowired
    private lateinit var dependency: Dependency
}

However, lateinit can only be defined with var. If you want to define with val, use Primary Constructor.

@Component("sample")
class Sample @Autowired constructor(private val dependency: Dependency) {
}

I want to define properties that do not change with Immutable as much as possible.

At the end

We were able to proceed with development with stable velocity, despite some stumbling blocks. It's more secure at the compiler level, and your code has better visibility. I think that the power of that support will be demonstrated when scaling in the future. There is also a description peculiar to Kotlin, so it would be good to proceed while exploring in the review what kind of policy to go! However, I felt that the threshold for migrating from Java to Kotlin and the cost of learning were low again. I want Server Side Kotlin to get more and more exciting: tada:

Recommended Posts

Migrate from Java to Server Side Kotlin + Spring-boot
Memo for migration from java to kotlin
Changes from Java 8 to Java 11
Sum from Java_1 to 100
Migrate from JUnit 4 to JUnit 5
[Java] How to retrieve the parameters passed from html on the server side
Verify the ID token obtained from Firebase on the server side (Java + SpringBoot)
From Java to Ruby !!
Minecraft BE server development from PHP to Java
Migration from Cobol to JAVA
New features from Java7 to Java8
Connect from Java to PostgreSQL
From Ineffective Java to Effective Java
How to migrate from JUnit4 to JUnit5
Whether to make the server side at the time of system rebuild with Kotlin or Java
Stop resending from client to server
Kotlin Class to send to Java developers
Migrate Docker image to another server
Migrate from on-premise Pukiwiki to esa.io \ (⁰⊖⁰) /
Java to be involved from today
From Java to VB.NET-Writing Contrast Memo-
Java, interface to start from beginner
The road from JavaScript to Java
[Android] Convert Android Java code to Kotlin
[Java] Conversion from array to List
Notes on building Kotlin development environment and migrating from Java to Kotlin
What I thought about when I started migrating from Java to Kotlin
Kotlin Class part.2 to send to Java developers
[Kotlin] 3 ways to get Class from KClass
Convert all Android apps (Java) to Kotlin
Kick ShellScript on the server from Java
Convert from java UTC time to JST time
Connect from Java to MySQL using Eclipse
From installing Eclipse to executing Java (PHP)
Kotlin scope functions to send to Java developers
Post to Slack from Play Framework 2.8 (Java)
Java: How to send values from Servlet to Servlet
[Java] Flow from source code to execution
Get history from Zabbix server in Java
Introduction to monitoring from Java Touching Prometheus
Precautions when migrating from VB6.0 to JAVA
Let's migrate to make Java more comfortable
Type conversion from java BigDecimal type to String type
Summary of points I was worried about when migrating from java to kotlin
[Java] From two Lists to one array list
Kotlin functions and lambdas to send to Java developers
Migrate Ubuntu 18.04 LTS from HDD to smaller SSD
Run R from Java I want to run rJava
Introduce Kotlin to your existing Java Maven Project
Connect to Aurora (MySQL) from a Java application
To become a VB.net programmer from a Java shop
How to get Class from Element in Java
Initial settings for rewriting Java projects to Kotlin
Migrating from Eclipse server function (Tomcat) to Embed Tomcat
Getting started with Kotlin to send to Java developers
[Java] How to switch from open jdk to oracle jdk
Migrate from Transport Client to Rest High Level Client
What I did when I converted java to Kotlin
For Java engineers starting Kotlin from now on
I want to write quickly from java to sqlite
Where Java programmers tend to trip over Kotlin