Add Companion Object Factory Methods to Kotlin Data Classes
Learn how to enhance generated Kotlin data classes with companion object factory methods for JSON parsing, validation, and default instances. Covers invoke operator and named constructors.
Detailed Explanation
Companion Objects in Kotlin Data Classes
After converting JSON to a Kotlin data class, you can enhance it with a companion object that provides factory methods, constants, and parsing utilities.
Basic Data Class from JSON
{
"latitude": 37.7749,
"longitude": -122.4194,
"label": "San Francisco"
}
data class Location(
val latitude: Double,
val longitude: Double,
val label: String
) {
companion object {
val ORIGIN = Location(0.0, 0.0, "Origin")
fun fromJson(jsonString: String): Location =
Json.decodeFromString(jsonString)
fun parse(lat: String, lng: String, label: String = "Unknown"): Location =
Location(lat.toDouble(), lng.toDouble(), label)
}
}
Usage
val sf = Location.fromJson(jsonString)
val origin = Location.ORIGIN
val parsed = Location.parse("40.7128", "-74.0060", "New York")
Factory Method Patterns
Validation factory:
companion object {
fun create(lat: Double, lng: Double, label: String): Location {
require(lat in -90.0..90.0) { "Invalid latitude" }
require(lng in -180.0..180.0) { "Invalid longitude" }
return Location(lat, lng, label)
}
}
Default instance:
companion object {
val DEFAULT = Location(0.0, 0.0, "Unknown")
val EMPTY = Location(0.0, 0.0, "")
}
The invoke Operator
companion object {
operator fun invoke(jsonString: String): Location =
Json.decodeFromString(jsonString)
}
// Looks like a constructor call:
val location = Location(jsonString)
Why Companion Objects?
- Encapsulation -- parsing logic lives with the data class, not scattered across the codebase
- Named constructors --
Location.fromJson(),Location.fromCsv(),Location.fromDatabase() - Constants -- shared instances like
EMPTYandDEFAULTavoid re-allocation - Interop -- companion objects compile to Java static methods via
@JvmStatic
Companion Object with Serialization
@Serializable
data class Config(
val apiUrl: String,
val timeout: Int,
val retries: Int
) {
companion object {
val DEFAULT = Config(
apiUrl = "https://api.example.com",
timeout = 30,
retries = 3
)
}
}
This pairs JSON deserialization with sensible defaults, useful for configuration objects that may partially exist in the JSON payload.
Use Case
In Android development, companion objects on data classes provide clean factory methods for creating instances from JSON, database cursors, or Intent bundles. This pattern centralizes construction logic and makes unit testing straightforward.
Try It — JSON to Kotlin
Related Topics
Convert Simple JSON to a Kotlin Data Class
Basic Data Classes
Use Default Values in Kotlin Data Classes for Missing JSON Fields
Serialization
Kotlin Serialization Annotations for JSON Mapping
Serialization
Map JSON String Values to Kotlin Enum Classes
Advanced Patterns
Model Polymorphic JSON with Kotlin Sealed Classes
Advanced Patterns