or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdcustom-serialization.mdfield-access.mdindex.mdpolymorphic-schemas.mdruntime-environment.mdschema-generation.mdtype-strategy.md

annotations.mddocs/

0

# Annotation-Based Configuration

1

2

Field-level configuration annotations for controlling serialization behavior, field numbers, and exclusions. These annotations provide a declarative way to customize how protostuff-runtime handles individual fields and classes during schema generation and serialization.

3

4

## Capabilities

5

6

### @Tag Annotation

7

8

Primary annotation for configuring field serialization behavior, field numbers, and field-level options.

9

10

```java { .api }

11

/**

12

* Annotation for configuring field serialization behavior

13

* Controls field numbers, aliases, and group filtering

14

*/

15

@Target(ElementType.FIELD)

16

@Retention(RetentionPolicy.RUNTIME)

17

public @interface Tag {

18

19

/**

20

* The field number to use in the protobuf wire format

21

* Must be unique within the message and in range [1, 2^29-1]

22

* @return field number

23

*/

24

int value();

25

26

/**

27

* Optional alias for the field name

28

* If specified, this name will be used instead of the Java field name

29

* @return field alias or empty string for default

30

*/

31

String alias() default "";

32

33

/**

34

* Group filter for conditional field processing

35

* Fields with the same group filter can be processed together

36

* @return group filter value, 0 for no filtering

37

*/

38

int groupFilter() default 0;

39

}

40

```

41

42

### @Exclude Annotation

43

44

Annotation to mark fields that should be ignored during serialization and schema generation.

45

46

```java { .api }

47

/**

48

* Annotation to exclude fields from serialization

49

* Fields marked with @Exclude will not be included in the schema

50

*/

51

@Target(ElementType.FIELD)

52

@Retention(RetentionPolicy.RUNTIME)

53

public @interface Exclude {

54

// Marker annotation - no parameters

55

}

56

```

57

58

### @Morph Annotation

59

60

Annotation for controlling polymorphic behavior of fields and types.

61

62

```java { .api }

63

/**

64

* Annotation for controlling polymorphic morphing behavior

65

* Affects how non-final POJOs and interfaces are handled

66

*/

67

@Target({ElementType.FIELD, ElementType.TYPE})

68

@Retention(RetentionPolicy.RUNTIME)

69

public @interface Morph {

70

71

/**

72

* Whether to enable morphing for this field or type

73

* @return true to enable morphing, false to disable

74

*/

75

boolean value() default true;

76

}

77

```

78

79

## Usage Examples

80

81

### Basic Field Tagging

82

83

```java

84

import io.protostuff.Tag;

85

import io.protostuff.Exclude;

86

87

/**

88

* User class with explicit field numbering

89

*/

90

public class User {

91

92

@Tag(1)

93

public String name;

94

95

@Tag(2)

96

public int age;

97

98

@Tag(3)

99

public String email;

100

101

@Tag(4)

102

public boolean active;

103

104

// This field will not be serialized

105

@Exclude

106

public String password;

107

108

// This field will not be serialized either

109

@Exclude

110

public transient String sessionToken;

111

}

112

```

113

114

### Field Aliases and Naming

115

116

```java

117

import io.protostuff.Tag;

118

119

/**

120

* Class demonstrating field aliases

121

*/

122

public class Product {

123

124

@Tag(value = 1, alias = "product_id")

125

public long id;

126

127

@Tag(value = 2, alias = "product_name")

128

public String name;

129

130

@Tag(value = 3, alias = "unit_price")

131

public double price;

132

133

@Tag(value = 4, alias = "is_available")

134

public boolean available;

135

136

// Alias helps with naming conventions different from Java

137

@Tag(value = 5, alias = "created_timestamp")

138

public long createdAt;

139

}

140

```

141

142

### Group Filtering

143

144

```java

145

import io.protostuff.Tag;

146

147

/**

148

* Class using group filters for conditional serialization

149

*/

150

public class UserProfile {

151

152

// Basic information (group 1)

153

@Tag(value = 1, groupFilter = 1)

154

public String name;

155

156

@Tag(value = 2, groupFilter = 1)

157

public int age;

158

159

// Contact information (group 2)

160

@Tag(value = 3, groupFilter = 2)

161

public String email;

162

163

@Tag(value = 4, groupFilter = 2)

164

public String phone;

165

166

// Sensitive information (group 3)

167

@Tag(value = 5, groupFilter = 3)

168

public String ssn;

169

170

@Tag(value = 6, groupFilter = 3)

171

public String creditCardNumber;

172

173

// Always included (no group filter)

174

@Tag(7)

175

public String publicId;

176

}

177

```

178

179

### Complex Field Configuration

180

181

```java

182

import io.protostuff.Tag;

183

import io.protostuff.Exclude;

184

import java.util.List;

185

import java.util.Map;

186

187

/**

188

* Complex class with various annotation combinations

189

*/

190

public class Order {

191

192

@Tag(1)

193

public String orderId;

194

195

@Tag(2)

196

public long customerId;

197

198

@Tag(value = 3, alias = "order_items")

199

public List<OrderItem> items;

200

201

@Tag(value = 4, alias = "order_total")

202

public double totalAmount;

203

204

@Tag(value = 5, groupFilter = 1) // Audit information

205

public long createdAt;

206

207

@Tag(value = 6, groupFilter = 1) // Audit information

208

public String createdBy;

209

210

@Tag(value = 7, alias = "shipping_address")

211

public Address shippingAddress;

212

213

@Tag(value = 8, alias = "billing_address")

214

public Address billingAddress;

215

216

// Additional metadata that might be filtered

217

@Tag(value = 9, groupFilter = 2)

218

public Map<String, String> metadata;

219

220

// Internal processing fields - excluded

221

@Exclude

222

public boolean processed;

223

224

@Exclude

225

public String internalNotes;

226

227

// Transient fields are also excluded by default

228

public transient Object tempData;

229

}

230

```

231

232

### Polymorphic Configuration with @Morph

233

234

```java

235

import io.protostuff.Tag;

236

import io.protostuff.Morph;

237

238

/**

239

* Base class with morphing enabled

240

*/

241

@Morph(true) // Enable morphing at the class level

242

public abstract class Shape {

243

244

@Tag(1)

245

public String name;

246

247

@Tag(2)

248

public String color;

249

}

250

251

/**

252

* Derived classes automatically inherit morphing behavior

253

*/

254

public class Circle extends Shape {

255

256

@Tag(3)

257

public double radius;

258

}

259

260

public class Rectangle extends Shape {

261

262

@Tag(3)

263

public double width;

264

265

@Tag(4)

266

public double height;

267

}

268

269

/**

270

* Class using polymorphic fields

271

*/

272

public class Drawing {

273

274

@Tag(1)

275

public String title;

276

277

// This field will use polymorphic serialization

278

@Tag(2)

279

@Morph(true) // Explicitly enable morphing for this field

280

public List<Shape> shapes;

281

282

// This field disables morphing (will serialize as base type only)

283

@Tag(3)

284

@Morph(false)

285

public Shape backgroundShape;

286

}

287

```

288

289

### Advanced Annotation Patterns

290

291

```java

292

import io.protostuff.Tag;

293

import io.protostuff.Exclude;

294

295

/**

296

* Advanced usage patterns with annotations

297

*/

298

public class AdvancedEntity {

299

300

// Required fields with low numbers for efficiency

301

@Tag(1)

302

public String id;

303

304

@Tag(2)

305

public String name;

306

307

// Optional fields with higher numbers

308

@Tag(10)

309

public String description;

310

311

@Tag(11)

312

public Map<String, Object> properties;

313

314

// Versioning fields

315

@Tag(20)

316

public int version;

317

318

@Tag(21)

319

public long lastModified;

320

321

// Audit fields with group filtering

322

@Tag(value = 30, groupFilter = 100, alias = "created_timestamp")

323

public long createdAt;

324

325

@Tag(value = 31, groupFilter = 100, alias = "created_by_user")

326

public String createdBy;

327

328

@Tag(value = 32, groupFilter = 100, alias = "updated_timestamp")

329

public long updatedAt;

330

331

@Tag(value = 33, groupFilter = 100, alias = "updated_by_user")

332

public String updatedBy;

333

334

// Internal state - excluded from serialization

335

@Exclude

336

public boolean dirty;

337

338

@Exclude

339

public Object cache;

340

341

// Computed fields - excluded

342

@Exclude

343

public String displayName; // Computed from other fields

344

345

@Exclude

346

public boolean valid; // Computed validation state

347

}

348

```

349

350

## Schema Generation with Annotations

351

352

### Basic Schema Creation

353

354

```java

355

import io.protostuff.runtime.RuntimeSchema;

356

import io.protostuff.Schema;

357

358

// Schema generation respects annotations automatically

359

Schema<User> userSchema = RuntimeSchema.getSchema(User.class);

360

361

// Field numbers and aliases from @Tag annotations are used

362

System.out.println("Field 1 name: " + userSchema.getFieldName(1)); // "name"

363

System.out.println("Field number for 'email': " + userSchema.getFieldNumber("email")); // 3

364

365

// @Exclude fields are not included in the schema

366

List<Field<User>> fields = ((RuntimeSchema<User>) userSchema).getFields();

367

// password field will not be in the list

368

```

369

370

### Group-Based Field Filtering

371

372

```java

373

import java.util.Set;

374

375

// Create schema excluding sensitive fields (group 3)

376

Set<String> exclusions = Set.of("ssn", "creditCardNumber");

377

RuntimeSchema<UserProfile> filteredSchema = RuntimeSchema.createFrom(

378

UserProfile.class, exclusions, RuntimeEnv.ID_STRATEGY

379

);

380

381

// Or use group filters programmatically when processing

382

RuntimeSchema<UserProfile> fullSchema = RuntimeSchema.createFrom(UserProfile.class);

383

for (Field<UserProfile> field : fullSchema.getFields()) {

384

if (field.groupFilter == 3) {

385

System.out.println("Sensitive field: " + field.name);

386

// Handle sensitive fields specially

387

}

388

}

389

```

390

391

### Polymorphic Schema with Morphing

392

393

```java

394

import io.protostuff.runtime.DefaultIdStrategy;

395

import io.protostuff.runtime.IdStrategy;

396

397

// Configure strategy for morphing

398

int flags = IdStrategy.MORPH_NON_FINAL_POJOS | IdStrategy.MORPH_COLLECTION_INTERFACES;

399

DefaultIdStrategy strategy = new DefaultIdStrategy(flags);

400

401

// Register polymorphic types

402

strategy.registerPojo(Shape.class);

403

strategy.registerPojo(Circle.class);

404

strategy.registerPojo(Rectangle.class);

405

strategy.map(Shape.class, Circle.class);

406

strategy.map(Shape.class, Rectangle.class);

407

408

// Create schema with morphing support

409

Schema<Drawing> drawingSchema = RuntimeSchema.getSchema(Drawing.class, strategy);

410

411

// The schema will handle polymorphic Shape objects in the shapes list

412

```

413

414

## Annotation Processing Rules

415

416

### Field Number Assignment

417

418

1. **Explicit @Tag**: Use the specified field number

419

2. **No @Tag**: Assign field numbers automatically in declaration order

420

3. **Mixed Usage**: Explicit tags take precedence, automatic assignment fills gaps

421

4. **Validation**: Field numbers must be unique and in valid range [1, 2^29-1]

422

423

### Field Exclusion Priority

424

425

1. **@Exclude annotation**: Highest priority - field is always excluded

426

2. **transient modifier**: Excluded by default (can be overridden with @Tag)

427

3. **static modifier**: Always excluded (cannot be overridden)

428

4. **Accessibility**: Private fields may need reflection access

429

430

### Alias Handling

431

432

1. **Wire Format**: Aliases are used in the protobuf wire format

433

2. **Field Lookup**: Both original name and alias can be used for field lookup

434

3. **Precedence**: Alias takes precedence over original field name in wire format

435

4. **Uniqueness**: Aliases must be unique within the message

436

437

## Best Practices

438

439

1. **Explicit Field Numbers**: Use @Tag with explicit numbers for stable schemas

440

2. **Reserved Ranges**: Reserve number ranges for different types of fields

441

3. **Group Filtering**: Use group filters for conditional serialization scenarios

442

4. **Meaningful Aliases**: Use aliases that match your wire format naming conventions

443

5. **Exclude Sensitive Data**: Always exclude passwords, tokens, and sensitive information

444

6. **Version Compatibility**: Plan field number assignments for schema evolution

445

7. **Documentation**: Document the purpose of group filters and special annotations

446

447

## Error Handling

448

449

Common issues with annotation usage:

450

451

- `IllegalArgumentException` - Invalid field numbers (out of range or duplicate)

452

- `RuntimeException` - Conflicting field configurations

453

- Field number conflicts when mixing @Tag and automatic assignment

454

- Invalid group filter values in certain contexts

455

- Alias conflicts with existing field names

456

457

## Interaction with IdStrategy

458

459

Annotations work in conjunction with IdStrategy configuration:

460

461

- **@Morph + MORPH_NON_FINAL_POJOS**: Enables polymorphic serialization

462

- **Group filters + custom strategy**: Custom field filtering logic

463

- **@Exclude + field exclusions**: Programmatic exclusions complement annotation exclusions

464

- **@Tag aliases + custom naming**: Strategy can provide additional naming transformations