458 字
2 分钟
记录一下自己写第一个的Kotlin编译器插件

当你需要一个功能,虽然这个功能可以手写实现,但是谁不想偷个”懒“呢?

插件的作用#

插件的作用就是给Kotlin的特性为Java做桥接 --- 拓展属性

拓展属性是Kotlin的核心特性之一,在Kotlin中是非常好用的功能,但是到了Java反而变的难用,

Kotlin编译后的字节码文件#

在Kotlin/JVM平台中,拓展属性一般为顶层属性 --- topLevel,既然是顶层,那最终都会被放到一个静态类中这个静态类名 分为两部分一个: 前面的部分就是原文件的名称, 后面的部分加上Kt字符串例如: MyClass.kt会被编译为 MyClassKt.class, 在Java中访问需要调用这个静态类里面的静态方法或者属性, 就像下面这样

// MyClass.kt
val String.firstChar get() = this.first()
System.out.println(MyClassKt.getFirstChar("Hello"));  // H

这里MyClassKt#getFirstChar传入的就是receiver(接收器)

在Kotlin中可以像访问成员属性一样访问拓展属性,而在Java中必须通过”工具类”来访问, 显得有些不美观了, 所以我写了一个插件用于自动为receiver生成成员getter/setter

使用插件#

提前配置好插件后直接在commonMainjvmMain内写拓展属性

// Text.kt
import cn.rtast.interop.annotation.AutoGenGetter

class Text {}

@AutoGenGetter  // 使用注解标记生成getter
val Text.text get() = "Hello"

下面是将编译后的字节码反编译为Java代码的简化代码

import cn.rtast.interop.annotation.JavaOnly;


public final class Text {
   @JavaOnly
   public int getA() {
      return TextKt.getA(this);
   }
}

JavaOnly注解是一个RequiresOptIn的注解, 对Java使用者没有任何影响, 如果Kotlin 使用者使用这个API必须手动加上OptIn来抑制错误, 不手动加上则无法通过编译

插件地址#

插件源代码已经开源在Github上, 地址: InteropShield