Skip to main content

Default parameters without JvmOverloads

DEFAULT_PARAMETERS_WITHOUT_JVM_OVERLOADS reports public functions and constructors that declare default parameter values without @JvmOverloads.

DiagnosticDEFAULT_PARAMETERS_WITHOUT_JVM_OVERLOADS
Default severityError
Applies toJVM compilations only
Gradle propertydefaultParametersWithoutJvmOverloads
Exemption@IntentionallyWithoutJvmOverloads

What it reports

A public function or constructor that declares at least one default parameter value but carries no @JvmOverloads.

@file:JvmName("Sockets")
/** Opens a socket to [host]. */
public fun openSocket(
host: String,
port: Int = 80,
timeout: Int = 30,
) { }

Rationale

Without @JvmOverloads, Java callers of a function with three defaulted parameters have to spell out all three at every call site. See Kotlin's guide on overloads generation for how @JvmOverloads compiles the reduced overloads Java needs.

Don't

@file:JvmName("Connections")
/** Connects to [host]. */
public fun connect(
host: String,
port: Int = 80,
timeout: Int = 30,
) { }

Do

@file:JvmName("Connections")
/** Connects to [host]. */
@JvmOverloads
public fun connect(
host: String,
port: Int = 80,
timeout: Int = 30,
) { }

Don't

/** A connection to [host]. */
public class Connection(
host: String,
port: Int = 80,
)

Do

/** A connection to [host]. */
public class Connection @JvmOverloads constructor(
host: String,
port: Int = 80,
)

Notes

  • A defaulted parameter in the middle of the list still can't be skipped from Java even with @JvmOverloads. Keep optional parameters last (see REQUIRED_PARAMETER_AFTER_OPTIONAL) so the generated overloads actually cover the common call shapes.
  • Abstract and interface members, and annotation class constructors, are not reported: @JvmOverloads doesn't apply to them.
  • suspend functions and members of a value class are not reported: they are not Java-callable regardless of overloads.
  • Overrides are not reported: they can't re-declare default values.
  • @PublishedApi internal declarations are not reported: their public bytecode entry is a binary implementation detail, not supported Java source API.
  • @JvmSynthetic functions and constructors are hidden from Java on purpose and are not reported.
  • Non-JVM compilations never register this check at all.

Exemption

Apply @IntentionallyWithoutJvmOverloads to the function or constructor when serving Java callers the full signature only is intended, for example when the defaulted parameters make no sense without Kotlin's named arguments:

@file:JvmName("Connections")
// Supporting options type
/** Options applied after connecting. */
public class ConnectionConfig
/** Connects to [host] and applies [options]. */
@IntentionallyWithoutJvmOverloads(
reason = ExemptionReason.IGNORE_JAVA_INTEROP,
description = "Kotlin-only function. " +
"Java callers are expected to use the builder instead.",
)
@IntentionallyKotlinOnlyApi(reason = ExemptionReason.API_DESIGN)
public fun connect(
host: String,
port: Int = 80,
timeout: Int = 30,
builder: ConnectionConfig.() -> Unit,
) { }

Configuration

apiWatchdog {
javaInterop {
defaultParametersWithoutJvmOverloads = 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=DEFAULT_PARAMETERS_WITHOUT_JVM_OVERLOADS:warning

See also