Kotlin Noarg Allopen插件的安装使用和测试以及踩过的坑(插件似乎不生效问题)
前言:
在kotlin中使用java的部分框架/工具时,尝尝会出现不兼容的问题,这些问题有很大概率是由于kotlin类没有无参构造器或者kotlin类默认final引起的。
同样,我在使用工具类/框架时也遇到了这样的问题,最终的解决办法是引入kotlin官方的 No-arg,All-open插件。
本文假设使用的是IDEA集成开发环境和Gradle管理工具。
安装:
在你的build.gradle文件中
Groovy:
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
}
apply plugin: "kotlin-noarg"
apply plugin: "kotlin-allopen"
Kotlin:
plugins {
id "org.jetbrains.kotlin.plugin.noarg" version "1.7.21"
id "org.jetbrains.kotlin.plugin.allopen" version "1.7.21"
}
配置和使用:
1.在build.gradle中配置插件必须的属性
noArg {
//如果您希望插件从合成构造函数运行初始化逻辑,则启用invokeInitializers选项。缺省情况下,它是禁用的。
invokeInitializers = true
//注意是全名,不是包名,以我下文为例,这里应该是annotation("com.openaddr.annotation.NoArg")
annotation("你的自定义注解全引用名")
}
allOpen {
//annotation("com.openaddr.annotation.AllOpen")
annotation("你的自定义注解全引用名")
// annotations("你的自定义注解全引用名", "你的另一个自定义注解全引用名")
}
2.在项目某个路径下创建自定义注解
//例如我在com.addr.annotation包下创建了两个注解
//NoArg代表添加无参构造方法,AllOpen代表给类和方法取消final
package com.addr.annotation
annotation class NoArg
annotation class AllOpen
3.在某个需要添加无参构造方法或者取消final的类上添加自定义注解
package com.addr.model
import com.addr.annotation.AllOpen
import com.addr.annotation.NoArg
//需要哪个功能就添加哪个注解,也可以都添加,甚至你可以在build.gradle中将这两个功能指定为同一个注解,添加一个注解则同时生效两个功能
@AllOpen
@NoArg
//可以是data类,也可是普通类
data class Father(val string: String) {
fun hello(){
println("hello from father")
}
}
验证是否生效(注意有坑!!):
1.坑:
相信读者中有一部分已经想到了,验证是否生效直接用IDEA的反编译工具看一下反编译的结果,根据有没有无参构造,是不是final就可以验证了。确实,它有时候是可以判断的。
然而,据我实测,IDEA的反编译似乎有延迟,或者完全不更新。它显示final或者没有无参构造的时候,实际上根据我实测,其实已经是有了的(尤其是同时加入两个插件,非常容易出现反编译结果不准确,我为此耽误了大量时间)。所以尽量不要依赖此工具验证结果。
建议参考下文的验证方式。
2.验证是否open:
验证open最简单的方式是尝试去继承被@AllOpen标注的类
创建子类,并继承父类(验证类是否open),重写方法(验证方法是否open)
package com.openaddr.model
class Son(string: String) : Father(string) {
override fun hello() {
println("hello from son")
}
}
编译,如果编译通过,说明已经有open了(如果没有open,则会报错)
如果没有open,报错信息:
//类不能被继承
This type is final, so it cannot be inherited from
//方法不能被重写
'hello' in 'Father' is final and cannot be overridden
如果open了则会正常编译通过
3.验证是否有无参构造:
需要注意的是,官方有这样一段声明:
The generated constructor is synthetic so it can't be directly called from Java or Kotlin, but it can be called using reflection.
意思是:
被生成的无参构造器不能被直接被Java或者Kotlin调用,但它可以通过反射的方式调用。
因此,我们验证是不能直接通过无参构造对象来验证的,应该通过反射来构造对象:
package com.openaddr.test
import com.openaddr.model.Father
import com.openaddr.model.Son
fun main() {
//反射构造
val father = Father::class.java.getDeclaredConstructor().newInstance()
println(father)
}
如果能成功输出对象(编译通过),说明无参构造生效了:
Father(string=null)
如果无参构造没有生效,则应该会抛出以下异常:
Exception in thread "main" java.lang.NoSuchMethodException: com.openaddr.model.Father.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at com.openaddr.test.MainTestKt.main(MainTest.kt:8)
at com.openaddr.test.MainTestKt.main(MainTest.kt)
进程已结束,退出代码1
至此,如果一切顺利,我们已经成功使用并测试了这两个插件。祝大家kotlin学习顺利。