侧边栏壁纸
博主头像
术业有道之编程博主等级

亦是三月纷飞雨,亦是人间惊鸿客。亦是秋霜去叶多,亦是风华正当时。

  • 累计撰写 99 篇文章
  • 累计创建 50 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

springboot中使用kotlin的一些问题

Administrator
2020-09-01 / 0 评论 / 0 点赞 / 95 阅读 / 10543 字

spring很早就支持kotlin,实际项目中大多数情况下都是java和kotlin混合编写,本文是一篇指引如何在springboot中使用kotlin与java混合开发,并且遇到的一些问题及解决方案。

本教程只演示maven下对kotlin的集成使用

1、声明要使用的kotlin的信息

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <kotlin.version>1.3.21</kotlin.version>
        <kotlin.language.version>1.3</kotlin.language.version>
        <kotlin.compiler.incremental>true</kotlin.compiler.incremental>
        <kotlin.compiler.languageVersion>${kotlin.language.version}</kotlin.compiler.languageVersion>
        <kotlin.compiler.apiVersion>${kotlin.language.version}</kotlin.compiler.apiVersion>
        <kotlin.compiler.jvmTarget>${java.version}</kotlin.compiler.jvmTarget>
        <kotlin.compiler.incremental>true</kotlin.compiler.incremental>
    </properties>

这里有很多都不是必须的 具体参数意义请移步 kotlin官方maven工具文档
2、使用kotlin必要的maven包引入

 <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>

3、增加maven编译插件
以下是我个人的使用配置,与kotlin官方的稍微有些不同

<plugin>
                <artifactId>kotlin-maven-plugin</artifactId>
                <groupId>org.jetbrains.kotlin</groupId>
                <version>${kotlin.version}</version>
                <configuration>
                    <compilerPlugins>
                        <plugin>spring</plugin>
                    </compilerPlugins>
                    <languageVersion>${kotlin.language.version}</languageVersion>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.jetbrains.kotlin</groupId>
                        <artifactId>kotlin-maven-allopen</artifactId>
                        <version>${kotlin.version}</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <id>compile</id>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.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>

遇到的问题

1、springboot使用maven编译、打包后启动都正常,但是在idea中启动项目报错

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: @Configuration class 'TestApplication' may not be final. Remove the final modifier to continue.

导致的原因是kotlin最终的class都是 final 修饰的,而spring中 @SpringBootApplication、@Configuration、@Bean等注解的class是可继承的,导致了一些问题, 具体细节可以参考这篇文章

解决方案

第一种:手动加上open关键字,麻烦而且在idea中默认是灰色,强迫症不好受。
第二种:修改工程配置文件。必须保证当前的配置是按上面的maven配置来的,
然后针对idea开发工具下的项目增加或修改.iml文件,下面是一个完整的.iml文件,可以参考此文件适当修改自己工程的.iml文件(修改前备份一下文件,错了还能还原)

<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="FacetManager">
    <facet type="Spring" name="Spring">
      <configuration />
    </facet>
    <facet type="web" name="Web">
      <configuration>
        <webroots />
        <sourceRoots>
          <root url="file://$MODULE_DIR$/src/main/java" />
          <root url="file://$MODULE_DIR$/src/main/resources" />
        </sourceRoots>
      </configuration>
    </facet>
    <facet type="kotlin-language" name="Kotlin">
      <configuration version="3" platform="JVM 1.8" useProjectSettings="false">
        <compilerSettings>
          <option name="additionalArguments" value="-java-parameters" />
        </compilerSettings>
        <compilerArguments>
          <option name="jvmTarget" value="1.8" />
          <option name="languageVersion" value="1.3" />
          <option name="apiVersion" value="1.3" />
          <option name="pluginOptions">
            <array>
              <option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.stereotype.Component" />
              <option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.transaction.annotation.Transactional" />
              <option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.scheduling.annotation.Async" />
              <option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.cache.annotation.Cacheable" />
              <option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.boot.test.context.SpringBootTest" />
              <option value="plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.validation.annotation.Validated" />
            </array>
          </option>
          <option name="pluginClasspaths">
            <array>
              <option value="$KOTLIN_BUNDLED$/lib/allopen-compiler-plugin.jar"/>
            </array>
          </option>
        </compilerArguments>
      </configuration>
    </facet>
  </component>
</module>

注意文件中没有以下代码块的加上

<option name="pluginClasspaths">
    <array>
       <option value="$KOTLIN_BUNDLED$/lib/allopen-compiler-plugin.jar"/>
    </array>
</option>

然后maven清理下当前的编译文件,重新启动springboot项目,应该就能正常启动了。

2、声明的 javaBean无法直接按照kotlin的方式获取属性。

例如:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "min_user")
@DynamicUpdate
@DynamicInsert
@Accessors(chain = true)
public class MinUser implements Serializable {
    @Id
    @Column(name = "id",
            columnDefinition = "bigint(20) COMMENT 'ID,自增'")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "openId",
            columnDefinition = ("varchar(100) COMMENT 'openid'"), unique = true)
    private String openId;

    @Column(name = "session_key",
            columnDefinition = ("varchar(255) COMMENT '会话密钥'"))
    private String sessionKey;

    @Column(name = "unionid",
            columnDefinition = ("varchar(100) COMMENT '用户在开放平台的唯一标识符'"))
    private String unionid;
}

使用kotlin代码进行赋值或者取值的时候会报错,无法找到属性。
例如以下代码:

val user= MinUser()
user.openId="123456"

解决方案

原因是kotlin无法访问私有的javabean对象资源 需要属性 private 改为 public,如果使用kotlin的方式声明javabean则没有此问题。但是由于使用了hibernate持久化方案,为了避免hibernate和spring-data-jpa与kotlin的不兼容,故javabean最好是使用java创建

3、lombok.extern.slf4j.Slf4j 注解在kotlin的class上无法使用。

解决方案

在class中声明 private val logger = LoggerFactory.getLogger(javaClass) 替换原有的@Slf4j方式
个人公众号

0

评论区