[JAVA] You can eliminate @Param with Kotlin 1.1 and MyBatis 3.4.1+! !!

I thought that "Customizer for Platform Transaction Manager will be added from Spring Boot 1.5" posted yesterday was written this year ... : sweat_smile: I've found what I want to write, so I'm really posting the last post of the year: wink:

As a story ... Kotlin 1.1 and MyBatis 3.4.1+ scheduled to be released in 2017 1Q (January to March) (when compiled using the -parameters option added from Java SE 8, the argument name of the Mapper method is bound. If you combine it with the version that becomes the variable name), you don't need to use @ Param.

Note:

2017/03/02 Kotlin 1.1 has been officially released, so we've made a complete fix to the release base! !! (The content is basically the same)

What about Kotlin 1.0?

For Kotlin 1.0.x ...

@Select("""
    SELECT
        id, title, details, finished
    FROM
        todo
    WHERE
        id = #{id}
    AND
        finished = #{finished}
""")
fun select(@Param("id") id: Int, @Param("finished") finished: Boolean = false): Todo

I had to specify @ Param. If you don't specify @ Param, the bind variable name will be assigned mechanically using the order of the arguments, like pram1 or param2. (I don't like the order ...)

From Kotlin 1.1?

If you specify -java-parameters (equivalent to the -parameters option added from Java SE 8) as a compile option in Kotlin 1.1 ...

@Select("""
    SELECT
        id, title, details, finished
    FROM
        todo
    WHERE
        id = #{id}
    AND
        finished = #{finished}
""")
fun select(id: Int, finished: Boolean = false): Todo // @Param can be omitted! !!

With that feeling, you can omit the specification of @ Param: laughing:

Note:

It is supported at https://youtrack.jetbrains.com/issue/KT-8816 and released in Kotlin 1.1-M3.

Let's actually use Kotlin 1.1! !!

Seeing is believing ... So let's actually check it using Kotlin 1.1 and MyBatis 3.4.1+. In this post, I will explain based on the previously posted "Use mybatis-spring-boot-starter with Kotlin".

Operation verification version

Let's fix the source

First, fix TodoMapper as follows. The point is to have multiple arguments for the Mapper method (because there are no particular restrictions on the bind variable name if there is only one argument, it will work no matter what you specify).

src/main/kotlin/com/example/mapper/TodoMapper.kt


@Mapper
interface TodoMapper {

    @Insert("""
        INSERT INTO todo
            (title, details, finished)
        VALUES
            (#{title}, #{details}, #{finished})
    """)
    @Options(useGeneratedKeys = true)
    fun insert(todo: Todo)

    @Select("""
        SELECT
            id, title, details, finished
        FROM
            todo
        WHERE
            id = #{id}
+        AND
+            finished = #{finished}
    """)
-    fun select(id: Int): Todo
+    fun select(id: Int, finished: Boolean = false): Todo

}

Next, let's fix the caller of the Mapper method.

src/main/kotlin/com/example/MybatisKotlinDemoApplication.kt


@SpringBootApplication
open class MybatisKotlinDemoApplication : CommandLineRunner {

    @Autowired
    lateinit var todoMapper: TodoMapper

    @Transactional
    override fun run(vararg args: String?) {
        val newTodo: Todo = Todo()
        newTodo.title = "drinking party"
        newTodo.details = "Ginza 19:00"

        todoMapper.insert(newTodo) //Insert a new Todo

-        val loadedTodo: Todo = todoMapper.select(newTodo.id)
+        val loadedTodo: Todo = todoMapper.select(id = newTodo.id) //Only id is specified, the default value false is used for finished
        println("ID       : " + loadedTodo.id)
        println("TITLE    : " + loadedTodo.title)
        println("DETAILS  : " + loadedTodo.details)
        println("FINISHED : " + loadedTodo.finished)
    }

}

fun main(args: Array<String>) {
    SpringApplication.run(MybatisKotlinDemoApplication::class.java, *args)
}

Try it ... Let's try using the Maven command to see what happens when it is executed in this state.

$ ./mvnw clean spring-boot:run

The following stack Torres is displayed, and I get an error saying that the bind variable named ʻid` cannot be found.

...
        ... 12 more
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [0, 1, param1, param2]
        at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:186)
...

Execution on Maven command

First, let's fix the POM file as follows.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>mybatis-kotlin-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>mybatis-kotlin-demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
-        <version>1.4.1.RELEASE</version>
+        <version>1.5.1.RELEASE</version> <!--Modified to use the latest at the time of posting update (correction is optional)-->
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
-        <kotlin.version>1.0.3</kotlin.version>
+        <kotlin.version>1.1.0</kotlin.version> <!-- 1.Fixed to use the latest of 1-->
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>${kotlin.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
-            <version>1.1.1</version>
+            <version>1.2.0</version> <!-- 1.2.By setting it to 0, MyBatis 3.4.2 is transitively added to dependent artifacts-->
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>

    </dependencies>

    <build>
        <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
        <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <artifactId>kotlin-maven-plugin</artifactId>
                <groupId>org.jetbrains.kotlin</groupId>
                <version>${kotlin.version}</version>
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
+                <configuration>
+                    <args>
+                        <arg>-java-parameters</arg> <!-- Kotlin 1.Supported by 1-java-Specify parameters option-->
+                    </args>
+                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

If you execute the Maven command again after modifying the POM file ...

$ ./mvnw clean spring-boot:run

Now works fine: laughing:

...
2017-03-02 22:00:55.855  INFO 85743 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
ID       : 1
TITLE    :drinking party
DETAILS  :Ginza 19:00
FINISHED : false
2017-03-02 22:00:55.932  INFO 85743 --- [           main] c.e.MybatisKotlinDemoApplicationKt       : Started MybatisKotlinDemoApplicationKt in 1.84 seconds (JVM running for 9.21)
...

Note:

By the way ... If you compile without specifying the -java-parameters option ... the argument name will be something like ʻarg0 or ʻarg1, and that value will be used as the bind variable name. The following error will occur.

...
       ... 12 more
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]
       at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:195)
...

Running on IntelliJ IDEA

I was able to confirm that it works using the Maven command, but ... During development, it is common to execute it using the functions of the IDE. In this post, we will configure Kotlin 1.1 to be used on IntelliJ IDEA provided by JetBrains, the developer of Kotlin, and execute the modified program. (It seems that Eclipse Plugin is also available, but I will not handle it this time)

First ... Update to Kotlin 1.1 support Plugin. Select "Tools-> Kotlin-> Configure Kotlin Plugin Updates" from the window menu, select "Stable", click the "Check for updates now" button, and if there is an update target, click the "Install" button to install the plugin. Please update.

Next, set the Kotlin language version and compile options used in the project. After selecting "Preferences-> Build, Execution, Deployment-> Compiler-> Kotlin Compiler from the window menu"

Then click the "OK" button.

kotlin11-compiler-settings.png

After changing the settings, be sure to select ** "Build-> Rebuild Project" from the window menu and rebuild (compile) with the changed settings. (If you forget this, it may not work as expected ...)

Finally ... If you select MybatisKotlinDemoApplication on the IDE and run the program, it will work fine: laughing:

...
2017-03-02 22:37:28.315  INFO 86040 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
ID       : 1
TITLE    :drinking party
DETAILS  :Ginza 19:00
FINISHED : false
2017-03-02 22:37:28.390  INFO 86040 --- [           main] c.e.MybatisKotlinDemoApplicationKt       : Started MybatisKotlinDemoApplicationKt in 2.282 seconds (JVM running for 2.677)
...

Summary

Even if I can't completely migrate from Java to Kotlin, I personally think that the option of using Kotlin, which only supports multi-line strings in the Mapper interface, is quite "ant". I thought it was a pity that the actual argument name could not be handled as a bind variable name in Kotlin 1.0, but since it will be possible to handle it perfectly from Kotlin 1.1, MyBatis is annotated (specify SQL with annotation) I think it's worth a try if you're using it in).

For the compilation method using kotlin-maven-plugin when Java and Kotlin coexist, Kotlin reference page .html # compiling-kotlin-and-java-sources).

Recommended Posts

You can eliminate @Param with Kotlin 1.1 and MyBatis 3.4.1+! !!
Hello world with Kotlin and JavaFX
Hello world with Kotlin and Tornado FX
[Good news] You can still go with Java 8 !!
With Tomcat you can use placeholders ($ {...}) in web.xml
Periodically update DB with Spring Batch and MyBatis
Compiled kotlin with cli with docker and created an environment that can be executed with java
You can do it with copy! Aspect-oriented programming (Android)
If you want to use Mockito with Kotlin, use mockito-kotlin
I want to transition screens with kotlin and java!
How to install Gradle and Kotlin with SDKMAN (Mac)