or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-message-api.mddescriptors-reflection.mdextensions.mdindex.mdjson-format.mdserialization-io.mdwell-known-types.md

extensions.mddocs/

0

# Extension System

1

2

Support for protocol buffer extensions allowing fields to be added to messages without modifying the original .proto files. This enables third-party extensibility and backwards-compatible schema evolution in the shaded akka.protobufv3.internal package.

3

4

## Capabilities

5

6

### Extension Class

7

8

Represents a protocol buffer extension with type-safe access to extended fields.

9

10

```java { .api }

11

/**

12

* Represents a protocol buffer extension.

13

* Provides type-safe access to extension fields in messages.

14

*/

15

class Extension<ContainingType extends ExtendableMessage<ContainingType>, Type> {

16

/** Get the field descriptor for this extension */

17

Descriptors.FieldDescriptor getDescriptor();

18

19

/** Get the message type that contains this extension */

20

Class<ContainingType> getContainingType();

21

22

/** Get the type of this extension's value */

23

Class<Type> getType();

24

25

/** Check if this extension has a default value */

26

boolean hasDefaultValue();

27

28

/** Get the default value for this extension */

29

Type getDefaultValue();

30

31

/** Check if this is a repeated extension */

32

boolean isRepeated();

33

34

/** Check if this extension is packed (for repeated numeric types) */

35

boolean isPacked();

36

37

/** Get the message type for message extensions */

38

Class<? extends Message> getMessageDefaultInstance();

39

}

40

```

41

42

### GeneratedExtension Class

43

44

Implementation of Extension for generated extension fields.

45

46

```java { .api }

47

/**

48

* Generated implementation of Extension for protocol buffer extensions

49

* created by the protocol compiler.

50

*/

51

static class GeneratedMessage.GeneratedExtension<ContainingType extends Message, Type>

52

extends Extension<ContainingType, Type> {

53

54

/** Get the field number for this extension */

55

int getNumber();

56

57

/** Get the wire type for this extension */

58

WireFormat.FieldType getLiteType();

59

60

/** Check if this extension is lite */

61

boolean isLite();

62

63

/** Create a new instance of the extension */

64

GeneratedExtension<ContainingType, Type> clone();

65

}

66

```

67

68

### ExtensionRegistry Class

69

70

Registry for protocol buffer extensions that enables parsing messages with extension fields.

71

72

```java { .api }

73

/**

74

* Registry for protocol buffer extensions.

75

* Required when parsing messages that contain extension fields.

76

*/

77

class ExtensionRegistry extends ExtensionRegistryLite {

78

/** Create a new mutable extension registry */

79

static ExtensionRegistry newInstance();

80

81

/** Get the empty extension registry */

82

static ExtensionRegistry getEmptyRegistry();

83

84

/** Add an extension to this registry */

85

void add(Extension<?, ?> extension);

86

87

/** Add an extension with explicit descriptor */

88

void add(Descriptors.FieldDescriptor type);

89

90

/** Add all extensions from another registry */

91

void addAll(ExtensionRegistry other);

92

93

/** Find extension by containing type and field number */

94

Extension<?, ?> findExtensionByNumber(Descriptors.Descriptor containingType, int fieldNumber);

95

96

/** Find immutable extension by field descriptor */

97

Extension<?, ?> findImmutableExtensionByName(String fullName);

98

99

/** Find mutable extension by field descriptor */

100

Extension<?, ?> findMutableExtensionByName(String fullName);

101

102

/** Get an unmodifiable view of this registry */

103

ExtensionRegistry getUnmodifiable();

104

105

/** Create a copy of this registry */

106

ExtensionRegistry clone();

107

}

108

```

109

110

### ExtensionRegistryLite Class

111

112

Lite version of extension registry with minimal functionality for resource-constrained environments.

113

114

```java { .api }

115

/**

116

* Lite version of extension registry with minimal functionality.

117

* Used when full extension support is not needed.

118

*/

119

class ExtensionRegistryLite {

120

/** Create a new mutable lite extension registry */

121

static ExtensionRegistryLite newInstance();

122

123

/** Get the empty lite extension registry */

124

static ExtensionRegistryLite getEmptyRegistry();

125

126

/** Add an extension to this registry */

127

void add(GeneratedMessageLite.GeneratedExtension<?, ?> extension);

128

129

/** Add a message extension to this registry */

130

<ContainingType extends MessageLite> void add(

131

GeneratedMessageLite.GeneratedExtension<ContainingType, ?> extension);

132

133

/** Find extension by containing type and field number */

134

GeneratedMessageLite.GeneratedExtension<?, ?> findLiteExtensionByNumber(

135

ExtendableMessageLite<?> containingTypeDefaultInstance, int fieldNumber);

136

137

/** Get an unmodifiable view of this registry */

138

ExtensionRegistryLite getUnmodifiable();

139

140

/** Create a copy of this registry */

141

ExtensionRegistryLite clone();

142

}

143

```

144

145

### ExtendableMessage Interface

146

147

Interface for messages that can be extended with additional fields.

148

149

```java { .api }

150

/**

151

* Interface for protocol buffer messages that support extensions.

152

* Provides methods to access and check extension fields.

153

*/

154

interface ExtendableMessage<MessageType extends ExtendableMessage<MessageType>>

155

extends Message {

156

157

/** Check if an extension field is set */

158

<Type> boolean hasExtension(Extension<MessageType, Type> extension);

159

160

/** Get the value of an extension field */

161

<Type> Type getExtension(Extension<MessageType, Type> extension);

162

163

/** Get the count of elements in a repeated extension field */

164

<Type> int getExtensionCount(Extension<MessageType, List<Type>> extension);

165

166

/** Get an element from a repeated extension field */

167

<Type> Type getExtension(Extension<MessageType, List<Type>> extension, int index);

168

169

/** Get all extension fields as a map */

170

Map<Descriptors.FieldDescriptor, Object> getAllExtensions();

171

172

/** ExtendableMessage builder interface */

173

interface Builder<MessageType extends ExtendableMessage<MessageType>,

174

BuilderType extends Builder<MessageType, BuilderType>>

175

extends Message.Builder {

176

177

/** Set the value of an extension field */

178

<Type> BuilderType setExtension(Extension<MessageType, Type> extension, Type value);

179

180

/** Add a value to a repeated extension field */

181

<Type> BuilderType addExtension(Extension<MessageType, List<Type>> extension, Type value);

182

183

/** Set an element in a repeated extension field */

184

<Type> BuilderType setExtension(Extension<MessageType, List<Type>> extension,

185

int index, Type value);

186

187

/** Clear an extension field */

188

<Type> BuilderType clearExtension(Extension<MessageType, Type> extension);

189

190

/** Check if an extension field is set */

191

<Type> boolean hasExtension(Extension<MessageType, Type> extension);

192

193

/** Get the value of an extension field */

194

<Type> Type getExtension(Extension<MessageType, Type> extension);

195

196

/** Get the count of elements in a repeated extension field */

197

<Type> int getExtensionCount(Extension<MessageType, List<Type>> extension);

198

199

/** Get an element from a repeated extension field */

200

<Type> Type getExtension(Extension<MessageType, List<Type>> extension, int index);

201

}

202

}

203

```

204

205

### ExtendableMessageLite Interface

206

207

Lite version of extendable message interface with minimal functionality.

208

209

```java { .api }

210

/**

211

* Lite version of extendable message interface.

212

* Provides basic extension support without full reflection capabilities.

213

*/

214

interface ExtendableMessageLite<MessageType extends ExtendableMessageLite<MessageType>>

215

extends MessageLite {

216

217

/** Check if an extension field is set */

218

<Type> boolean hasExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);

219

220

/** Get the value of an extension field */

221

<Type> Type getExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);

222

223

/** Get the count of elements in a repeated extension field */

224

<Type> int getExtensionCount(GeneratedMessageLite.GeneratedExtension<MessageType, List<Type>> extension);

225

226

/** Get an element from a repeated extension field */

227

<Type> Type getExtension(GeneratedMessageLite.GeneratedExtension<MessageType, List<Type>> extension,

228

int index);

229

230

/** ExtendableMessageLite builder interface */

231

interface Builder<MessageType extends ExtendableMessageLite<MessageType>,

232

BuilderType extends Builder<MessageType, BuilderType>>

233

extends MessageLite.Builder {

234

235

/** Set the value of an extension field */

236

<Type> BuilderType setExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension,

237

Type value);

238

239

/** Add a value to a repeated extension field */

240

<Type> BuilderType addExtension(GeneratedMessageLite.GeneratedExtension<MessageType, List<Type>> extension,

241

Type value);

242

243

/** Clear an extension field */

244

<Type> BuilderType clearExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);

245

246

/** Check if an extension field is set */

247

<Type> boolean hasExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);

248

249

/** Get the value of an extension field */

250

<Type> Type getExtension(GeneratedMessageLite.GeneratedExtension<MessageType, Type> extension);

251

}

252

}

253

```

254

255

## Usage Examples

256

257

### Defining Extensions

258

259

Extensions are typically defined in .proto files and generated as static fields:

260

261

```proto

262

// In your .proto file

263

extend MyMessage {

264

optional string custom_field = 1001;

265

repeated int32 custom_numbers = 1002;

266

}

267

```

268

269

The generated Java code would look like:

270

271

```java

272

// Generated extension fields (example)

273

// public static final Extension<MyMessage, String> customField =

274

// GeneratedMessage.newFileScopedGeneratedExtension(String.class, null);

275

//

276

// public static final Extension<MyMessage, List<Integer>> customNumbers =

277

// GeneratedMessage.newFileScopedGeneratedExtension(Integer.class, null);

278

```

279

280

### Using Extensions in Messages

281

282

```java

283

import akka.protobufv3.internal.*;

284

285

// Set extension fields in a message (assumes MyMessage and extensions exist)

286

// MyMessage message = MyMessage.newBuilder()

287

// .setExtension(MyExtensions.customField, "Hello Extension!")

288

// .addExtension(MyExtensions.customNumbers, 42)

289

// .addExtension(MyExtensions.customNumbers, 84)

290

// .build();

291

292

// Read extension fields

293

// boolean hasCustomField = message.hasExtension(MyExtensions.customField);

294

// if (hasCustomField) {

295

// String customValue = message.getExtension(MyExtensions.customField);

296

// System.out.println("Custom field: " + customValue);

297

// }

298

299

// Read repeated extension

300

// int count = message.getExtensionCount(MyExtensions.customNumbers);

301

// for (int i = 0; i < count; i++) {

302

// Integer number = message.getExtension(MyExtensions.customNumbers, i);

303

// System.out.println("Custom number " + i + ": " + number);

304

// }

305

```

306

307

### Working with Extension Registry

308

309

```java

310

import akka.protobufv3.internal.*;

311

312

// Create extension registry

313

ExtensionRegistry registry = ExtensionRegistry.newInstance();

314

315

// Add extensions to registry

316

// registry.add(MyExtensions.customField);

317

// registry.add(MyExtensions.customNumbers);

318

319

// Parse message with extensions

320

byte[] data = getMessageBytes();

321

try {

322

// MyMessage message = MyMessage.parseFrom(data, registry);

323

324

// Extensions will be properly parsed and accessible

325

// String customValue = message.getExtension(MyExtensions.customField);

326

} catch (InvalidProtocolBufferException e) {

327

System.err.println("Failed to parse message with extensions: " + e.getMessage());

328

}

329

```

330

331

### Dynamic Extension Access

332

333

```java

334

import akka.protobufv3.internal.*;

335

336

// Access extensions dynamically using descriptors

337

// MyMessage message = getMessageWithExtensions();

338

339

// Get all extension fields

340

Map<Descriptors.FieldDescriptor, Object> allExtensions = message.getAllExtensions();

341

for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : allExtensions.entrySet()) {

342

Descriptors.FieldDescriptor field = entry.getKey();

343

Object value = entry.getValue();

344

345

System.out.println("Extension field " + field.getName() +

346

" (number " + field.getNumber() + "): " + value);

347

}

348

349

// Find extension by field number

350

ExtensionRegistry registry = getExtensionRegistry();

351

Descriptors.Descriptor messageType = message.getDescriptorForType();

352

Extension<?, ?> extension = registry.findExtensionByNumber(messageType, 1001);

353

354

if (extension != null) {

355

System.out.println("Found extension: " + extension.getDescriptor().getName());

356

}

357

```

358

359

### Building Messages with Extensions

360

361

```java

362

import akka.protobufv3.internal.*;

363

364

// Create builder and set both regular and extension fields

365

// MyMessage.Builder builder = MyMessage.newBuilder();

366

367

// Set regular fields

368

// builder.setName("Regular Field");

369

// builder.setId(123);

370

371

// Set extension fields

372

// builder.setExtension(MyExtensions.customField, "Extension Value");

373

// builder.addExtension(MyExtensions.customNumbers, 1);

374

// builder.addExtension(MyExtensions.customNumbers, 2);

375

// builder.addExtension(MyExtensions.customNumbers, 3);

376

377

// Build the message

378

// MyMessage message = builder.build();

379

380

// Verify extensions are set

381

// System.out.println("Has custom field: " + message.hasExtension(MyExtensions.customField));

382

// System.out.println("Custom numbers count: " + message.getExtensionCount(MyExtensions.customNumbers));

383

```

384

385

### Clearing and Modifying Extensions

386

387

```java

388

import akka.protobufv3.internal.*;

389

390

// Start with a message that has extensions

391

// MyMessage original = getMessageWithExtensions();

392

393

// Create builder from existing message

394

// MyMessage.Builder builder = original.toBuilder();

395

396

// Clear specific extension

397

// builder.clearExtension(MyExtensions.customField);

398

399

// Modify repeated extension

400

// builder.setExtension(MyExtensions.customNumbers, 0, 999); // Set first element

401

// builder.addExtension(MyExtensions.customNumbers, 888); // Add new element

402

403

// Build modified message

404

// MyMessage modified = builder.build();

405

```

406

407

### Lite Extension Registry

408

409

```java

410

import akka.protobufv3.internal.*;

411

412

// For lite messages, use ExtensionRegistryLite

413

ExtensionRegistryLite liteRegistry = ExtensionRegistryLite.newInstance();

414

415

// Add lite extensions

416

// liteRegistry.add(MyLiteExtensions.customLiteField);

417

418

// Parse lite message with extensions

419

byte[] liteData = getLiteMessageBytes();

420

try {

421

// MyLiteMessage message = MyLiteMessage.parseFrom(liteData, liteRegistry);

422

423

// Access lite extensions

424

// String value = message.getExtension(MyLiteExtensions.customLiteField);

425

} catch (InvalidProtocolBufferException e) {

426

System.err.println("Failed to parse lite message: " + e.getMessage());

427

}

428

```

429

430

### Extension Registry Management

431

432

```java

433

import akka.protobufv3.internal.*;

434

435

// Create base registry

436

ExtensionRegistry baseRegistry = ExtensionRegistry.newInstance();

437

// baseRegistry.add(CommonExtensions.timestampField);

438

// baseRegistry.add(CommonExtensions.versionField);

439

440

// Create specialized registry

441

ExtensionRegistry specializedRegistry = ExtensionRegistry.newInstance();

442

// specializedRegistry.addAll(baseRegistry); // Include base extensions

443

// specializedRegistry.add(SpecialExtensions.debugField);

444

// specializedRegistry.add(SpecialExtensions.metadataField);

445

446

// Get unmodifiable view for safety

447

ExtensionRegistry readOnlyRegistry = specializedRegistry.getUnmodifiable();

448

449

// Use appropriate registry based on context

450

// if (isDebugMode()) {

451

// message = MyMessage.parseFrom(data, specializedRegistry);

452

// } else {

453

// message = MyMessage.parseFrom(data, baseRegistry);

454

// }

455

```

456

457

### Error Handling with Extensions

458

459

```java

460

import akka.protobufv3.internal.*;

461

462

try {

463

// Parse message without proper extension registry

464

byte[] data = getMessageWithExtensions();

465

// MyMessage message = MyMessage.parseFrom(data); // Extensions will be in unknown fields

466

467

// Access extension (will return default value)

468

// String customValue = message.getExtension(MyExtensions.customField);

469

// System.out.println("Custom value: " + customValue); // Will be default/empty

470

471

// Check unknown fields for unparsed extensions

472

UnknownFieldSet unknownFields = message.getUnknownFields();

473

if (!unknownFields.asMap().isEmpty()) {

474

System.out.println("Message has unknown fields (possibly extensions)");

475

}

476

477

} catch (InvalidProtocolBufferException e) {

478

System.err.println("Failed to parse message: " + e.getMessage());

479

}

480

```