背景
项目接入Kotlin之后,在进行打包时,多个 Gradle Plugin 处理class时抛出异常,包括使用asm或者javassist库都会报错,
具体异常信息如下:
asm:
Caused by: java.lang.RuntimeException
at org.objectweb.asm.ClassVisitor.visitModule(ClassVisitor.java:148)
at org.objectweb.asm.ClassReader.readModule(ClassReader.java:731)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:632)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:500)
复制代码
javassist:
java.io.IOException: invalid constant type: 19 at 5
at javassist.bytecode.ConstPool.readOne(ConstPool.java:1244)
at javassist.bytecode.ConstPool.read(ConstPool.java:1175)
at javassist.bytecode.ConstPool.<init>(ConstPool.java:185)
at javassist.bytecode.ClassFile.read(ClassFile.java:829)
at javassist.bytecode.ClassFile.<init>(ClassFile.java:154)
at javassist.CtClassType.<init>(CtClassType.java:96)
at javassist.ClassPool.makeClass(ClassPool.java:729)
at javassist.ClassPool.makeClass(ClassPool.java:707)
at javassist.ClassPool$makeClass$2.call(Unknown Source)
复制代码
问题原因
经排查,插件报错的时机是在处理module-info.class
,那么这个文件是做什么的呢?
module-info.class
首先,我们发现这个module-info.class存在于多个kotlin官方库中,例如:
org.jetbrains.kotlin:kotlin-stdlib-common:1.4.21
+--- kotlin-stdlib-jdk8-1.4.21.jar
+--- META-INF
+--- versions
+--- 9
+--- module-info.class
复制代码
module-info.class 内容如下:
module kotlin.stdlib {
exports kotlin;
exports kotlin.annotation;
exports kotlin.collections;
exports kotlin.collections.unsigned;
exports kotlin.comparisons;
...
}
复制代码
经 baidu + google,找到这个class的作用;
简单来讲,就是JDK9支持模块化,类似Dart语言的包组织,JS的export,这样可以管理或者重新组织一个新的包,而不是像JDK8以下一样,只能通过Java修饰符来控制访问权限;而这个module-info.class
就是来管理和描述这个包的;
在JDK8及以下,module-info.class并不会起作用,只有在JDK9以上才会起作用;
可以看到这个class并不是一个正常的class,并不包含类或者方法,所以asm和javassist处理这个class时,就会解析报错;
解决办法
方法一:在处理class时,判断class是否为module-info.class
签名,如果是,则跳过;但是需要所有的插件都做了这样的处理;
方法二:编写独立的插件,专门用来删除module-info.class
,并且第一个注册这个transform,这样后面所有的插件都不会处理到这个class;缺点是,项目就不能支持JDK9了,但是Android目前相关库最高支持到JDK8,所以影响不大;
最终我们项目采用的方法二,目前运行稳定,未发现异常;