skip to content

What does the kotlin-reflect library let you inspect at runtime that plain java.lang.reflect cannot?

level: juniorimportance: must knowfreq 55%

answer

  1. @Metadata feeds kotlin-reflect
  2. Nullability: isMarkedNullable
  3. Properties reunite field+getter/setter
  4. isOptional = has default
  5. isSuspend recovers suspend

basics

~10 s

Kotlin reflection can see Kotlin-only details like whether a type is nullable, default parameter values, properties, and suspend functions. Plain Java reflection only sees what Java understands and misses these.

solid answer

~40 s

java.lang.reflect works at the JVM-bytecode level, so it sees classes, methods, fields and Java-visible annotations, but it is blind to Kotlin language concepts. The kotlin-reflect library reads the @Metadata annotation the Kotlin compiler attaches to every class and exposes a richer model: KClass, KProperty, KFunction, KParameter, KType. Through these you can see nullability (KType.isMarkedNullable), real Kotlin properties (val/var with getters/setters) rather than raw fields/methods, default-valued parameters (KParameter.isOptional), suspend functions, variance, type parameters, and visibility/modality as Kotlin sees them. You get Kotlin reflection from instance::class or KClass<*>, and you must add the kotlin-reflect dependency for the full API. Without it, only a limited subset works.

code

kotlin · 8 lines
kotlin
import kotlin.reflect.full.memberProperties

data class User(val name: String, val nickname: String? = null)

val props = User::class.memberProperties
props.forEach { p ->
    println("${p.name} nullable=${p.returnType.isMarkedNullable}")
}

go deeper

for a junior

Names a couple of Kotlin-only things (nullability, defaults) kotlin-reflect surfaces.

for a middle

Explains @Metadata as the source and lists properties/suspend/isOptional concretely.

for a senior

Distinguishes JVM bytecode model from Kotlin model and knows the bridge APIs and dependency boundary.

for a principal

Reasons about when reflecting on Kotlin semantics is worth the metadata cost vs staying in Java reflection for interop or startup.

## What reflection is Reflection means inspecting and manipulating code structure (types, members, parameters) at **runtime** instead of compile time. ## Two reflection systems on the JVM - **java.lang.reflect** — built into the JDK. It models the JVM bytecode view: `Class`, `Method`, `Field`, `Constructor`, `Parameter`, plus Java-retained annotations. It knows nothing about Kotlin's source-level concepts. - **kotlin-reflect** — Kotlin's own reflection library. Its entry types are `KClass`, `KCallable`, `KFunction`, `KProperty`, `KParameter`, and `KType`. It reads the **`@Metadata`** annotation that the Kotlin compiler stamps onto every compiled class; that metadata encodes the original Kotlin signatures. ## Kotlin-only things only kotlin-reflect can see - **Nullability** — `KType.isMarkedNullable` tells you `String` vs `String?`. The JVM erases this; Java sees both as `java.lang.String`. - **Properties** — Kotlin `val`/`var` become a backing field plus getter/setter in bytecode. Java reflection sees the field and methods separately; `KProperty` reunites them as one unit with `.getter`/`.setter`. - **Default parameter values** — `KParameter.isOptional` is true when a parameter has a default. Java has no notion of defaults at all. - **suspend functions** — Kotlin compiles `suspend fun` to a method with an extra `Continuation` parameter. `KFunction.isSuspend` recovers the original intent. - **Variance, declaration-site type parameters, `reified`-era type info via `typeOf<T>()`** and Kotlin **visibility/modality** (`KVisibility`, `isOpen`, `isAbstract`). ```kotlin import kotlin.reflect.full.memberProperties import kotlin.reflect.jvm.isAccessible data class User(val name: String, val nickname: String? = null) fun main() { val kClass = User::class for (p in kClass.memberProperties) { println("${p.name}: nullable=${p.returnType.isMarkedNullable}") } // name: nullable=false // nickname: nullable=true } ``` ## How you get each - Kotlin: `instance::class`, `SomeType::class`, `::topLevelFun`, `Type::property`. - Bridge to Java: `kClass.java` (KClass -> Class), `clazz.kotlin` (Class -> KClass), and `KFunction.javaMethod`, `KProperty.javaField` from `kotlin.reflect.jvm`. ## When you still drop to java.lang.reflect When you don't need Kotlin metadata, want zero extra dependency, or interop with Java frameworks that already work in `Class`/`Method` terms.

  • Where does kotlin-reflect get its Kotlin-specific information from?
    From the @Metadata annotation the Kotlin compiler embeds in each .class file; kotlin-reflect decodes it to reconstruct Kotlin signatures.
  • Does instance::class always need the kotlin-reflect artifact?
    Basic ::class and simpleName/qualifiedName work without it via kotlin-stdlib, but the rich API (memberProperties, callBy, isSuspend, etc.) needs the kotlin-reflect dependency on the classpath.

Java reflection reads the compiled blueprint; kotlin-reflect also keeps the architect's original annotated drawing (@Metadata).

saying these in an interview costs you the question

  • Claiming Java reflection can read Kotlin nullability or default values
  • Thinking KClass and Class are the same object
  • Not knowing @Metadata exists
  • Assuming all KClass APIs work without the kotlin-reflect artifact

context