입력 (.proto 스키마)

출력 (Kotlin)

이 도구가 하는 일

Protocol Buffers 스키마가 있고 — 백엔드 팀에서 받았거나, 서드파티 API 계약에서 받았을 수도 있고 — 그에 맞는 타입화된 형태가 필요한 Kotlin 코드베이스가 있습니다. gRPC 백엔드를 호출하는 Android 앱이거나, JSON으로 인코딩된 Protobuf 메시지를 파싱하는 서버사이드 Kotlin입니다. data class 형태만 필요하다면 grpc-kotlin codegen 파이프라인을 통째로 셋업하는 것은 과합니다 — 붙여넣고, 복사하고, 떨어뜨리세요.

타입 매핑은 Kotlin 관용구를 따릅니다: stringString, boolBoolean, bytesByteArray, int32/sint32/fixed32Int, int64/sint64/fixed64Long, doubleDouble, floatFloat. repeated T는 기본값 emptyList()를 가진 List<T>가 되고, map<K, V>는 기본값 emptyMap()을 가진 Map<K, V>가 됩니다. 단일 중첩 메시지 필드는 기본값 null의 nullable(?)입니다 — proto3의 has-value 의미와 맞춰진 결과입니다.

필드 이름은 proto의 snake_case에서 Kotlin의 camelCase로 변환됩니다 (order_idorderId) — 공식 Kotlin 스타일에 따른 표준 Kotlin 코딩 컨벤션입니다. 클래스와 enum 이름은 PascalCase로 유지됩니다. 각 enum은 Int 백킹 값을 갖는 enum class가 됩니다. 변환은 전부 브라우저 안에서 실행됩니다 — 당신의 .proto는 페이지를 떠나지 않습니다.

사용법

세 단계. 출력은 바로 붙여넣을 수 있는 Kotlin입니다.

1

.proto 스키마를 붙여넣기

왼쪽 에디터에 스키마를 떨어뜨립니다. 상단의 syntax = "proto3";는 있어도 좋고 없어도 됩니다. 중첩된 message 블록, enum 선언, oneof, map<K, V>, 필드 옵션 모두 처리됩니다.

Kotlin 코드 컨벤션은 프로퍼티에 camelCase를 선호합니다 — 변환기가 그렇게 해줍니다. 원래의 snake_case 이름이 더 좋다면 (일부 직렬화 라이브러리는 필드 이름을 그대로 매칭합니다) 출력에서 찾기-바꾸기 하세요.

2

Kotlin 출력 읽기

오른쪽: 각 메시지는 모든 프로퍼티에 기본값을 가진 data class가 됩니다. 각 enum은 enum class(val value: Int)가 되어 wire 포맷을 라운드트립할 수 있습니다. 최상위 레벨만(중첩 없음) — 한 파일에 넣기도, 분할하기도 쉽습니다.

3

프로젝트에 연결하기

파일을 프로젝트에 떨어뜨리고 package 선언을 추가한 뒤 import 합니다. Android나 JVM에서 진짜 gRPC 코드를 쓰려면 결국 marshal 메서드와 스텁을 얻기 위해 grpc-kotlin codegen을 돌리고 싶을 겁니다. 이 출력은 타입화된 JSON 처리, 구조 스케치, 리뷰용입니다.

실제로 시간을 아껴주는 순간

백엔드 .proto에서 Android 타입 스케치하기

Android 앱이 gRPC 백엔드와 통신합니다. 백엔드 팀이 .proto를 소유합니다. 아직 codegen을 셋업하지 않고 view model을 타입화할 data class 형태가 필요합니다. 붙여넣고 Models.kt에 떨어뜨리면 타입화 끝입니다.

JSON 인코딩 Protobuf를 파싱하는 서버사이드 Kotlin

서버사이드 Kotlin(Ktor / Spring Boot)이 proto3 JSON 인코딩을 따르는 JSON을 소비합니다. 거기에 맞는 data class가 필요합니다. .proto를 붙여넣고, Kotlin 출력을 복사한 뒤 원하는 직렬화기에 꽂으세요.

Protobuf API 변경 리뷰

팀원이 메시지에 필드를 추가했습니다. 새 .proto를 붙여넣고 Kotlin 출력을 현재의 Models.kt와 diff 한 뒤, 전체 툴체인을 띄우지 않고도 초점이 맞춰진 리뷰를 남길 수 있습니다.

일회성 스크립트와 빠른 프로토타입

gRPC-gateway를 두드리는 50줄짜리 Kotlin 스크립트. 거기에 grpc-kotlin과 protoc를 셋업하는 건 과합니다. 여기서 data class를 생성해 떨어뜨리세요.

자주 묻는 질문

이게 protoc-gen-kotlin을 대체하나요?

아닙니다. 진짜 codegen은 marshal/unmarshal 메서드, 디스크립터, gRPC 스텁을 만듭니다. 이 도구는 data class 형태만 출력합니다. 프로덕션 gRPC 코드에는 grpc-kotlin을 돌리세요. 이건 스케치, JSON 파싱, 리뷰, 일회성 스크립트용입니다.

왜 단일 메시지 필드가 nullable인가요?

proto3에서 메시지 필드는 "has value" 의미를 가집니다 — 설정되지 않을 수 있습니다. 가장 깔끔한 Kotlin 대응은 기본값 null을 가진 nullable 프로퍼티입니다. 데이터가 항상 이 필드들을 채운다는 걸 알고 있다면 ?와 기본값을 빼세요 — 단순한 찾기-바꾸기입니다.

uint32와 uint64는 어떻게 처리되나요?

둘 다 부호 있는 타입(IntLong)으로 매핑됩니다. Kotlin은 1.5 이후 안정화된 UIntULong 타입을 가지지만, 부호 있는 타입이 기존 직렬화 라이브러리 및 대부분의 Android 코드베이스와의 호환성이 더 좋습니다. 부호 없는 변형이 꼭 필요하다면 출력에서 갈아끼우세요.

enum은 어떻게 출력되나요?

각각 enum class WithValue(val value: Int)가 되어 wire 포맷의 정수 값을 보존할 수 있습니다. 각 값은 원래의 proto 이름을 받습니다 (예: ORDER_STATUS_PENDING) — Kotlin enum 항목은 관례적으로 이미 SCREAMING_SNAKE_CASE이므로 잘 맞습니다.

필드 이름은 어떻게 변환되나요?

Kotlin 코딩 컨벤션에 따라 snake_casecamelCase. order_idorderId가 되고, customer_namecustomerName이 됩니다. 클래스와 enum 이름은 proto 그대로 PascalCase를 유지합니다.

중첩된 메시지를 처리하나요?

네 — 중첩된 message 블록은 출력에서 최상위 data class 선언으로 평탄화됩니다. 그러면 파일을 읽기 쉽고 여러 파일로 나누기도 쉬워집니다. Kotlin 중첩 클래스가 더 좋다면 직접 감싸 주세요.

관련 도구

Protobuf와 Kotlin으로 작업한다면, 이것들이 잘 어울립니다: