CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-squareup-wire--wire-runtime

Runtime support library for Wire-generated Protocol Buffer classes in Kotlin multiplatform applications

Pending
Overview
Eval results
Files

message-framework.mddocs/

Message Framework

The Message Framework provides the foundational classes for all Wire-generated protocol buffer messages. It implements the builder pattern for immutable message construction and handles unknown field preservation for forward compatibility.

Capabilities

Message Base Class

Abstract base class for all protocol buffer messages providing encoding, unknown field management, and builder creation.

/**
 * Abstract base class for protocol buffer messages
 * @param M The message type
 * @param B The builder type for this message
 */
expect abstract class Message<M : Message<M, B>, B : Message.Builder<M, B>> protected constructor(
    adapter: ProtoAdapter<M>,
    unknownFields: ByteString
) {
    /** If non-zero, the hash code of this message */
    protected var hashCode: Int
    
    /** Returns unknown fields from proto encoding as ByteString */
    val unknownFields: ByteString
    
    /** The ProtoAdapter for encoding and decoding messages of this type */
    val adapter: ProtoAdapter<M>
    
    /** Returns a new builder initialized with the data in this message */
    abstract fun newBuilder(): B
    
    /** Encode this message and write it to stream */
    fun encode(sink: BufferedSink)
    
    /** Encode this message as a byte array */
    fun encode(): ByteArray
    
    /** Encode this message as a ByteString */
    fun encodeByteString(): ByteString
}

Usage Examples:

import com.squareup.wire.*
import okio.Buffer

// Assuming generated Person class extends Message
val person = Person.Builder()
    .name("Alice")
    .age(30)
    .build()

// Encode to different formats
val bytes: ByteArray = person.encode()
val byteString: ByteString = person.encodeByteString()

// Write to a buffered sink
val buffer = Buffer()
person.encode(buffer)

// Access unknown fields (for forward compatibility)
val unknownFields: ByteString = person.unknownFields

// Create a modified copy using builder
val updatedPerson = person.newBuilder()
    .age(31)
    .build()

Message Builder

Abstract base class for message builders implementing the builder pattern for immutable message construction.

/**
 * Superclass for protocol buffer message builders
 * @param M The message type this builder creates
 * @param B The builder type (self-reference for fluent interface)
 */
abstract class Message.Builder<M : Message<M, B>, B : Builder<M, B>> protected constructor() {
    /** Cached unknown fields as ByteString */
    internal var unknownFieldsByteString: ByteString
    
    /** Buffer for unknown fields (lazily instantiated) */
    internal var unknownFieldsBuffer: Buffer?
    
    /** Writer for unknown fields */
    internal var unknownFieldsWriter: ProtoWriter?
    
    /** Add unknown fields from another message or source */
    fun addUnknownFields(unknownFields: ByteString): Builder<M, B>
    
    /** Add a single unknown field with specified encoding */
    fun addUnknownField(
        tag: Int,
        fieldEncoding: FieldEncoding,
        value: Any?
    ): Builder<M, B>
    
    /** Clear all accumulated unknown fields */
    fun clearUnknownFields(): Builder<M, B>
    
    /** Build unknown fields to ByteString */
    fun buildUnknownFields(): ByteString
    
    /** Returns an immutable Message based on fields set in this builder */
    abstract fun build(): M
}

Usage Examples:

import com.squareup.wire.*

// Create message using builder pattern
val person = Person.Builder()
    .name("Bob")
    .email("bob@example.com")
    .age(25)
    .build()

// Builder with unknown field handling
val builder = Person.Builder()
    .name("Charlie")
    
// Add unknown fields (useful for proxy/gateway scenarios)
builder.addUnknownField(999, FieldEncoding.VARINT, 42)
builder.addUnknownField(998, FieldEncoding.LENGTH_DELIMITED, "custom_data")

val personWithUnknownFields = builder.build()

// Unknown fields are preserved when encoding/decoding
val encoded = personWithUnknownFields.encode()
val decoded = Person.ADAPTER.decode(encoded)
// decoded.unknownFields contains the unknown fields

// Clear unknown fields if needed
val cleanBuilder = decoded.newBuilder()
    .clearUnknownFields()
val cleanPerson = cleanBuilder.build()

Unknown Field Management

Wire Runtime preserves unknown fields to maintain forward compatibility when older clients receive messages with newer fields.

// Unknown fields are automatically preserved during decode/encode cycles
val messageWithUnknownFields = SomeMessage.ADAPTER.decode(bytesFromNewerVersion)

// Unknown fields are maintained
val reencoded = messageWithUnknownFields.encode()
// reencoded contains both known and unknown fields

// Access unknown fields directly
val unknownFieldsBytes: ByteString = messageWithUnknownFields.unknownFields

// Copy message while preserving unknown fields
val modified = messageWithUnknownFields.newBuilder()
    .someKnownField("new value")
    .build()
// modified.unknownFields still contains the unknown fields

Builder Pattern Benefits

The builder pattern in Wire Runtime provides several advantages:

  1. Immutability: Messages are immutable after construction
  2. Type Safety: Compile-time validation of required fields
  3. Fluent Interface: Chainable method calls for readable construction
  4. Unknown Field Preservation: Automatic handling of forward compatibility
  5. Null Safety: Kotlin's null safety integrated with optional fields

Platform-Specific Implementations

The Message and Builder classes use Kotlin's expect/actual mechanism for multiplatform support:

  • JVM: Full reflection-based implementation with Java interoperability
  • JavaScript: Optimized for browser and Node.js environments
  • Native: Compiled implementations for iOS, macOS, Linux, and Windows
  • Android: Android-specific optimizations and Parcelable support

Install with Tessl CLI

npx tessl i tessl/maven-com-squareup-wire--wire-runtime

docs

any-message.md

enum-support.md

field-annotations.md

index.md

message-framework.md

proto-adapters.md

protobuf-io.md

time-types.md

tile.json