Top-level API without JvmName
TOP_LEVEL_API_WITHOUT_JVM_NAME reports a file whose public top-level functions or properties
compile into a file facade class without an explicit @file:JvmName.
| Diagnostic | TOP_LEVEL_API_WITHOUT_JVM_NAME |
| Default severity | Error |
| Applies to | JVM compilations only |
| Gradle property | topLevelApiWithoutJvmName |
| Exemption | @IntentionallyDefaultFacadeName |
What it reports
Kotlin files with top-level properties or functions that can be called from Java sources.
The diagnostic fires once per file, anchored on the first public top-level function or property.
package com.example/** Checks whether the network is reachable. */public fun ping(): Int = 0
Rationale
The derived facade name reads as an implementation detail at Java call sites (NetworkKt.connect()
instead of something Java-idiomatic), and it is tied to a fact Kotlin callers never see: the file
name. Renaming the file silently renames the facade and breaks Java sources and binaries compiled
against it. See Kotlin's
Java-to-Kotlin interop guide
for how top-level declarations actually compile.
Don't
package com.example// Facade class NetworkKt// renaming this file to NetworkClient.kt breaks every Java caller./** Connects to the network. */public fun connect(): Int = 0/** Disconnects from the network. */public fun disconnect(): Int = 0
Do
@file:JvmName("Network")package com.example// Java callers write Network.connect(),// the file can be renamed freely./** Connects to the network. */public fun connect(): Int = 0/** Disconnects from the network. */public fun disconnect(): Int = 0
Notes
- Files exposing only classifiers - classes, objects, type aliases - produce no facade worth naming.
- Files where every top-level callable is hidden from Java with
@JvmSyntheticare not reported. @PublishedApi internalcallables still count: public inline bodies can copy calls to their file facade into user binaries, so renaming that facade can break binary linkage.- Non-JVM compilations never register this check at all.
Exemption
@IntentionallyDefaultFacadeName is a file-target annotation, applied once per file as
@file:IntentionallyDefaultFacadeName(...), when keeping the derived facade name is intended:
@file:IntentionallyDefaultFacadeName(reason = ExemptionReason.FOR_BACKWARDS_COMPATIBILITY,)package com.exampleimport org.jetbrains.kotlinx.libs.api.watchdog.ExemptionReasonimport org.jetbrains.kotlinx.libs.api.watchdog.IntentionallyDefaultFacadeName/** Connects to the network. */public fun connect(): Int = 0/** Disconnects from the network. */public fun disconnect(): Int = 0
Configuration
apiWatchdog {javaInterop {topLevelApiWithoutJvmName = WatchdogSeverity.WARNING}}
The property lives inside the javaInterop { } block. javaInterop { enabled = false } turns off
this check along with the rest of the Java interop checks group.
With direct compiler invocation:
-P plugin:org.jetbrains.kotlin.library.api.watchdog:diagnosticSeverity=TOP_LEVEL_API_WITHOUT_JVM_NAME:warning