0
# Message Framework
1
2
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.
3
4
## Capabilities
5
6
### Message Base Class
7
8
Abstract base class for all protocol buffer messages providing encoding, unknown field management, and builder creation.
9
10
```kotlin { .api }
11
/**
12
* Abstract base class for protocol buffer messages
13
* @param M The message type
14
* @param B The builder type for this message
15
*/
16
expect abstract class Message<M : Message<M, B>, B : Message.Builder<M, B>> protected constructor(
17
adapter: ProtoAdapter<M>,
18
unknownFields: ByteString
19
) {
20
/** If non-zero, the hash code of this message */
21
protected var hashCode: Int
22
23
/** Returns unknown fields from proto encoding as ByteString */
24
val unknownFields: ByteString
25
26
/** The ProtoAdapter for encoding and decoding messages of this type */
27
val adapter: ProtoAdapter<M>
28
29
/** Returns a new builder initialized with the data in this message */
30
abstract fun newBuilder(): B
31
32
/** Encode this message and write it to stream */
33
fun encode(sink: BufferedSink)
34
35
/** Encode this message as a byte array */
36
fun encode(): ByteArray
37
38
/** Encode this message as a ByteString */
39
fun encodeByteString(): ByteString
40
}
41
```
42
43
**Usage Examples:**
44
45
```kotlin
46
import com.squareup.wire.*
47
import okio.Buffer
48
49
// Assuming generated Person class extends Message
50
val person = Person.Builder()
51
.name("Alice")
52
.age(30)
53
.build()
54
55
// Encode to different formats
56
val bytes: ByteArray = person.encode()
57
val byteString: ByteString = person.encodeByteString()
58
59
// Write to a buffered sink
60
val buffer = Buffer()
61
person.encode(buffer)
62
63
// Access unknown fields (for forward compatibility)
64
val unknownFields: ByteString = person.unknownFields
65
66
// Create a modified copy using builder
67
val updatedPerson = person.newBuilder()
68
.age(31)
69
.build()
70
```
71
72
### Message Builder
73
74
Abstract base class for message builders implementing the builder pattern for immutable message construction.
75
76
```kotlin { .api }
77
/**
78
* Superclass for protocol buffer message builders
79
* @param M The message type this builder creates
80
* @param B The builder type (self-reference for fluent interface)
81
*/
82
abstract class Message.Builder<M : Message<M, B>, B : Builder<M, B>> protected constructor() {
83
/** Cached unknown fields as ByteString */
84
internal var unknownFieldsByteString: ByteString
85
86
/** Buffer for unknown fields (lazily instantiated) */
87
internal var unknownFieldsBuffer: Buffer?
88
89
/** Writer for unknown fields */
90
internal var unknownFieldsWriter: ProtoWriter?
91
92
/** Add unknown fields from another message or source */
93
fun addUnknownFields(unknownFields: ByteString): Builder<M, B>
94
95
/** Add a single unknown field with specified encoding */
96
fun addUnknownField(
97
tag: Int,
98
fieldEncoding: FieldEncoding,
99
value: Any?
100
): Builder<M, B>
101
102
/** Clear all accumulated unknown fields */
103
fun clearUnknownFields(): Builder<M, B>
104
105
/** Build unknown fields to ByteString */
106
fun buildUnknownFields(): ByteString
107
108
/** Returns an immutable Message based on fields set in this builder */
109
abstract fun build(): M
110
}
111
```
112
113
**Usage Examples:**
114
115
```kotlin
116
import com.squareup.wire.*
117
118
// Create message using builder pattern
119
val person = Person.Builder()
120
.name("Bob")
121
.email("bob@example.com")
122
.age(25)
123
.build()
124
125
// Builder with unknown field handling
126
val builder = Person.Builder()
127
.name("Charlie")
128
129
// Add unknown fields (useful for proxy/gateway scenarios)
130
builder.addUnknownField(999, FieldEncoding.VARINT, 42)
131
builder.addUnknownField(998, FieldEncoding.LENGTH_DELIMITED, "custom_data")
132
133
val personWithUnknownFields = builder.build()
134
135
// Unknown fields are preserved when encoding/decoding
136
val encoded = personWithUnknownFields.encode()
137
val decoded = Person.ADAPTER.decode(encoded)
138
// decoded.unknownFields contains the unknown fields
139
140
// Clear unknown fields if needed
141
val cleanBuilder = decoded.newBuilder()
142
.clearUnknownFields()
143
val cleanPerson = cleanBuilder.build()
144
```
145
146
### Unknown Field Management
147
148
Wire Runtime preserves unknown fields to maintain forward compatibility when older clients receive messages with newer fields.
149
150
```kotlin { .api }
151
// Unknown fields are automatically preserved during decode/encode cycles
152
val messageWithUnknownFields = SomeMessage.ADAPTER.decode(bytesFromNewerVersion)
153
154
// Unknown fields are maintained
155
val reencoded = messageWithUnknownFields.encode()
156
// reencoded contains both known and unknown fields
157
158
// Access unknown fields directly
159
val unknownFieldsBytes: ByteString = messageWithUnknownFields.unknownFields
160
161
// Copy message while preserving unknown fields
162
val modified = messageWithUnknownFields.newBuilder()
163
.someKnownField("new value")
164
.build()
165
// modified.unknownFields still contains the unknown fields
166
```
167
168
## Builder Pattern Benefits
169
170
The builder pattern in Wire Runtime provides several advantages:
171
172
1. **Immutability**: Messages are immutable after construction
173
2. **Type Safety**: Compile-time validation of required fields
174
3. **Fluent Interface**: Chainable method calls for readable construction
175
4. **Unknown Field Preservation**: Automatic handling of forward compatibility
176
5. **Null Safety**: Kotlin's null safety integrated with optional fields
177
178
## Platform-Specific Implementations
179
180
The Message and Builder classes use Kotlin's `expect`/`actual` mechanism for multiplatform support:
181
182
- **JVM**: Full reflection-based implementation with Java interoperability
183
- **JavaScript**: Optimized for browser and Node.js environments
184
- **Native**: Compiled implementations for iOS, macOS, Linux, and Windows
185
- **Android**: Android-specific optimizations and Parcelable support