MYMONDAY.ai
서비스스튜디오도구데이터·포맷73CSS 생성기19색상·이미지10인코딩·보안10웹·SEO11개발·데브옵스10파일·내보내기18계산기6가이드

JSON to Kotlin data class 변환기

JSON 객체나 배열을 선택 키가 null 기본값을 가진 nullable 프로퍼티가 되는 @Serializable Kotlin data class로 바꿉니다.

  • 브라우저에서 처리
  • 가입 없음
  • 무료

도구 작업 공간

예제

옵션

JSON 입력

27줄435byte

결과

⌘/Ctrl + Enter로 복사
결과 · Payload.kt
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement

@Serializable
data class Payload(
    val id: Long,
    val status: String,
    val customer: PayloadCustomer,
    val items: List<PayloadItem>,
    val total: Double,
    @SerialName("shipped_at") val shippedAt: String,
    val tracking: JsonElement? = null,
)

@Serializable
data class PayloadCustomer(
    val id: Long,
    val name: String,
    val email: String,
    val vip: Boolean,
)

@Serializable
data class PayloadItem(
    val sku: String,
    val name: String,
    val qty: Long,
    val price: Double,
)
타입3
크기647byte

이 JSON to Kotlin 변환기는 샘플 JSON 값을 읽어 kotlinx.serialization용 @Serializable data class 선언을 작성합니다. 중첩 객체는 각각 별도 클래스가 되고, 키는 camelCase val 프로퍼티가 되며, Kotlin 이름이 JSON 키와 다를 때마다 @SerialName("original_key")가 붙습니다. 배열은 List<T>가 되고, 파일에는 세미콜론도 java.util import도 없습니다.

배열은 모든 요소를 읽습니다. 같은 위치의 객체를 키의 합집합을 가진 클래스 하나로 병합하고, 일부 요소에 없거나 일부에서 null인 키는 = null이 붙은 nullable 프로퍼티가 됩니다. 한 키에서 서로 맞지 않는 타입이 나오면 JsonElement입니다. 루트는 객체 또는 배열이며, 배열 루트는 typealias로 작성됩니다.

입력은 브라우저에서 처리되고 업로드되지 않습니다. 입력 한도는 20 MiB입니다. 페이지에는 루트 타입 이름, 패키지, kotlinx.serialization 어노테이션 옵션이 있고, 내려받는 파일은 루트 이름을 따라 기본값 Payload.kt입니다.

사용 방법

  1. JSON 객체 또는 배열 붙여 넣기

    페이로드를 입력창에 붙여 넣거나 예제(API 응답, 중첩 배열, 엣지 케이스)를 불러옵니다. 최상위에 문자열이나 null 같은 단독 값이 오면 오류로 알려 줍니다.

  2. 옵션 설정

    루트 타입 이름(기본 Payload)과 패키지(기본은 비어 있어 package 줄이 없음)를 입력하고, kotlinx.serialization 어노테이션을 켜거나 끕니다. 끄면 일반 data class가 나오고 JsonElement 대신 Any가 쓰입니다.

  3. 클래스 읽기

    패키지 줄과 import가 먼저 나오고, 루트 클래스, 그다음 중첩 클래스가 처음 만난 순서대로 이어집니다. 루트가 배열이면 첫 선언이 typealias Payload = List<PayloadItem>입니다.

  4. import 확인

    어노테이션이 켜져 있고 출력에 클래스가 하나 이상 있으면 Serializable을 import합니다. 클래스 없는 배열 typealias에는 어노테이션과 import가 필요 없습니다. SerialName과 JsonElement는 이름이 바뀐 프로퍼티나 알 수 없는 타입이 있을 때만 나옵니다.

  5. 복사하거나 .kt로 저장

    출력을 복사하거나 루트 클래스 이름을 딴 파일(기본 Payload.kt)로 내려받고, 모듈에 kotlinx-serialization Gradle 플러그인을 추가합니다.

작동 원리

JSON과 Kotlin 타입 대응

도구는 같은 위치의 값을 병합합니다. 절댓값 2^63 미만인 정수 표기는 Long, 소수점·지수 표기와 소수 값 및 2^63 이상의 정수는 Double입니다. nullable 또는 선택 프로퍼티에는 ?와 = null이 붙습니다.

JSON 값Kotlin 타입비고
문자열String
true / falseBoolean
2^63 미만의 정수 표기LongInt는 쓰지 않음
소수가 있는 숫자Double[1, 2.5]는 List<Double>
모든 샘플에서 nullJsonElement?= null과 함께 작성, 어노테이션을 끄면 Any?
일부 요소에서 null이거나 없음T? = null예: String? = null, Long? = null
객체@Serializable data class키가 없는 객체는 일반 @Serializable class
배열List<T>중첩 배열은 List<List<Long>>, null이 섞이면 List<Long?>
빈 배열List<JsonElement>참고할 요소가 없음
같은 위치에 서로 다른 형태JsonElement[1, "a"]는 List<JsonElement>

이름 규칙

프로퍼티 이름은 camelCase 경계와 영문·숫자가 아닌 문자에서 단어를 나눠 lowerCamelCase로 잇습니다. first_name은 firstName입니다. 숫자로 시작하면 field 접두사가 붙습니다. 변환기 목록의 class, in, object, val, when 같은 예약어에는 밑줄이 붙지만 data, field, it는 그대로 유지됩니다.

두 키가 같은 프로퍼티 이름이 되면 두 번째에 2부터 숫자 접미사가 붙고, 두 이름 모두 키와 달라지므로 둘 다 @SerialName을 받습니다. 클래스 이름도 같은 규칙을 따르며, 리스트 요소 클래스는 키의 단수형을 씁니다. items는 PayloadItem, data는 PayloadDataItem입니다.

@SerialName("user_id") val userId: Long,
@SerialName("userId") val userId2: Long,
val qty: Long? = null

kotlinx.serialization으로 디코딩

org.jetbrains.kotlin.plugin.serialization Gradle 플러그인을 적용하고 Json.decodeFromString<Payload>(text)를 호출합니다. 알 수 없는 키는 Json { ignoreUnknownKeys = true }를 설정하지 않으면 오류가 나고, 기본값 없는 프로퍼티의 키가 없을 때도 실패합니다. 그래서 선택 키에 = null이 붙어 있습니다. 파라미터 목록 끝의 쉼표는 Kotlin 1.4부터 허용됩니다.

JsonElement는 임의의 JSON을 담으므로 이 타입의 필드에는 숫자, 문자열, 객체, null이 들어올 수 있고 jsonPrimitive나 jsonObject로 확인합니다. 따옴표로 감싼 큰 ID는 직접 String으로 두세요.

실제 예시

문자열 리스트가 있는 중첩 객체
입력
{"id":42,"user":{"name":"Ada","active":true},"roles":["admin","editor"]}
출력
import kotlinx.serialization.Serializable

@Serializable
data class Payload(
    val id: Long,
    val user: PayloadUser,
    val roles: List<String>,
)

@Serializable
data class PayloadUser(
    val name: String,
    val active: Boolean,
)

각 객체가 @Serializable data class가 됩니다. 루트 클래스가 먼저 나오고 중첩 클래스가 뒤따릅니다. 모든 이름이 키와 같아서 SerialName이 필요 없습니다.

이름이 바뀐 프로퍼티와 @SerialName
입력
{"user_id":7,"userId":8,"class":"A","2fa":true,"user-agent":"curl"}
출력
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class Payload(
    @SerialName("user_id") val userId: Long,
    @SerialName("userId") val userId2: Long,
    @SerialName("class") val class_: String,
    @SerialName("2fa") val field2fa: Boolean,
    @SerialName("user-agent") val userAgent: String,
)

Kotlin 이름이 키와 다르면 @SerialName이 키를 유지합니다. class에는 밑줄이 붙고, 2fa는 field2fa가 되며, 충돌한 userId에는 2가 붙습니다.

null, 빈 배열, 혼합 배열
입력
{"deleted_at":null,"tags":[],"scores":[1,null,3],"mixed":[1,"a"],"nums":[1,2.5]}
출력
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement

@Serializable
data class Payload(
    @SerialName("deleted_at") val deletedAt: JsonElement? = null,
    val tags: List<JsonElement>,
    val scores: List<Long?>,
    val mixed: List<JsonElement>,
    val nums: List<Double>,
)

null뿐인 위치, 빈 배열, 혼합 배열은 JsonElement입니다. 같은 타입 사이에 null이 있는 리스트는 타입을 유지해 List<Long?>가 되고, [1, 2.5]는 List<Double>로 합쳐집니다.

키가 서로 다른 객체 배열
입력
{"users":[{"id":1,"name":"Ada"},{"id":2,"email":"b@x.io","name":null}]}
출력
import kotlinx.serialization.Serializable

@Serializable
data class Payload(
    val users: List<PayloadUser>,
)

@Serializable
data class PayloadUser(
    val id: Long,
    val name: String? = null,
    val email: String? = null,
)

email은 두 번째 사용자에만 있고 name은 거기서 null이라 둘 다 = null이 붙은 nullable이 됩니다. id는 둘 다 있어 Long으로 남습니다.

어노테이션 없는 배열 루트
입력
[{"id":1},{"id":2,"label":"x"}]
출력
package com.acme.model

typealias Tags = List<Tag>

data class Tag(
    val id: Long,
    val label: String? = null,
)

옵션: 루트 타입 이름 Tags, 패키지 com.acme.model, kotlinx.serialization 어노테이션 끔. 배열 루트는 typealias와 요소 클래스 Tag이 되고, 선택 필드 label은 String? = null입니다.

자주 하는 실수

  • 샘플 하나로는 항상 있는 필드인지 알 수 없습니다

    붙여 넣은 요소 중 키가 없거나 null인 것이 있을 때만 nullable이 됩니다. 레코드가 하나뿐이면 모든 프로퍼티가 필수이고, 하나라도 빠진 응답이 오면 kotlinx.serialization이 예외를 던집니다. 값이 빠진 레코드를 포함해 여러 개를 붙여 넣으세요.

  • 2^63 미만의 정수 표기는 Long입니다

    작은 카운터를 포함해 2^63 미만인 정수 표기는 Long, 2^63 이상은 Double입니다. 2^53을 넘는 값은 반올림될 수 있으므로 정확한 ID는 문자열로 입력하고 모델에서 String으로 다루세요.

  • null뿐인 필드에는 타입 정보가 없습니다

    붙여 넣은 모든 레코드에서 null인 키는 JsonElement? = null이 되고 빈 리스트는 List<JsonElement>가 됩니다. 실제 타입을 알게 되면 String?이나 구체 클래스로 바꾸세요.

  • 어노테이션을 끄면 import만 바뀌지 않습니다

    kotlinx.serialization 옵션을 끄면 클래스에서 @Serializable과 @SerialName이 빠지고, 알 수 없는 값은 Any가 되며, 이름이 바뀐 키는 더 이상 매핑되지 않습니다. Gson이나 Moshi용으로 쓸 때는 그쪽 어노테이션을 직접 추가해야 합니다.

  • 알 수 없는 키는 여전히 디코딩 오류를 냅니다

    생성된 클래스에는 샘플에서 본 키만 있습니다. 나중에 API가 필드를 추가하면 ignoreUnknownKeys = true를 설정하지 않은 한 Json.decodeFromString이 예외를 던집니다.

  • 목록에 있는 예약어에만 밑줄이 붙습니다

    class 같은 키는 @SerialName("class")와 함께 class_가 됩니다. data, field, it 같은 일반 식별자는 그대로 유지되며, 이름이 충돌할 때만 숫자 접미사가 붙습니다.

자주 묻는 질문

kotlinx.serialization을 쓰나요, Gson이나 Moshi를 쓰나요?

kotlinx.serialization의 @Serializable과 @SerialName을 씁니다. Gson이나 Moshi를 쓰려면 옵션을 끄고 @SerializedName이나 @Json을 직접 추가하세요.

배열의 모든 요소를 읽나요?

네. 같은 위치의 객체를 키의 합집합을 가진 클래스 하나로 병합합니다. 일부 요소에 없는 키는 T? = null이 되고, 값의 타입이 서로 다르면 JsonElement가 됩니다.

숫자가 Int가 아니라 Long인 이유는 무엇인가요?

절댓값 2^63 미만인 정수 표기는 Long입니다. 소수점·지수 표기와 소수 값 및 2^63 이상의 정수는 Double입니다.

null 값은 어떤 타입이 되나요?

다른 값과 함께 나온 null은 String? = null처럼 null 기본값이 있는 nullable 타입이 됩니다. 항상 null인 키는 JsonElement? = null입니다.

Kotlin 키워드인 키는 어떻게 되나요?

뒤에 밑줄이 붙어 class_처럼 되고 @SerialName("class")가 키를 되돌립니다. 어노테이션 옵션이 켜져 있어야 합니다.

루트 클래스 이름과 패키지를 바꿀 수 있나요?

네. 루트 타입 이름이 루트 클래스나 typealias와 파일 이름을 정하고, 패키지는 package 줄을 추가합니다. 중첩 클래스 이름은 루트 이름에서 만들어집니다.

JSON이 업로드되나요?

아니요. 변환은 브라우저에서 실행되며 입력 한도는 20 MiB입니다.

마지막 업데이트: