Kotlin ksp命令行解析kotlin文件自动生成UML类图

ksp是官方提供的用来解析Kotlin文件的工具,这里我用它来实现解析Kotlin项目,自动生成UML类图的功能(如上图所示)。

网上包括外网所有的ksp介绍都是在Android Studio中使用通过gradle配置,因为我想用ksp解析任意项目,而不是集成到某个项目里面,所以我研究了一下通过命令行调用的方式。

官方教程在这个地址里面。

1. 下载kotlin编译器和ksp

#!/bin/bash

# Kotlin compiler
wget https://github.com/JetBrains/kotlin/releases/download/v1.8.0/kotlin-compiler-1.8.0.zip
unzip kotlin-compiler-1.8.0.zip

# KSP
wget https://github.com/google/ksp/releases/download/1.8.0-1.0.8/artifacts.zip
unzip artifacts.zip

2. bash命令行调用kotlinc


#!/bin/bash
KSP_PLUGIN_ID=com.google.devtools.ksp.symbol-processing
KSP_PLUGIN_OPT=plugin:$KSP_PLUGIN_ID

KSP_PLUGIN_JAR=./com/google/devtools/ksp/symbol-processing-cmdline/1.8.0-1.0.8/symbol-processing-cmdline-1.8.0-1.0.8.jar
KSP_API_JAR=./com/google/devtools/ksp/symbol-processing-api/1.8.0-1.0.8/symbol-processing-api-1.8.0-1.0.8.jar
KOTLINC=./kotlinc/bin/kotlinc

AP=/path/to/your-processor.jar

mkdir out
$KOTLINC \
        -Xplugin=$KSP_PLUGIN_JAR \
        -Xplugin=$KSP_API_JAR \
        -Xallow-no-source-files \
        -P $KSP_PLUGIN_OPT:apclasspath=$AP \
        -P $KSP_PLUGIN_OPT:projectBaseDir=. \
        -P $KSP_PLUGIN_OPT:classOutputDir=./out \
        -P $KSP_PLUGIN_OPT:javaOutputDir=./out \
        -P $KSP_PLUGIN_OPT:kotlinOutputDir=./out \
        -P $KSP_PLUGIN_OPT:resourceOutputDir=./out \
        -P $KSP_PLUGIN_OPT:kspOutputDir=./out \
        -P $KSP_PLUGIN_OPT:cachesDir=./out \
        -P $KSP_PLUGIN_OPT:incremental=false \
        -P $KSP_PLUGIN_OPT:apoption=key1=value1 \
        -P $KSP_PLUGIN_OPT:apoption=key2=value2 \
        $*

官方教程到这一步就结束了,里面没有介绍最关键的ksp处理类的jar包生成。只知道要传一个AP=/path/to/your-processor.jar进去。

3. ksp处理类

package cc.rome753
import com.google.devtools.ksp.*
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.symbol.*


class MySymbolProcessorProvider:SymbolProcessorProvider {
    override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
        return MySymbolProcessor(environment)
    }
}

class MySymbolProcessor(private val environment: SymbolProcessorEnvironment): SymbolProcessor {
    @OptIn(KspExperimental::class)
    override fun process(resolver: Resolver): List<KSAnnotated> {
        environment.logger.info("process--------------------------------")
        val logger = environment.logger

        val files = resolver.getAllFiles()

        val allClass = mutableListOf<MyClass>()
        val dictNameId = mutableMapOf<String,Int>()

        files.forEach { file ->
            logger.info("file: ${file.fileName}")
            file.declarations.forEach { dec ->
                if (dec is KSClassDeclaration) {

实际上就是一个继承SymbolProcessorProvider和一个继承SymbolProcessor的类,在SymbolProcessor的process方法里面可以遍历所有的kotlin文件和类、类的属性和方法,这样就能把这些保存到json中,供后面使用。

4. ksp处理类生成jar包

用kotlinc编译指令生成jar包
kotlinc myprocessor -cp symbol-processing-api-1.8.0-1.0.8.jar -d myprocessor.jar

但是这个生成的jar包是不能直接提供给上面的bash命令使用的,因为kotlinc编译器不知道怎么从jar包里面找MySymbolProcessorProvider这个类。

我参考了一下github上ksp示例,它是Android Studio工程的,里面有jar包的META-INF设置。方法如下:

新建一个META-INF文件夹,文件夹里面放一个文本文件:
文件名是:com.google.devtools.ksp.processing.SymbolProcessorProvider
文件内容是:cc.rome753.MySymbolProcessorProvider

用jar命令把文件夹写入jar包里
jar uvMf myprocessor.jar META-INF

这样就能运行kotlinc的bash指令了。

5. 绘制UML类图

将ksp处理类生成的类相关的json信息用vis-network绘制到网页中展示。具体参考Swift自动生成UML类图这篇教程,虽然是Swift的,但是原理是一样的。

完整代码都在github仓库

运行方法:下载或克隆仓库,进入主目录,运行命令即可
python3 runKotlin.py /YourKotlinProjectDir

6. 缺点

用ksp命令行有一个致命的问题,就是当kotlin文件稍微多点(超过100个,大部分非demo项目都超过这个数),kotlinc命令行会就产生OOM.

exception: java.lang.OutOfMemoryError: GC overhead limit exceeded
	at org.jetbrains.kotlin.protobuf.CodedOutputStream.newInstance(CodedOutputStream.java:106)
	at org.jetbrains.kotlin.metadata.ProtoBuf$Type.<init>(ProtoBuf.java:4838)
	at org.jetbrains.kotlin.metadata.ProtoBuf$Type.<init>(ProtoBuf.java:4807)
	at org.jetbrains.kotlin.metadata.ProtoBuf$Type$1.parsePartialFrom(ProtoBuf.java:4979)
	at org.jetbrains.kotlin.metadata.ProtoBuf$Type$1.parsePartialFrom(ProtoBuf.java:4974)
	at org.jetbrains.kotlin.protobuf.CodedInputStream.readMessage(CodedInputStream.java:495)
	at org.jetbrains.kotlin.metadata.ProtoBuf$Type$Argument.<init>(ProtoBuf.java:5094)
	at org.jetbrains.kotlin.metadata.ProtoBuf$Type$Argument.<init>(ProtoBuf.java:5030)

我配置了一些提升虚拟机内存的指令,但是没什么效果。

kotlinc -Dkotlin.daemon.jvm.options="-Xms2g -Xmx12g -XX:+UseG1GC -XX:G1HeapRegionSize=2048m -XX:MaxGCPauseMillis=5000 -XX:MaxPermSize=700m -XX:ReservedCodeCacheSize=480m

当然这个问题是kotlinc命令行导致的,跟ksp没有关系。我在issues里反应了,看看有没有解决方法。

posted @ 2023-02-06 17:26  rome753  阅读(523)  评论(0编辑  收藏  举报