Kotlin Data Class vs Regular Class for JSON Models

Understand when to use data class vs regular class for JSON models in Kotlin. Covers generated methods, equality semantics, inheritance limitations, and mutable vs immutable patterns.

Real-World Patterns

Detailed Explanation

Data Class vs Regular Class for JSON

The converter generates data class by default, but sometimes a regular class is more appropriate. Understanding the differences helps you make the right choice.

What Data Class Gives You

data class User(val id: Int, val name: String, val email: String)

// Auto-generated:
// - equals() / hashCode() based on all properties
// - toString() -> "User(id=1, name=Alice, email=alice@example.com)"
// - copy() -> user.copy(name = "Bob")
// - componentN() -> val (id, name, email) = user

When Data Class Is Better

  • Immutable value objects -- most JSON models are read-only after deserialization
  • Comparison by value -- two users with the same fields are equal
  • Debugging -- meaningful toString() output
  • Pattern matching -- destructuring in when expressions and let blocks

When Regular Class Is Better

Inheritance required:

// Data classes cannot be abstract or open
open class BaseModel(
    open val id: Int,
    open val createdAt: String
)

class User(
    override val id: Int,
    override val createdAt: String,
    val name: String
) : BaseModel(id, createdAt)

Mutable state:

class MutableUser(
    var id: Int,
    var name: String,
    var email: String
) {
    fun updateFrom(json: JsonObject) {
        json["name"]?.jsonPrimitive?.content?.let { name = it }
    }
}

Custom equality:

class Entity(val id: Int, val name: String, val version: Int) {
    // Equality based only on id, not all fields
    override fun equals(other: Any?) =
        other is Entity && id == other.id
    override fun hashCode() = id.hashCode()
}

Comparison Table

Feature data class class
Auto equals/hashCode Yes (all props) No (identity)
Auto toString Yes No
copy() Yes No
Destructuring Yes No
Inheritance Limited Full
Mutable properties Possible but discouraged Natural

Best Practice for JSON Models

  1. Start with data class -- it is correct for 90% of JSON models
  2. Switch to class when you need inheritance hierarchies or identity-based equality
  3. Use sealed classes for polymorphic JSON (not regular inheritance)
  4. Keep data classes immutable -- use val not var, use copy() for modifications

Value Class for Single-Field Wrappers

@JvmInline
value class UserId(val value: Int)

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

Value classes add type safety without runtime overhead, useful for wrapping primitive ID fields to prevent mixing up user IDs and order IDs.

Use Case

When designing the model layer for an Android MVVM architecture or a Kotlin backend service, choosing between data class and regular class affects testability, debugging, and maintenance. Data classes are the correct default for JSON DTOs, with regular classes reserved for stateful entities.

Try It — JSON to Kotlin

Open full tool