skip to content

How and why would you use `@get:JvmName` (and `@set:JvmName`) on a Kotlin property, and what problem does it solve at the Java boundary?

level: middleimportance: should knowfreq 35%

answer

  1. @JvmName renames the bytecode method, not the Kotlin name
  2. On properties: must pick @get: or @set:
  3. Fixes is-prefix Boolean accessor names
  4. Resolves platform/signature clashes
  5. Kotlin call sites unchanged

basics

~10 s

@get:JvmName("...") renames the getter method that Java sees, without changing the Kotlin property name. You use it to fix or customize the Java-facing accessor name, e.g. to avoid awkward or clashing generated names.

solid answer

~40 s

`@JvmName` renames a generated JVM method. Because a property has separate getter and setter methods, you must target the right one: `@get:JvmName("...")` renames the getter, `@set:JvmName("...")` renames the setter. Common uses: giving Java a cleaner accessor name; working around Kotlin's `is`-prefix getter rule (a `Boolean` `val isReady` generates `isReady()` not `getIsReady()`) when you need a specific name; and resolving accessor naming that would otherwise be unidiomatic for Java callers. It does **not** change how Kotlin code refers to the property. A related use is breaking a JVM signature clash where two declarations would erase to the same method name. Note `@JvmName` on the *getter* changes only the method Java calls; Kotlin still uses `obj.property`.

code

kotlin · 8 lines
kotlin
class Session {
    var active: Boolean = false
        @get:JvmName("isSessionActive")
        @set:JvmName("setSessionActive")
        set(v) { field = v }
}
// Java: session.isSessionActive(); session.setSessionActive(true);
// Kotlin: session.active = true

go deeper

for a junior

Knows @get:JvmName renames the Java-visible getter and that the Kotlin name stays the same.

for a middle

Correctly targets getter vs setter and cites the Boolean is-prefix and cleaner-accessor use cases.

for a senior

Uses it to resolve platform signature clashes and understands override/identifier constraints.

for a principal

Weighs JVM-API stability and naming conventions across a public library boundary when prescribing @JvmName usage.

## What `@JvmName` does `@JvmName("newName")` controls the **name of the method emitted into bytecode**. It does not rename the Kotlin declaration — Kotlin source still uses the original property/function name. It exists purely to shape what **Java (and other JVM languages) see**. ## Why it needs a use-site target on properties A property has more than one generated method (getter, setter), so `@JvmName` placed bare on the property is **not allowed** there in a meaningful way — you must say *which* accessor: ```kotlin var status: String = "" @get:JvmName("fetchStatus") @set:JvmName("updateStatus") set(value) { field = value.trim() } ``` From Java this is `obj.fetchStatus()` / `obj.updateStatus(...)`. From Kotlin it stays `obj.status`. ## Problems it solves at the boundary ### 1. Cleaner Java accessor names Kotlin generates `getFoo()`/`setFoo()`. If Java consumers expect a different name (matching an interface or legacy convention), `@get:JvmName` lets you supply it without renaming the property. ### 2. The `is`-prefix rule for Booleans A `Boolean` property named `isReady` generates `isReady()` (no `get`) and `setReady(...)`. If you need a non-standard accessor name for Java, `@get:JvmName`/`@set:JvmName` override the generated names. ### 3. Signature clashes Two declarations can erase to the **same JVM signature** (e.g. an extension and a member, or two functions differing only by generic erasure), producing a *platform declaration clash*. `@JvmName` on one of them gives it a distinct bytecode name so both can coexist. On properties you apply it via `@get:`/`@set:`. ```kotlin fun List<String>.firstChar(): Char = first()[0] @JvmName("firstCharInt") fun List<Int>.firstChar(): Int = first() ``` ## Key constraints - The new name must be a valid JVM identifier. - It changes **only** the JVM-visible method name; Kotlin call sites are unaffected. - Overriding a method while renaming it via `@JvmName` is restricted — you generally cannot `@JvmName` an `open`/`override` accessor in a way that breaks the override contract.

  • Why can't you just put `@JvmName` directly on the property without a target?
    A property generates multiple methods (getter/setter), so the compiler needs `@get:`/`@set:` to know which method to rename; an untargeted `@JvmName` on a property isn't valid for this purpose.
  • Does `@get:JvmName` affect Kotlin reflection or call syntax?
    No. Kotlin still accesses the property by its declared name; only the JVM method name (what Java/bytecode sees) changes.

saying these in an interview costs you the question

  • Thinking @JvmName renames the Kotlin property too
  • Putting bare @JvmName on a property and expecting it to work
  • Using it to rename an override in a way that breaks the contract
  • Confusing @JvmName with @JvmStatic or @JvmField

context