Runtime support library for Wire-generated Protocol Buffer classes in Kotlin multiplatform applications
—
Support for google.protobuf.Any messages allowing type-safe packing and unpacking of arbitrary protocol buffer messages. AnyMessage provides a way to embed any message type within another message.
Wire implementation of google.protobuf.Any for wrapping arbitrary protobuf messages.
/**
* Wire implementation of google.protobuf.Any type
* @param typeUrl Type identifier (e.g., "type.googleapis.com/package.MessageName")
* @param value Serialized message data
*/
class AnyMessage(
val typeUrl: String,
val value: ByteString = ByteString.EMPTY
) : Message<AnyMessage, Nothing> {
/** Unpack to specific type, throws if type mismatch */
fun <T> unpack(adapter: ProtoAdapter<T>): T
/** Unpack to specific type, returns null if type mismatch */
fun <T> unpackOrNull(adapter: ProtoAdapter<T>): T?
/** Create copy with modified fields */
fun copy(
typeUrl: String = this.typeUrl,
value: ByteString = this.value
): AnyMessage
companion object {
/** Pack any message into AnyMessage */
fun pack(message: Message<*, *>): AnyMessage
/** Built-in adapter for AnyMessage */
@JvmField
val ADAPTER: ProtoAdapter<AnyMessage>
}
}Usage Examples:
import com.squareup.wire.*
// Create messages to pack
val person = Person.Builder()
.name("Alice")
.age(30)
.build()
val address = Address.Builder()
.street("123 Main St")
.city("Springfield")
.build()
// Pack messages into Any
val anyPerson: AnyMessage = AnyMessage.pack(person)
val anyAddress: AnyMessage = AnyMessage.pack(address)
println(anyPerson.typeUrl) // "type.googleapis.com/com.example.Person"
println(anyAddress.typeUrl) // "type.googleapis.com/com.example.Address"
// Unpack with type checking
val unpackedPerson: Person = anyPerson.unpack(Person.ADAPTER)
val unpackedAddress: Address = anyAddress.unpack(Address.ADAPTER)
// Safe unpacking (returns null if type mismatch)
val maybePerson: Person? = anyAddress.unpackOrNull(Person.ADAPTER) // null
val maybeAddress: Address? = anyAddress.unpackOrNull(Address.ADAPTER) // Address instance
// Type mismatch throws exception
try {
val wrongType: Address = anyPerson.unpack(Address.ADAPTER)
} catch (e: IllegalStateException) {
println("Type mismatch: ${e.message}")
}
// Use in container messages
class Container(
@field:WireField(tag = 1, adapter = "com.squareup.wire.AnyMessage#ADAPTER")
val payload: AnyMessage?,
unknownFields: ByteString = ByteString.EMPTY
) : Message<Container, Container.Builder>(ADAPTER, unknownFields) {
// Helper methods for type-safe access
fun getPersonPayload(): Person? = payload?.unpackOrNull(Person.ADAPTER)
fun getAddressPayload(): Address? = payload?.unpackOrNull(Address.ADAPTER)
}
// Create container with different payload types
val containerWithPerson = Container.Builder()
.payload(AnyMessage.pack(person))
.build()
val containerWithAddress = Container.Builder()
.payload(AnyMessage.pack(address))
.build()
// Process containers generically
fun processContainer(container: Container) {
val payload = container.payload ?: return
when {
payload.typeUrl.endsWith("Person") -> {
val person = payload.unpack(Person.ADAPTER)
println("Processing person: ${person.name}")
}
payload.typeUrl.endsWith("Address") -> {
val address = payload.unpack(Address.ADAPTER)
println("Processing address: ${address.street}")
}
else -> {
println("Unknown payload type: ${payload.typeUrl}")
}
}
}Type URLs follow the format: type.googleapis.com/package.MessageName
type.googleapis.com for Google typesWire automatically generates appropriate type URLs for all messages with typeUrl support.
Install with Tessl CLI
npx tessl i tessl/maven-com-squareup-wire--wire-runtime