A story about a Spring Boot project written in Java that supports Kotlin

background

The engineers of the NOREL team are modernizing the technology used, and there was a talk that "I want to write a system written in Java / Spring Boot in Kotlin anyway", so I will proceed with correspondence so that it can be developed in Kotlin. I am.

I often see articles such as starting with Kotlin (Gradle) from the beginning, but I could not find many articles that correspond to Kotlin (Maven) while it was written in Java, so I tried to deal with it.

Existing environment

Basically, Spring Boot implements only REST API.

Policy to support Kotlin

--Since development in Java is progressing in parallel, converting all code from Java to Kotlin will be postponed this time. --Controller / Service can be written in Kotlin --Leave the data access layer such as JPA as Java ――I want to make everything Kotlin in the end

Also, this work was done on IntelliJ.

Migration work

pom.xml settings

--For the pom.xml settings, I referred to the following Kotlin official website.

--Definition of Kotlin version

pom.xml


  <properties>
...
     <java.version>1.8</java.version>
+    <kotlin.version>1.2.10</kotlin.version>
+    <kotlin.compiler.incremental>true</kotlin.compiler.incremental>
  </properties>

--Added Kotlin dependency library

pom.xml


  <dependencies>
・ ・ ・
+    <dependency>
+      <groupId>org.jetbrains.kotlin</groupId>
+      <artifactId>kotlin-stdlib</artifactId>
+      <version>${kotlin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jetbrains.kotlin</groupId>
+      <artifactId>kotlin-reflect</artifactId>
+      <version>${kotlin.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jetbrains.kotlin</groupId>
+      <artifactId>kotlin-test</artifactId>
+      <version>${kotlin.version}</version>
+      <scope>test</scope>
+    </dependency>
  </dependencies>

--Build settings

Originally I didn't use maven-compiler-plugin, but each package is ready for development in both Java and Kotlin.

I'm using maven-compiler-plugin to separate by.

In addition, spring is defined as compilerPlugins so that various annotations used in Spring can be used. As mentioned in the documentation, defining a spring plugin seems to eliminate the need to define all-open.

pom.xml


  <build>
     <finalName>${project.name}</finalName>
-    <sourceDirectory>src/main/java</sourceDirectory>
-    <testSourceDirectory>src/test/java</testSourceDirectory>
    <resources>
      <resource>
        <directory>${resources.directory}</directory>
      </resource>
      <resource>
        <directory>src/main/resources</directory>
      </resource>
     </resources>
     <testResources>
       <testResource>
         <directory>src/test/resources</directory>
       </testResource>
     </testResources>
     <plugins>
       <plugin>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-maven-plugin</artifactId>
         <configuration>
           <executable>true</executable>
         </configuration>
       </plugin>
+      <plugin>
+        <artifactId>kotlin-maven-plugin</artifactId>
+        <groupId>org.jetbrains.kotlin</groupId>
+        <version>${kotlin.version}</version>
+        <configuration>
+          <compilerPlugins>
+            <plugin>spring</plugin>
+          </compilerPlugins>
+        </configuration>
+        <executions>
+          <execution>
+            <id>compile</id>
+            <goals> <goal>compile</goal> </goals>
+            <configuration>
+              <sourceDirs>
+                <sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
+                <sourceDir>${project.basedir}/src/main/java</sourceDir>
+              </sourceDirs>
+            </configuration>
+          </execution>
+          <execution>
+            <id>test-compile</id>
+            <goals> <goal>test-compile</goal> </goals>
+            <configuration>
+              <sourceDirs>
+                <sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
+                <sourceDir>${project.basedir}/src/test/java</sourceDir>
+              </sourceDirs>
+            </configuration>
+          </execution>
+        </executions>
+        <dependencies>
+          <dependency>
+            <groupId>org.jetbrains.kotlin</groupId>
+            <artifactId>kotlin-maven-allopen</artifactId>
+            <version>${kotlin.version}</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.5.1</version>
+        <executions>
+          <!-- Replacing default-compile as it is treated specially by maven -->
+          <execution>
+            <id>default-compile</id>
+            <phase>none</phase>
+          </execution>
+          <!-- Replacing default-testCompile as it is treated specially by maven -->
+          <execution>
+            <id>default-testCompile</id>
+            <phase>none</phase>
+          </execution>
+          <execution>
+            <id>java-compile</id>
+            <phase>compile</phase>
+            <goals> <goal>compile</goal> </goals>
+          </execution>
+          <execution>
+            <id>java-test-compile</id>
+            <phase>test-compile</phase>
+            <goals> <goal>testCompile</goal> </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
  </build>

Now you are ready to write Kotlin on IntelliJ.

Support for STS (Eclipse)

When I asked the members who usually use STS to check the correspondence so far, it did not work well and I was a little addicted to it, so I will also describe how to deal with STS.

--Install the Kotlin Plugin for Eclipse from the Eclipse marketplace.

--Since src / main / kotlin is not recognized as a build path, check the kotlin folder with Add File from Source of Projects> Properties> Java Build Path. Same for src / test / kotlin

buildPath.png

--Right-click on the project and run Configure Kotlin> Add Kotlin Nature

In the figure below, you can not select it because it has already been added Kotlin Nature, but you can select it before execution.

AddKotlinNature.png

Now it compiles on STS and you can develop on Kotlin.

Write Kotlin

Convert from Java code to Kotlin code

Since the conversion function of IntelliJ is excellent, I basically converted it with IntelliJ. It's scary to put them all together at once, so I converted one code or several codes at a time.

Select the code you want to convert and convert it to Kotlin code with Code> Convert Java File to Kotlin File.

ConvertToKotlin.png

Also, since the package is still under src / main / java, move it under the same package under src / main / kotlin. This is also nicely refactored with Refactor> Move ... in IntelliJ.

DI (Autowired etc.)

For example, the code below

@Service
public class HogeService {
    @Autowired
    private HogeRepository hogeRepository;
}

In Kotlin, you can also declare it with lateinit, but this time I defined it with constructor injection.

@Service
class HogeService(
    private val hogeRepository: HogeRepository
) {
}

Around Lombok

When using Lombok, I sometimes got a compile error when converting to Kotlin.

Basically, the class that converts to Kotlin and the class that is referenced from Kotlin are solved by Delombok.

Use the IntelliJ lombok plugin. It will remove the Lombok conversion from Refactor> Delombok.

Delombok.png

--Slf4j annotation

You can omit the logger declaration and write code that outputs logs suddenly. If you use Kotlin, the following code cannot resolve the log variable and a compile error will occur.

@Service
@Slf4j
public class HogeService {
    public void hoge() {
        log.info("hoge");
    }
}

In kotlin, it can be used by initializing the logger with companion object.

@Service
class HogeService {
    companion object {
        private val log = LoggerFactory.getLogger(HogeService::class.java)
    }
}

Some people have tried the DI method with annotations, so I would like to consider making it easier. http://saiya-moebius.hatenablog.com/entry/2017/11/08/033932

--Data annotation

I read the following Lombokized Java code from Kotlin, and when I try to get the hoge, it says that it is private and not accessible. In this case, as described above, it was converted to Delombok. (If everything becomes Kotlin, you don't have to use Lombok in the first place ...)

@Entity
@Data
@EqualsAndHashCode(callSuper = false)
@ToString(callSuper = true)
public class Hoge extends AbstractEntity {
	@Column(name = "hoge")
	private String hoge;
}

About the future

At this point, some code is now Kotlinized and works. However, I've had problems several times while I was actually writing the code, so it's possible that I'll continue to have problems. I think that I should add more and more how to deal with it.

Recommended Posts

A story about a Spring Boot project written in Java that supports Kotlin
Java tips-Create a Spring Boot project in Gradle
Create Java Spring Boot project in IntelliJ
A story about the JDK in the Java 11 era
Run a Spring Boot project in VS Code
How to create a Spring Boot project in IntelliJ
A story about BeanNotOfRequiredTypeException occurring after applying AOP in Spring
A memo that touched Spring Boot
Compare Hello, world! In Spring Boot with Java, Kotlin and Groovy
About returning a reference in a Java Getter
Launch (old) Spring Boot project in IntelliJ
About Spring Dependency Injection using Java, Kotlin
[Creating] A memorandum about coding in Java
Create a Spring Boot project in intellij and exit immediately after launching
Autowired fields in a class that inherits TextWebSocketHandler in Spring Boot become NULL
Automatically deploy a web application developed in Java using Jenkins [Spring Boot application]
A story about an arithmetic overflow that you shouldn't encounter in Ruby
A story about Java 11 support for Web services
A story about making a Builder that inherits the Builder
A story about trying to operate JAVA File
How to add a classpath in Spring Boot
A bat file that uses Java in windows
Check with Java / Kotlin that files cannot be written in UAC on Windows
View the Gradle task in the Spring Boot project
The story that the port can no longer be used in the Spring boot sample program
Until you create a Spring Boot project in Intellij and push it to Github
A story that stumbled when deploying a web application created with Spring Boot to EC2
Write a class that can be ordered in Java
A small story that is sometimes useful in Maven
Write a class in Kotlin and call it in Java
[Spring Boot] How to create a project (for beginners)
Try gRPC in Spring Boot & Spring Cloud project (Mac OS)
A story about developing ROS called rosjava with java
Call a program written in Swift from Processing (Java)
The story that .java is also built in Unity 2018
A library that realizes multi-line strings in Java multiline-string
Learn about the spec while shortening FizzBuzz written in Java
[Java / Kotlin] Escape (sanitize) HTML5 support with unbescape [Spring Boot]
Accelerate testing of Validators that require DI in Spring Boot
A story packed with the basics of Spring Boot (solved)
Sample web application that handles multiple databases in Spring Boot 1.5
How to call and use API in Java (Spring Boot)
[Java] A story about IntelliJ IDEA teaching Map's putIfAbsent method
A story about making Spring + Hibernate + MySQL apps replication compatible
[MQTT / Java] Implemented a class that does MQTT Pub / Sub in Java
Introducing Spring Boot2, a Java framework for web development (for beginners)
A story about misunderstanding how to use java scanner (memo)
[Java] Sample project for developing web applications with Spring Boot
A story that made me regret when a "NotReadablePropertyException" occurred during the development of the Spring Boot application.
With [AWS] CodeStar, you can build a Spring (Java) project running on Lambda in just 3 minutes! !!
I created a Selenium sample app that supports multiple browsers (Chrome, IE, Firefox) that runs in Java.
A note about Java GC
Set context-param in Spring Boot
Spring Boot 2 multi-project in Gradle
[Java] Thymeleaf Basic (Spring Boot)
Find a subset in Java
[Java] Get KClass in Java [Kotlin]
CICS-Run Java application-(4) Spring Boot application
Major changes in Spring Boot 1.5
NoHttpResponseException in Spring Boot + WireMock
[Java] [Spring] Spring Boot 1.4-> 1.2 Downgrade Note