JavaからKotlinへ.再び


本稿では、JavaからKotlinへの小さなマイクロサービスの移行中に遭遇した問題点と解決策について考察する.

スタック

  • ジャバ11
  • スプリングウエブMVC
  • バネデータJPA
  • マップ構造
  • ロンボク
  • マヴェン
  • 始まり


    まず最初に、テストから始めるためにあなたのプロジェクトにKotlinを置きたいと思う誰でも推薦します.このプロセスの間、我々はあなたが必要とするほとんどすべてを構成します.次の手順を実行します.
  • プロジェクトの構成
  • 必要なライブラリを追加する
  • 多くのエラーをキャッチ
  • そして最後に、テストの一部を移行する.
  • 同時に、ビジネスロジックを担当する主なコードは影響を受けません.

    琴を加える


    マヴェン


    いつものようにhttps://start.spring.io/
    2 pomを比較しましょう.XML - Javaと1のための1つ.
  • コルトバージョン
  • <properties>
     ....
      <kotlin.version>1.5.31</kotlin.version>
    </properties>
    
    
  • Kotlinとジャクソンのために標準ライブラリを加えてください
  • <dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-module-kotlin</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-reflect</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib-jdk8</artifactId>
    </dependency>
    
  • ビルドセクションの追加
  •     <build>
            <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
            <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
            <plugins>
              .....
                <plugin>
                    <groupId>org.jetbrains.kotlin</groupId>
                    <artifactId>kotlin-maven-plugin</artifactId>
                    <configuration>
                        <args>
                            <arg>-Xjsr305=strict</arg>
                        </args>
                        <compilerPlugins>
                            <plugin>spring</plugin>
                            <plugin>jpa</plugin>
                        </compilerPlugins>
                    </configuration>
                    <dependencies>
                        <dependency>
                            <groupId>org.jetbrains.kotlin</groupId>
                            <artifactId>kotlin-maven-allopen</artifactId>
                            <version>${kotlin.version}</version>
                        </dependency>
                        <dependency>
                            <groupId>org.jetbrains.kotlin</groupId>
                            <artifactId>kotlin-maven-noarg</artifactId>
                            <version>${kotlin.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>
            </plugins>
        </build>
    
    詳細情報kotlin-maven-plugin あなたは見つけることができますhere
    しかし、この設定は、JavaをKotlinで使用する場合は適切ではありません.この場合、Mavenコンパイラプラグインを設定する必要がありますdocumentation )
    <build>
      <plugins>
        .....
        <plugin>
          <groupId>org.jetbrains.kotlin</groupId>
          <artifactId>kotlin-maven-plugin</artifactId>
          <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>
          <configuration>
            <args>
              <arg>-Xjsr305=strict</arg>
            </args>
            <compilerPlugins>
              <plugin>spring</plugin>
              <plugin>jpa</plugin>
            </compilerPlugins>
          </configuration>
          <dependencies>
            <dependency>
              <groupId>org.jetbrains.kotlin</groupId>
              <artifactId>kotlin-maven-allopen</artifactId>
              <version>${kotlin.version}</version>
            </dependency>
            <dependency>
              <groupId>org.jetbrains.kotlin</groupId>
              <artifactId>kotlin-maven-noarg</artifactId>
              <version>${kotlin.version}</version>
            </dependency>
          </dependencies>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <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>
    
    プラグインに関する情報All-open and No-arg 下記を見つけることができます.

    コリンプラグイン


    古林用途compiler plugins コンパイル中にASTツリーを変更するにはデフォルトでは、スプリング初期化子は2つのプラグインを追加します.all-open and no-arg . また、Kaptとロンボクのプラグインが人気です.

    全開


    デフォルトでは、Kotlin内のすべてのクラスが最終的であり、それらは上書きできません.したがって、Springはプロキシクラスを作成するためにそれらを使用することができません.All-open プラグインを追加open を指定します.
    春にはあらかじめ設定されているkotlin-spring プラグイン.
    これらの注釈だけで動作します.
  • @コンポーネント
  • @非同期
  • @トランザクション
  • @キャッシュ可能
  • @スプリングブータス
  • カスタム注釈を使用する場合は、構成する必要がありますkotlin-allopen .
    また、JPAの注釈がなく、JPAリポジトリを使用する場合は、それらを追加する必要があります.

    いいえ


    このプラグインは、各クラスに空のコンストラクターを追加します.JPAについてはkotlin-jpa . 注釈付きで動作します.
  • @エンティティ
  • @埋込み可能
  • @MappedSuperクラス
  • しかし、それは追加しませんopen これらのクラスに.

    神戸工大


    注釈プロセッサ用のアダプタです(documentation ). これは、例えば、MapStrootによって、KotlinでMappersのためにコードを生成するのに用いられます.
    例: Kaptプラグインの追加方法
    <plugin>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-maven-plugin</artifactId>
      <version>${kotlin.version}</version>
      <executions>
        <execution>
            <id>kapt</id>
            <goals>
                <goal>kapt</goal>
            </goals>
            <configuration>
                <sourceDirs>
                    <sourceDir>src/main/kotlin</sourceDir>
                    <sourceDir>src/main/java</sourceDir>
                </sourceDirs>
                <annotationProcessorPaths>
                    <annotationProcessorPath>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${mapstruct.version}</version>
                    </annotationProcessorPath>
                </annotationProcessorPaths>
            </configuration>
        </execution>
      ...
      </executions>
      ....
    </plugin>
    
    私の経験では、プラグインがLoboBokメソッドを使用するJavaファイルを解析できないので、このプラグインはあなたのビルドを中断することができます.

    ロンボクプラグイン


    このプラグインはこの問題に対処するために使用されますが、まだベータ版のみをサポートしていません@Builder

    コックスプリング


    春は素晴らしいフレームワークであり、もちろん、それはサポートしています
    琴林.しかし、いくつかの興味深い機能があります.
    いくつかのプレゼンテーション
  • from Jetbrains

  • 特徴:

  • 主な公称
  • @SpringBootApplication
    class DemoKotlinApplication
    
    fun main(args: Array<String>) {
        runApplication<DemoKotlinApplication>(*args)
    }
    
  • Kotlinのいくつかの新しい拡張方法が追加されましたRestOperationsExtensions.kt
  • 使用することをお勧めしますval コンストラクタとの引数
  • @Component
    class YourBean(
      private val mongoTemplate: MongoTemplate, 
      private val solrClient: SolrClient
    )
    
    しかし、いくつかの他のオプションがありますlatenin :
    @Component
    class YourBean {
    
        @Autowired
        lateinit var mongoTemplate: MongoTemplate
    
        @Autowired
        lateinit var solrClient: SolrClient
    }
    
    似ている
    @Component
    public class YourBean {
       @Autowired
       public MongoTemplate mongoTemplate;
       @Autowired
       public SolrClient solrClient;
    }
    
    また、setメソッドを使用してインジェクションを使用できます.
        var hello: HelloService? = null
            @Autowired
            set(value) {
                field = value
                println("test")
            }
    
  • プロパティクラスを作成するには@ConstructorBinding
  • @ConfigurationProperties("test")
    @ConstructorBinding
    class TestConfig(
        val name:String
    ) 
    
    またはlateinit
    @ConfigurationProperties("test")
    class TestConfig {
        lateinit var name: String
    }
    
  • メタ情報を生成する場合は、設定する必要がありますspring-boot-configuration-processor with kapt
  • 冬眠した小琴


    主なエラーと問題はHaulmont article .
    もう一度、私はあなたが設定する必要があるあなたの注意を引くno-args and all-open プラグインと実装hashCode and equals メソッド.

    ジャクソンと共に


    追加する必要がありますJackson Module Kotlin プロジェクトで.その後、明示的にオブジェクトの型を指定できません.
    import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
    import com.fasterxml.jackson.module.kotlin.readValue
    
    data class MyStateObject(val name: String, val age: Int)
    
    ...
    val mapper = jacksonObjectMapper()
    
    val state = mapper.readValue<MyStateObject>(json)
    // or
    val state: MyStateObject = mapper.readValue(json)
    // or
    myMemberWithType = mapper.readValue(json)
    

    マップコンストラクタ


    MapStrootは注釈プロセッサを通して動作します.したがって、設定する必要がありますkapt 正しく.同時に、モデルがLombok注釈を使用するならば、mappersに問題があるかもしれません.
    <plugin>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-maven-plugin</artifactId>
      <version>${kotlin.version}</version>
      <executions>
        <execution>
            <id>kapt</id>
            <goals>
                <goal>kapt</goal>
            </goals>
            <configuration>
                <sourceDirs>
                    <sourceDir>src/main/kotlin</sourceDir>
                    <sourceDir>src/main/java</sourceDir>
                </sourceDirs>
                <annotationProcessorPaths>
                    <annotationProcessorPath>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${mapstruct.version}</version>
                    </annotationProcessorPath>
                </annotationProcessorPaths>
            </configuration>
        </execution>
      ...
      </executions>
      ....
    </plugin>
    

    ロンボクと一緒のKollin


    正直、それは痛みです.
    もちろん、使用することができますLombok compiler plugin , しかし、しばしばあなたが同時にKaptとLrombokを使うならば、あなたは多くの問題に遭遇するかもしれません.
    デフォルトでは、Kaptはすべての注釈プロセッサを使用してJavaacを使用して作業を無効にしますが、これは正しく動作しません.
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <annotationProcessorPaths>
                <annotationProcessorPath>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                    <version>${lombok.version}</version>
                </annotationProcessorPath>
            </annotationProcessorPaths>
        </configuration>
    </plugin>
    
    同時に、KAPTによって使用される注釈プロセッサがLombokに依存しない場合にのみ、LMPBOKはKAPTと正しく動作します.我々の場合、それは真実ではなかった.理由は、なぜ我々は最初のステップでKotlinにドメインモデル全体を翻訳しなければならなかった.また、オプションの一つはDelombokを使うことです.

    モッカートとのコールリン


    Mockitoは、ボックスからkotlinタイプで正しく動作しません.春はMockk . また、mockitoのための特別なモジュールがあります.Mockito-Kotlin .
    プロジェクトではmokkito kotlinを使いました.多くのメソッドが異なるモジュールで複製されるので、注意しなければなりません.any() 現在2箇所になります-org.mockito.kotlin and org.mockito.Mockito .

    コリンと伐採


    選んだkotlin-logging . これは本当に便利なライブラリです.
    import mu.KotlinLogging
    private val logger = KotlinLogging.logger {} 
    class FooWithLogging {
        val message = "world"
        fun bar() {
            logger.debug { "hello $message" }
        }
    }
    

    結論


    簡単な結論でその記事を完成したい.1つのプロジェクトでJavaとKotlinを一緒に使用すると、追加の設定が必要ですが、ほとんどすべてが解決され、1つのプロジェクトで2つの言語を使用する機会が得られます.私たちにとって最大の問題は、ロボックとコリンが不和だった.

    参考文献

  • Kotlin references
  • Video from Jetbrains. Kotlin and Spring

  • Kotlin and Spring. References
  • Kotlin and Spring Boot. References
  • MapStruct and Kotlin
  • Jackson and Kotlin
  • Mockito and Kotlin
  • kotlin-logging