# Can't understand kotlin's manner that "privatize" members of a \`data class\`

**URL:** <https://discuss.kotlinlang.org/t/cant-understand-kotlins-manner-that-privatize-members-of-a-data-class/29002>\
**Category:** Android\
**Created:** [August 2, 2024, 7:12am UTC](https://discuss.kotlinlang.org/t/cant-understand-kotlins-manner-that-privatize-members-of-a-data-class/29002 "2024-08-02T07:12:39Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![bczhc](https://avatars.discourse-cdn.com/v4/letter/b/e47c2d/32.png) [@bczhc](https://discuss.kotlinlang.org/u/bczhc)\
**Post date:** [August 2, 2024, 7:12am UTC](https://discuss.kotlinlang.org/t/cant-understand-kotlins-manner-that-privatize-members-of-a-data-class/29002/1 "2024-08-02T07:12:39Z")

</div>

Greetings community!

Let’s say in my Android project I have a data class:

```kotlin
data class Foo(
    val a: Int,
    val b: String,
)

```

Now if I use kotlin reflection to access its fields, all goes well. The console will print:

```console
a PUBLIC Success(1)
b PUBLIC Success(b)

```

However, this only works for debug build. If building the app in release mode, things will change, and I found that, all members became PRIVATE, which caused a reflection access failure.

```console
a PRIVATE Failure(kotlin.reflect.full.IllegalCallableAccessException: java.lang.IllegalAccessException: Class java.lang.Class<kotlin.reflect.jvm.internal.calls.CallerImpl$FieldGetter> cannot access private final field int org.example.kotlinreflection.Foo.a of class java.lang.Class<org.example.kotlinreflection.Foo>)
b PRIVATE Failure(kotlin.reflect.full.IllegalCallableAccessException: java.lang.IllegalAccessException: Class java.lang.Class<kotlin.reflect.jvm.internal.calls.CallerImpl$FieldGetter> cannot access private final field java.lang.String org.example.kotlinreflection.Foo.b of class java.lang.Class<org.example.kotlinreflection.Foo>)

```

In release build, `Foo`’s public fields become Kotlin’s private properties, and getters and setters are generated correspondingly. Directly accessing the private members is forbidden.

This makes me confused. If we want the fields be private, we can just add the `private` modifier; fields declared as `public` (though in Kotlin `public` can be omitted) becoming private **implicitly** after release build, kinda unintuitive and comfusing for me. Just say, Kotlin-specific reflection methods (methods under `K*`) can’t access member values in a plain Kotlin data class?

Note `class` (instead of `data class`) has the same thing (members becoming private after release build). Btw the annotation `@JvmField` works, and that’s just because it tells the compiler treat them as vanilla Java members - don’t touch them!

I’m fairly new to Kotlin. Maybe I missed something about Kotlin fields vs properties vs reflection?

Any idea? Thanks.

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [August 2, 2024, 7:56am UTC](https://discuss.kotlinlang.org/t/cant-understand-kotlins-manner-that-privatize-members-of-a-data-class/29002/2 "2024-08-02T07:56:04Z")

</div>

You are confusing properties and fields. In Kotlin we define properties, and they are more about getters/setters than fields. Fields are just a way to implement properties and they are hidden by default as an implementation details.

It is a common practice in Java as well to (almost) never define public fields, and instead create private fields + public getters/setters. Kotlin just made this easier to do.

See: [Property (programming) - Wikipedia](https://en.wikipedia.org/wiki/Property_(programming))

---

<div class="post-metadata">

**Author:** ![bczhc](https://avatars.discourse-cdn.com/v4/letter/b/e47c2d/32.png) [@bczhc](https://discuss.kotlinlang.org/u/bczhc)\
**Post date:** [August 2, 2024, 8:56am UTC](https://discuss.kotlinlang.org/t/cant-understand-kotlins-manner-that-privatize-members-of-a-data-class/29002/3 "2024-08-02T08:56:01Z")

</div>

Thanks for the reply. yea I basically understand properties vs fields. But now, in this case, how can one define a pure data class with _fields_ (but not the private intermediate _properties_) that will make deserialization libraries happy (like Gson etc)? Attach `@JvmField` on every members?

FYI what i’m doing is deserializing an object to a Ktor `FormDataContent`. The code:

```kotlin
inline fun <reified T : Any> fromObject(obj: T): FormDataContent {
        return FormDataContent(Parameters.build {
            // only applicable for members with @JvmField
            T::class.memberProperties.forEach {
                val name = it.name
                val value = it.getter.call(obj)
                value?.let { v ->
                    append(name, v.toString())
                }
            }
        })
    }

```

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [August 2, 2024, 11:49am UTC](https://discuss.kotlinlang.org/t/cant-understand-kotlins-manner-that-privatize-members-of-a-data-class/29002/4 "2024-08-02T11:49:07Z")

</div>

Yes, I believe `@JvmField` is the way to go.

Longer answer and my personal opinion is that serialization frameworks, dependency injection, etc., should optimally use getters/setters. Or support both props and fields and let users choose. AFAIK, from the very beginning, users ask GSON authors to include support for props and they ignore this. Anyway, I would expect specifically GSON to work correctly, because it can access private fields.

---

<div class="post-metadata">

**Author:** ![madmax1028](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/madmax1028/32/3335_2.png) [@madmax1028](https://discuss.kotlinlang.org/u/madmax1028)\
**Post date:** [August 2, 2024, 9:20pm UTC](https://discuss.kotlinlang.org/t/cant-understand-kotlins-manner-that-privatize-members-of-a-data-class/29002/5 "2024-08-02T21:20:15Z")

</div>

In data classes all main properties defined in primary constructor already have fields. If you want to filter all the other non-field backed properties you can write this:

```kotlin
T::class.memberProperties
	.filter { it.javaField != null }
	.forEach {
		it(obj)?.let { value ->
			append("${it.name} = $value")
		}
	}

```
