Keep reflective access narrow and intentional
Reflection can support diagnostic tools, plugin registries, and metadata-driven configuration. It also bypasses some compile-time checks and can expose fields that were never intended for output. Prefer an explicit allowlist over “serialize everything.”
data class Account(val displayName: String, val token: String)
fun publicFields(account: Account): Map<String, String> =
mapOf("displayName" to account.displayName)
The explicit adapter makes the omission of token reviewable. A reflective equivalent should require an opt-in annotation on each exposed property and define behavior for throwing getters, unsupported types, and missing metadata.
Do not make private members accessible merely to avoid designing a public contract. Reflection behavior also differs across Kotlin targets; JVM-specific assumptions should be labeled.
Exercise
Design an annotated diagnostic model containing one public field and one sensitive field. Verify only the public field is emitted, including after adding a new unannotated property.
Check: default-deny behavior prevents future fields from becoming accidentally public. Treat diagnostic output as an API with tests, not a dump of the entire object.