Files
openidea/plugins/kotlin-bridge
l0ng-ai 9bb44cbeb3 feat(java): resolve compiled Kotlin APIs in Maven Java editors (#669)
Java files in mixed Maven projects could not resolve Kotlin types from the same module or upstream reactor modules, because Kotlin compiler output never reached JDT's Java model.

A per-project bridge compiles saved Kotlin sources with the project's own Maven setup into private staging output (a bundled Maven extension redirects outputs and records each module's Kotlin compile result) and mounts the Kotlin classes as marked libraries through a bundled JDT command, leaving m2e/JRE containers and other entries untouched. The last successful snapshot stays mounted while rebuilding; a new one is published when every Kotlin target compiles, even if javac fails, so Java callers of a renamed or removed Kotlin API show their errors in the editor. Kotlin compile failures keep the previous API and are reported under the kotlin-bridge Problems source. Removing the last Kotlin file withdraws the libraries. Changes under build outputs and excluded directories never trigger a rebuild.

Part of #428
2026-11-01 16:33:44 +08:00
..

Kotlin binary bridge

App-owned source, licensed under this repository's Apache-2.0 license. The jar contains no third-party implementation classes. JDT LS and Maven supply their respective APIs at runtime.

KotlinLibraries is a JDT LS delegate command. openidea.kotlin.replace takes one complete array of {projectUri, libraries: [{path, test}]} objects and returns the number of changed projects. Paths name fully published, immutable directories. An empty array withdraws all owned libraries. Only library entries carrying ai.openidea.kotlin=true are removed; all other IClasspathEntry objects are retained, including containers, access rules, attributes and project references. A Java model listener restores the desired snapshot after Maven reimport.

IsolatedOutput is a Java 8 Maven lifecycle participant, activated only in the private editor build via -Dmaven.ext.class.path=<jar> and -Dopenidea.kotlin.staging=<absolute-directory>. It redirects reactor output before lifecycle planning and records Maven's resolved dependency closure after each session, including failed builds. An execution listener records each module's Kotlin compile/test-compile targets as successful, failed or skipped. The host uses the project's Maven lifecycle/configuration, then publishes only classes whose actual SourceFile attribute ends in .kt, plus Kotlin module metadata. Java output is not bridged. Main/test Kotlin APIs and same-reactor consumers are covered; Precise Kotlin source navigation, unsaved analysis and refactoring are outside this bridge.

The host debounces saved/source/configuration changes, cancels superseded process groups, and retains the last successful snapshot while rebuilding. Maven runs with --fail-at-end. A new snapshot is attached only when all Kotlin targets in modules containing Kotlin sources succeed, even if javac fails. Java diagnostics belong to JDT. Failed or skipped Kotlin targets retain the previous snapshot and report errors under kotlin-bridge Problems and a notification explaining the older API. Old directories are deleted only after JDT acknowledges replacement. With no Kotlin sources left, all managed libraries and bridge diagnostics are withdrawn, even when the POM still declares the Kotlin plugin. Extensionless watcher paths trigger only below a Maven module's src/, outside generated and user-excluded directories. Run/Debug preparation is independent of this editor build.

Build

Built against JDT LS 1.63.0 and Maven 3.9.11, using their installed API jars. build-dependencies.sha256 pins all build inputs. The build refuses different inputs; --record-dependencies is an explicit maintainer action when updating those dependencies. Compilation uses the JDT batch compiler with Java 21 target for the JDT command and Java 8 target for the Maven participant. Use Java 25 to run the build compiler. Archive order and timestamps are deterministic.

python3 plugins/kotlin-bridge/build.py /path/to/jdtls /path/to/maven
shasum -a 256 plugins/kotlin-bridge/openidea-kotlin-bridge.jar

Committed jar SHA-256: 5c6407a85bd3cfcde0ee68b2f223dd3d1ca0e5165ff76a2249191617496b1fcd.

The SDK embeds this jar with include_bytes!, writes it atomically into the app data directory, and includes it in JDT LS initialization bundles.

Integration regression

# `java` on PATH must satisfy JDT LS; JAVA_HOME selects Maven's project JDK.
JAVA_HOME=/path/to/project/jdk python3 plugins/kotlin-bridge/tests/verify.py /path/to/jdtls

Requires Maven on PATH and access to Kotlin 2.0.10 and the fixture's Maven plugins (or their existing local cache). The test creates its own projects, workspace, bundle copy and JDT process. It checks baseline errors, single/reactor resolution, SMS/member completion, binary definition locations, preservation of unowned entries, reimport, API changes, publication despite javac failure, failed/skipped Kotlin target retention, deletion withdrawal and repair. Evidence and protocol transcripts are written to a printed temporary directory. Only the spawned JDT process is terminated.