skip to content

In Kotlin, what does the built-in standard library give you for reflection out of the box, and when do you need to add the kotlin-reflect dependency?

level: juniorimportance: must knowfreq 55%

answer

  1. ::class works; full reflection needs the JAR
  2. org.jetbrains.kotlin:kotlin-reflect
  3. KotlinReflectionNotSupportedError when missing
  4. kotlin.reflect.full package = the rich API
  5. Spring/Jackson pull it in transitively

basics

~10 s

Basic things like ::class work without extra setup. Richer reflection (reading properties, functions, parameters, supertypes) needs the separate kotlin-reflect library added to your build.

solid answer

~30 s

The kotlin-stdlib ships a tiny built-in reflection surface: the ::class operator gives you a KClass, but on stdlib alone you can mostly only read simpleName/qualifiedName and do basic identity/cast checks. Anything richer — listing members (memberProperties, declaredFunctions), reading constructors, supertypes, visibility, calling members, mapping a KClass to its Java counterpart fully, createInstance() — lives in the org.jetbrains.kotlin:kotlin-reflect artifact. You add it explicitly (e.g. implementation("org.jetbrains.kotlin:kotlin-reflect")). At runtime, calling a full-reflection API without kotlin-reflect on the classpath throws KotlinReflectionNotSupportedError. Many frameworks (Spring, Jackson Kotlin module) pull it in transitively, which is why people forget it is a separate dependency.

code

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

data class User(val id: Long, val name: String)

fun main() {
    // Works without kotlin-reflect:
    println(User::class.simpleName)        // "User"

    // Requires kotlin-reflect on the classpath, else
    // KotlinReflectionNotSupportedError at runtime:
    User::class.memberProperties.forEach { println(it.name) }
}

go deeper

for a junior

Knows ::class works out of the box and that a separate library is needed for 'more'.

for a middle

Names org.jetbrains.kotlin:kotlin-reflect and the kotlin.reflect.full APIs that require it.

for a senior

Explains the runtime KotlinReflectionNotSupportedError and how frameworks pull the artifact in transitively.

for a principal

Frames the two-JAR split as a deliberate cost-isolation design and reasons about when to keep reflection out entirely.

## Two reflection surfaces in Kotlin Kotlin splits reflection into two layers shipped in two different JARs: - **kotlin-stdlib** (always present): a minimal built-in reflection surface. The `::class` operator and `KClass` type live here, but only a thin slice of `KClass` actually works without the full library. - **kotlin-reflect** (`org.jetbrains.kotlin:kotlin-reflect`): the *full* implementation that backs the rich `kotlin.reflect.full` and `kotlin.reflect.jvm` APIs. ## What `::class` gives you without kotlin-reflect The `::class` operator (e.g. `String::class` or `value::class`) returns a `KClass<T>`. On stdlib alone you can reliably use: - `simpleName`, `qualifiedName` - `isInstance(obj)` - `.java` to bridge to a `java.lang.Class` (for plain Java reflection) ```kotlin val k: KClass<String> = String::class // works on stdlib alone println(k.simpleName) // "String" println(k.java.name) // bridge to java.lang.Class ``` ## What requires kotlin-reflect The richer members live mostly in the `kotlin.reflect.full` package and on `KCallable`/`KProperty`: - `memberProperties`, `declaredMemberProperties`, `declaredFunctions` - `primaryConstructor`, `constructors`, `createInstance()` - `supertypes`, `isData`, `visibility`, `isSealed` - Calling a `KFunction`/`KProperty` reflectively via `.call(...)` / `.get(...)` If you call one of these and kotlin-reflect is **not** on the classpath, the runtime throws `kotlin.reflect.jvm.internal.KotlinReflectionNotSupportedError`. ## How to add it ```kotlin dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") } ``` Version is usually managed by the Kotlin Gradle plugin's BOM/alignment, so you should match it to your Kotlin compiler version. Note many libraries (Spring, Jackson's `jackson-module-kotlin`) already pull it in transitively. ## Why the split exists Full reflection metadata and machinery is large and has startup/size cost. Keeping it out of stdlib means the common case (no reflection, or only `::class` identity checks) stays lightweight.

  • What exact error do you get if you call memberProperties without kotlin-reflect?
    A KotlinReflectionNotSupportedError is thrown at runtime — it is an Error, not a checked exception, so it usually surfaces as a crash.
  • Why might it 'just work' in a Spring app even though you never added kotlin-reflect?
    Spring (and Jackson's Kotlin module) declare kotlin-reflect as a transitive dependency, so it ends up on the classpath without you adding it explicitly.

stdlib reflection is a name tag (who are you); kotlin-reflect is the full medical chart (every detail) — you only carry the chart when you need it.

saying these in an interview costs you the question

  • Thinking all of KClass works from stdlib alone
  • Claiming kotlin-reflect is bundled in kotlin-stdlib
  • Not knowing the missing-dependency failure is a runtime error
  • Confusing kotlin-reflect with Java's java.lang.reflect

context