What is Pbandk?
master.proto definitions, supporting all platforms compatible with Kotlin Multiplatform, including JVM, Android, iOS, macOS, Linux, Windows, JS, and Wasm.repository·master·Indexed 43 days ago
https://github.com/streem/pbandkA Kotlin Multiplatform (KMP) code generator and runtime for Protocol Buffers that generates idiomatic Kotlin data classes from .proto files. It supports proto2 and proto3 syntaxes, JSON serialization, and targets JVM, Android, iOS, macOS, Linux, Windows, JS, and Wasm. Pbandk uses protoc for code generation and provides a runtime library available on Maven Central.
.proto definitions, supporting all platforms compatible with Kotlin Multiplatform, including JVM, Android, iOS, macOS, Linux, Windows, JS, and Wasm.Pbandk is a Kotlin Multiplatform library, but support levels vary by platform:
mingwX64): Supported on a best-effort basis. While the runtime is available, full correctness cannot be guaranteed via official protobuf conformance tests on Windows, though it shares most code with Linux/macOS.js): Support is experimental. While using pbandk from other KMP code on JS is mostly stable, using it directly from Javascript/Typescript is not well supported due to @JsExport limitations.wasmJs): Support is experimental. Pbandk APIs and generated code can only be called from other Kotlin code compiled for Wasm; they cannot be called directly from Javascript or other Wasm host languages due to limitations in passing complex types to the Wasm host environment.Pbandk generates Kotlin data classes that implement the pbandk.Message interface. These classes represent Protobuf messages and include several key features:
data classes, making them easy to use with standard Kotlin features.Companion object that provides a defaultInstance and a decodeWith(u: pbandk.MessageDecoder) method for deserialization.sealed classes implementing pbandk.Message.Enum. They include a values list and helper methods like fromValue(value: Int) and fromName(name: String).unknownFields property of type Map<Int, pbandk.UnknownField> to preserve data that was not recognized during decoding.plus operator (operator fun plus(other: pbandk.Message?)) to allow merging two messages together.descriptor property of type pbandk.MessageDescriptor for runtime reflection and schema inspection.orDefault() extension functions (e.g., Person?.orDefault()) to safely handle nullable message instances by returning the defaultInstance if the receiver is null.// Example of a generated message structure
@pbandk.Export
public data class Person(
val name: String = "",
val id: Int = 0,
val email: String = "",
val phones: List<tutorial.Person.PhoneNumber> = emptyList(),
val lastUpdated: pbandk.wkt.Timestamp? = null,
override val unknownFields: Map<Int, pbandk.UnknownField> = emptyMap()
) : pbandk.Message {
override operator fun plus(other: pbandk.Message?): tutorial.Person = protoMergeImpl(other)
override val descriptor: pbandk.MessageDescriptor<tutorial.Person> get() = Companion.descriptor
// ...
public companion object : pbandk.Message.Companion<tutorial.Person> {
public val defaultInstance: tutorial.Person by lazy { tutorial.Person() }
override fun decodeWith(u: pbandk.MessageDecoder): tutorial.Person = Person.decodeWithImpl(u)
// ...
}
}Generated messages are immutable Kotlin data classes that extend pbandk.Message.
encodeToByteArray() on the instance and MessageName.Companion.decodeFromByteArray(byteArray) to deserialize.encodeToJsonString() and decodeFromJsonString() for Protobuf JSON encoding.encodeToStream(outputStream) and decodeFromStream(inputStream).equals, hashCode, and toString automatically.unknownFields map stores unrecognized fields. These are preserved and re-encoded during output. You can configure MessageDecoder to discard them if desired.plus operator is defined for messages to follow protobuf merge semantics.protoSize field lazily calculates the message size.bytes fields use a pbandk.ByteArr wrapper around ByteArray to ensure predictable behavior in Kotlin data classes.Pbandk maps Protobuf collection types to standard Kotlin collections:
repeated fields: Represented as standard Kotlin Lists. Do not assume a specific implementation (like ArrayList).map fields: Represented as standard Kotlin Maps.Note for proto2: In proto2, because of how map entries are serialized, both the key and the value are considered nullable.
Because Protobuf enums are open-ended (they can contain values not defined in the schema), Pbandk generates them as sealed classes rather than standard Kotlin enum classes.
object.Unrecognized nested class is provided to hold unknown values encountered during decoding.value (numeric) and a name (string).fromValue(int) or fromName(String) methods to map values to the sealed class instances.values field to get a list of all known enum values.when expressions, you must explicitly handle the Unrecognized case.Pbandk provides several features for working with Protocol Buffers in Kotlin:
proto2 and proto3 syntaxes.oneof fields are generated as Kotlin sealed classes.StringValue, BoolValue) which are mapped to nullable primitives (e.g., String?, Boolean?).deprecated protobuf option in generated code.The Browser JS example is organized into two sub-projects to manage dependencies correctly:
:lib-proto: This project runs the pbandk protobuf plugin on the .proto files. The generated code is added to the commonMain source set.:app: This is the main Kotlin/JS project that consumes the generated code.This separation is necessary because the Protobuf Gradle Plugin requires the java-library plugin, while the :app project is kept as a standard Kotlin Multiplatform project for easier maintenance.
Types imported from google/protobuf (Well-Known Types) are mapped to the pbandk.wkt package.
Pbandk provides specialized support for google.protobuf/wrappers.proto to map them into Kotlin nullable primitives. For example:
google.protobuf.StringValue $\rightarrow$ String?google.protobuf.Int32Value $\rightarrow$ Int?Pbandk uses Kotlin-idiomatic types to represent Protobuf's open-ended structures.
oneof fields are generated as nested classes within a common sealed base class.
oneof is a class wrapping a single value.oneof member. Accessing a field returns its value if that specific oneof case is set, otherwise it returns null.The browser-js example shows how to leverage pbandk in web environments using Kotlin's JavaScript integration. This is useful for projects targeting the JS runtime where you need to handle Protobuf data.
See the `examples/browser-js` directory for implementation details.The custom-service-gen example provides a pattern for extending pbandk by writing a custom code generator specifically for service definitions. This allows you to generate specialized logic or boilerplate beyond the standard message types.
See the `examples/custom-service-gen` directory for implementation details.