0
# Code Generation Support
1
2
Avro's code generation support provides integration with generated Java classes for type-safe, high-performance data operations. Specific operations work with POJOs generated from Avro schemas, offering compile-time type checking and optimized serialization performance.
3
4
## Capabilities
5
6
### Specific Data Utilities
7
8
Core utilities for working with generated Avro classes and their schemas.
9
10
```java { .api }
11
public class SpecificData extends GenericData {
12
public static SpecificData get();
13
14
// Class and schema mapping
15
public static Class<?> getClassName(Schema schema);
16
public Schema getSchema(Class<?> c);
17
public Schema getSchema(Object object);
18
19
// Instance creation
20
public Object newInstance(Class<?> c, Schema schema);
21
public Object createFixed(Object old, Schema schema);
22
public Object createRecord(Object old, Schema schema);
23
public Object createEnum(String symbol, Schema schema);
24
25
// Protocol support
26
public Protocol getProtocol(Class<?> iface);
27
28
// Conversion support
29
public void addLogicalTypeConversion(Conversion<?> conversion);
30
public Conversion<?> getConversionFor(LogicalType logicalType);
31
public Collection<Conversion<?>> getConversions();
32
}
33
```
34
35
**Usage Examples:**
36
37
```java
38
// Get SpecificData instance
39
SpecificData specificData = SpecificData.get();
40
41
// Get class name from schema
42
Schema userSchema = new Schema.Parser().parse(userSchemaJson);
43
Class<?> userClass = SpecificData.getClassName(userSchema);
44
System.out.println("Generated class: " + userClass.getName());
45
46
// Get schema from generated class
47
Schema schemaFromClass = specificData.getSchema(User.class);
48
System.out.println("Schema from class: " + schemaFromClass.getName());
49
50
// Create instance of generated class
51
User user = (User) specificData.newInstance(User.class, userSchema);
52
user.setName("Alice");
53
user.setAge(25);
54
55
// Work with protocols for RPC
56
Protocol userServiceProtocol = specificData.getProtocol(UserService.class);
57
System.out.println("Protocol: " + userServiceProtocol.getName());
58
```
59
60
### Specific Record Interface
61
62
Base interface that all generated record classes implement.
63
64
```java { .api }
65
public interface SpecificRecord extends IndexedRecord {
66
Schema getSchema();
67
68
// Specific record methods are typically generated
69
// For example, for a User schema:
70
// String getName();
71
// void setName(String name);
72
// Integer getAge();
73
// void setAge(Integer age);
74
}
75
```
76
77
**Usage Examples:**
78
79
```java
80
// Using generated record class (example)
81
public class User implements SpecificRecord {
82
private static final Schema SCHEMA$ = new Schema.Parser().parse(SCHEMA_JSON);
83
84
private String name;
85
private Integer age;
86
private String email;
87
88
public User() {}
89
90
public User(String name, Integer age, String email) {
91
this.name = name;
92
this.age = age;
93
this.email = email;
94
}
95
96
@Override
97
public Schema getSchema() {
98
return SCHEMA$;
99
}
100
101
// Generated getters and setters
102
public String getName() { return name; }
103
public void setName(String name) { this.name = name; }
104
105
public Integer getAge() { return age; }
106
public void setAge(Integer age) { this.age = age; }
107
108
public String getEmail() { return email; }
109
public void setEmail(String email) { this.email = email; }
110
111
// IndexedRecord implementation
112
@Override
113
public Object get(int field) {
114
switch (field) {
115
case 0: return name;
116
case 1: return age;
117
case 2: return email;
118
default: throw new IndexOutOfBoundsException();
119
}
120
}
121
122
@Override
123
public void put(int field, Object value) {
124
switch (field) {
125
case 0: name = (String) value; break;
126
case 1: age = (Integer) value; break;
127
case 2: email = (String) value; break;
128
default: throw new IndexOutOfBoundsException();
129
}
130
}
131
}
132
133
// Use generated class
134
User user = new User("Bob", 30, "bob@example.com");
135
Schema userSchema = user.getSchema();
136
System.out.println("User: " + user.getName() + ", Age: " + user.getAge());
137
```
138
139
### Specific Datum Reader
140
141
DatumReader optimized for generated classes with compile-time type safety.
142
143
```java { .api }
144
public class SpecificDatumReader<T> extends GenericDatumReader<T> {
145
public SpecificDatumReader();
146
public SpecificDatumReader(Schema schema);
147
public SpecificDatumReader(Schema writer, Schema reader);
148
public SpecificDatumReader(Class<T> c);
149
public SpecificDatumReader(Class<T> c, Schema writer, Schema reader);
150
151
// Inherited from GenericDatumReader
152
public void setSchema(Schema schema);
153
public void setExpected(Schema reader);
154
public T read(T reuse, Decoder in) throws IOException;
155
}
156
```
157
158
**Usage Examples:**
159
160
```java
161
// Read generated objects from binary data
162
SpecificDatumReader<User> reader = new SpecificDatumReader<>(User.class);
163
164
InputStream inputStream = new FileInputStream("users.avro");
165
BinaryDecoder decoder = DecoderFactory.get().binaryDecoder(inputStream, null);
166
167
// Read specific records with type safety
168
User user1 = reader.read(null, decoder);
169
System.out.println("User name: " + user1.getName());
170
171
// Reuse objects for better performance
172
User reusedUser = null;
173
while (hasMoreData(decoder)) {
174
reusedUser = reader.read(reusedUser, decoder);
175
processUser(reusedUser);
176
}
177
178
// Schema evolution with generated classes
179
Schema writerSchema = getWriterSchema();
180
Schema readerSchema = User.SCHEMA$;
181
SpecificDatumReader<User> evolvingReader =
182
new SpecificDatumReader<>(User.class, writerSchema, readerSchema);
183
184
User evolvedUser = evolvingReader.read(null, decoder);
185
```
186
187
### Specific Datum Writer
188
189
DatumWriter optimized for generated classes with compile-time type safety.
190
191
```java { .api }
192
public class SpecificDatumWriter<T> extends GenericDatumWriter<T> {
193
public SpecificDatumWriter();
194
public SpecificDatumWriter(Schema schema);
195
public SpecificDatumWriter(Class<T> c);
196
197
// Inherited from GenericDatumWriter
198
public void setSchema(Schema schema);
199
public void write(T datum, Encoder out) throws IOException;
200
}
201
```
202
203
**Usage Examples:**
204
205
```java
206
// Write generated objects to binary format
207
SpecificDatumWriter<User> writer = new SpecificDatumWriter<>(User.class);
208
209
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
210
BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(outputStream, null);
211
212
// Write specific records with type safety
213
User user = new User("Charlie", 35, "charlie@example.com");
214
writer.write(user, encoder);
215
encoder.flush();
216
217
// Write multiple users
218
List<User> users = Arrays.asList(
219
new User("Alice", 25, "alice@example.com"),
220
new User("Bob", 30, "bob@example.com"),
221
new User("Carol", 28, "carol@example.com")
222
);
223
224
for (User u : users) {
225
writer.write(u, encoder);
226
}
227
encoder.flush();
228
229
byte[] serializedData = outputStream.toByteArray();
230
```
231
232
### Generated Class Annotations
233
234
Annotations used to mark and configure generated Avro classes.
235
236
```java { .api }
237
@Target(ElementType.TYPE)
238
@Retention(RetentionPolicy.RUNTIME)
239
public @interface AvroGenerated {
240
// Marks classes as Avro-generated
241
}
242
243
@Target(ElementType.TYPE)
244
@Retention(RetentionPolicy.RUNTIME)
245
public @interface FixedSize {
246
int value();
247
}
248
```
249
250
**Usage Examples:**
251
252
```java
253
// Generated record with annotations
254
@AvroGenerated
255
public class User implements SpecificRecord {
256
// Implementation generated by Avro compiler
257
}
258
259
// Generated fixed class with size annotation
260
@AvroGenerated
261
@FixedSize(16)
262
public class MD5Hash implements SpecificFixed {
263
private static final Schema SCHEMA$ = Schema.createFixed("MD5Hash", null, null, 16);
264
private byte[] bytes = new byte[16];
265
266
@Override
267
public Schema getSchema() {
268
return SCHEMA$;
269
}
270
271
@Override
272
public byte[] bytes() {
273
return bytes;
274
}
275
}
276
277
// Check if class is Avro-generated
278
if (User.class.isAnnotationPresent(AvroGenerated.class)) {
279
System.out.println("User class is Avro-generated");
280
}
281
282
// Get fixed size from annotation
283
if (MD5Hash.class.isAnnotationPresent(FixedSize.class)) {
284
FixedSize annotation = MD5Hash.class.getAnnotation(FixedSize.class);
285
System.out.println("Fixed size: " + annotation.value());
286
}
287
```
288
289
### Builder Pattern Support
290
291
Generated classes often include builder patterns for convenient object construction.
292
293
```java { .api }
294
// Example of generated builder (varies by schema)
295
public static class Builder {
296
// Builder methods generated based on schema fields
297
public Builder setName(String name);
298
public Builder setAge(Integer age);
299
public Builder setEmail(String email);
300
301
public User build();
302
public Builder clear();
303
304
// Field checking
305
public boolean hasName();
306
public boolean hasAge();
307
public boolean hasEmail();
308
}
309
```
310
311
**Usage Examples:**
312
313
```java
314
// Using generated builder (example pattern)
315
User user = User.newBuilder()
316
.setName("David")
317
.setAge(40)
318
.setEmail("david@example.com")
319
.build();
320
321
// Build with partial data
322
User partialUser = User.newBuilder()
323
.setName("Eve")
324
.build(); // Age and email will use defaults or be null
325
326
// Check what fields are set
327
User.Builder builder = User.newBuilder();
328
builder.setName("Frank");
329
330
if (builder.hasName()) {
331
System.out.println("Name is set");
332
}
333
if (!builder.hasEmail()) {
334
System.out.println("Email is not set");
335
}
336
337
User finalUser = builder.build();
338
```
339
340
### Specific Error Handling
341
342
Error classes generated from schema error types implement SpecificRecord.
343
344
```java { .api }
345
// Generated error class example
346
@AvroGenerated
347
public class UserNotFoundException extends Exception implements SpecificRecord {
348
private static final Schema SCHEMA$ = parseSchema(ERROR_SCHEMA_JSON);
349
350
private String userId;
351
private String message;
352
353
public UserNotFoundException() {}
354
355
public UserNotFoundException(String userId, String message) {
356
super(message);
357
this.userId = userId;
358
this.message = message;
359
}
360
361
@Override
362
public Schema getSchema() {
363
return SCHEMA$;
364
}
365
366
// Generated getters/setters
367
public String getUserId() { return userId; }
368
public void setUserId(String userId) { this.userId = userId; }
369
370
@Override
371
public String getMessage() { return message; }
372
public void setMessage(String message) { this.message = message; }
373
}
374
```
375
376
**Usage Examples:**
377
378
```java
379
// Throw generated error
380
public User findUser(String userId) throws UserNotFoundException {
381
User user = userRepository.find(userId);
382
if (user == null) {
383
throw new UserNotFoundException(userId, "User not found: " + userId);
384
}
385
return user;
386
}
387
388
// Catch and handle generated error
389
try {
390
User user = findUser("unknown123");
391
} catch (UserNotFoundException e) {
392
System.err.println("Failed to find user: " + e.getUserId());
393
System.err.println("Error message: " + e.getMessage());
394
395
// Error also implements SpecificRecord
396
Schema errorSchema = e.getSchema();
397
System.out.println("Error schema: " + errorSchema.getName());
398
}
399
```
400
401
## Types
402
403
```java { .api }
404
public class SpecificData extends GenericData {
405
// Utilities for generated classes
406
}
407
408
public interface SpecificRecord extends IndexedRecord {
409
Schema getSchema();
410
}
411
412
public interface SpecificFixed extends GenericFixed {
413
// Marker interface for generated fixed classes
414
}
415
416
public class SpecificDatumReader<T> extends GenericDatumReader<T> {
417
// Type-safe reader for generated classes
418
}
419
420
public class SpecificDatumWriter<T> extends GenericDatumWriter<T> {
421
// Type-safe writer for generated classes
422
}
423
424
@Target(ElementType.TYPE)
425
@Retention(RetentionPolicy.RUNTIME)
426
public @interface AvroGenerated {
427
// Annotation for generated classes
428
}
429
430
@Target(ElementType.TYPE)
431
@Retention(RetentionPolicy.RUNTIME)
432
public @interface FixedSize {
433
int value();
434
}
435
436
// Generated class interfaces (examples based on common patterns)
437
public interface Builder<T> {
438
T build();
439
Builder<T> clear();
440
}
441
442
public abstract class SpecificRecordBase implements SpecificRecord {
443
// Base class for generated records (implementation detail)
444
}
445
446
public abstract class SpecificExceptionBase extends Exception implements SpecificRecord {
447
// Base class for generated exceptions
448
}
449
```