0
# Utilities and Annotations
1
2
Utility classes and annotations that support Thrift operations, including string processing, partial deserialization support, and field annotations for enhanced functionality.
3
4
## Capabilities
5
6
### String Utilities
7
8
Utility methods for string processing and binary data handling in Thrift operations.
9
10
```java { .api }
11
/**
12
* String utility methods for Thrift operations
13
*/
14
public class StringUtils {
15
/** Convert object to string representation for debugging */
16
public static String toString(Object obj);
17
18
/** Convert binary data to string representation */
19
public static String toBinaryString(byte[] bytes);
20
21
/** Fast binary data decoding */
22
public static byte[] fastBinaryDecode(String str);
23
24
/** Fast binary data encoding */
25
public static String fastBinaryEncode(byte[] bytes);
26
}
27
```
28
29
**Usage Examples:**
30
31
```java
32
import org.apache.thrift.utils.StringUtils;
33
34
// Using string utilities for debugging and data conversion
35
public class StringUtilsExample {
36
public void demonstrateStringUtils() {
37
// Convert binary data for logging
38
byte[] binaryData = {0x48, 0x65, 0x6C, 0x6C, 0x6F}; // "Hello"
39
String binaryString = StringUtils.toBinaryString(binaryData);
40
System.out.println("Binary representation: " + binaryString);
41
42
// Fast encoding/decoding for binary fields
43
String encoded = StringUtils.fastBinaryEncode(binaryData);
44
byte[] decoded = StringUtils.fastBinaryDecode(encoded);
45
46
// Object to string conversion for debugging
47
MyStruct struct = new MyStruct();
48
struct.setName("example");
49
String debugString = StringUtils.toString(struct);
50
System.out.println("Debug string: " + debugString);
51
}
52
}
53
```
54
55
### Partial Deserialization Utilities
56
57
Additional utilities supporting partial deserialization operations beyond the basic TDeserializer functionality.
58
59
```java { .api }
60
/**
61
* Metadata support for partial deserialization operations
62
*/
63
public class ThriftMetadata {
64
/** Get Thrift metadata for a class */
65
public static <T extends TBase> Map<String, Object> getThriftMetadata(Class<T> clazz);
66
67
/** Get field metadata by name */
68
public static <T extends TBase> Object getFieldMetadata(Class<T> clazz, String fieldName);
69
70
/** Get field ID by name */
71
public static <T extends TBase> Integer getFieldId(Class<T> clazz, String fieldName);
72
}
73
74
/**
75
* Utility class for field data encoding and decoding in partial deserialization
76
*/
77
public class TFieldData {
78
/** Encode field data for efficient storage/transmission */
79
public static byte[] encode(Object fieldValue, byte fieldType);
80
81
/** Decode field data from encoded format */
82
public static Object decode(byte[] encodedData, byte fieldType);
83
84
/** Encode field ID for compact representation */
85
public static byte[] encodeId(short fieldId);
86
87
/** Decode field ID from encoded format */
88
public static short decodeId(byte[] encodedId);
89
}
90
91
/**
92
* Comparison utilities for partial Thrift objects
93
*/
94
public class PartialThriftComparer {
95
/** Compare two partial objects for equality */
96
public static boolean isEqualTo(Object obj1, Object obj2);
97
98
/** Compare two partial objects with ordering */
99
public static int compareTo(Object obj1, Object obj2);
100
101
/** Resolve differences between partial objects */
102
public static <T extends TBase> T resolve(T obj1, T obj2, ConflictResolver resolver);
103
104
/**
105
* Interface for resolving conflicts between partial objects
106
*/
107
public interface ConflictResolver {
108
/** Resolve conflict between two field values */
109
Object resolve(String fieldName, Object value1, Object value2);
110
}
111
}
112
```
113
114
**Usage Examples:**
115
116
```java
117
import org.apache.thrift.partial.ThriftMetadata;
118
import org.apache.thrift.partial.TFieldData;
119
import org.apache.thrift.partial.PartialThriftComparer;
120
121
// Working with partial deserialization utilities
122
public class PartialUtilitiesExample {
123
124
public void demonstrateMetadata() {
125
// Get metadata for a Thrift class
126
Map<String, Object> metadata = ThriftMetadata.getThriftMetadata(MyStruct.class);
127
System.out.println("Available fields: " + metadata.keySet());
128
129
// Get specific field information
130
Integer fieldId = ThriftMetadata.getFieldId(MyStruct.class, "name");
131
System.out.println("Field 'name' has ID: " + fieldId);
132
}
133
134
public void demonstrateFieldDataEncoding() {
135
// Encode field data for compact storage
136
String originalValue = "example string";
137
byte[] encoded = TFieldData.encode(originalValue, TType.STRING);
138
139
// Decode field data
140
String decoded = (String) TFieldData.decode(encoded, TType.STRING);
141
System.out.println("Original: " + originalValue);
142
System.out.println("Decoded: " + decoded);
143
144
// Encode field IDs
145
short fieldId = 123;
146
byte[] encodedId = TFieldData.encodeId(fieldId);
147
short decodedId = TFieldData.decodeId(encodedId);
148
}
149
150
public void demonstrateComparison() {
151
MyStruct struct1 = new MyStruct();
152
struct1.setName("example");
153
struct1.setValue(42);
154
155
MyStruct struct2 = new MyStruct();
156
struct2.setName("example");
157
struct2.setValue(43);
158
159
// Compare partial objects
160
boolean isEqual = PartialThriftComparer.isEqualTo(struct1, struct2);
161
int comparison = PartialThriftComparer.compareTo(struct1, struct2);
162
163
// Resolve conflicts
164
PartialThriftComparer.ConflictResolver resolver = (fieldName, value1, value2) -> {
165
// Custom resolution logic
166
if ("value".equals(fieldName)) {
167
// Take the higher value
168
return ((Integer) value1) > ((Integer) value2) ? value1 : value2;
169
}
170
return value1; // Default to first value
171
};
172
173
MyStruct resolved = PartialThriftComparer.resolve(struct1, struct2, resolver);
174
System.out.println("Resolved value: " + resolved.getValue()); // Should be 43
175
}
176
}
177
```
178
179
### Field Annotations
180
181
Annotations for marking field properties and behaviors in Thrift objects.
182
183
```java { .api }
184
/**
185
* Annotation to mark fields as nullable at runtime
186
* Can be used for validation and code generation hints
187
*/
188
@Retention(RetentionPolicy.RUNTIME)
189
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
190
public @interface Nullable {
191
/** Optional description of nullability conditions */
192
String value() default "";
193
}
194
```
195
196
**Usage Examples:**
197
198
```java
199
import org.apache.thrift.annotation.Nullable;
200
201
// Using nullable annotation in Thrift struct implementations
202
public class AnnotatedStruct implements TBase<AnnotatedStruct, AnnotatedStruct._Fields> {
203
204
@Nullable("This field may be null in some contexts")
205
private String optionalField;
206
207
private String requiredField; // Not annotated, assumed non-null
208
209
// Getters and setters
210
@Nullable
211
public String getOptionalField() {
212
return optionalField;
213
}
214
215
public void setOptionalField(@Nullable String optionalField) {
216
this.optionalField = optionalField;
217
}
218
219
public String getRequiredField() {
220
return requiredField;
221
}
222
223
public void setRequiredField(String requiredField) {
224
this.requiredField = requiredField;
225
}
226
}
227
228
// Utility for working with nullable annotations
229
public class NullableUtils {
230
231
public static boolean isNullable(Field field) {
232
return field.isAnnotationPresent(Nullable.class);
233
}
234
235
public static boolean isNullable(Method method) {
236
return method.isAnnotationPresent(Nullable.class);
237
}
238
239
public static String getNullableDescription(Field field) {
240
Nullable annotation = field.getAnnotation(Nullable.class);
241
return annotation != null ? annotation.value() : null;
242
}
243
244
// Validation method using nullable annotations
245
public static <T> void validateNullable(T obj) throws IllegalArgumentException {
246
Class<?> clazz = obj.getClass();
247
Field[] fields = clazz.getDeclaredFields();
248
249
for (Field field : fields) {
250
field.setAccessible(true);
251
try {
252
Object value = field.get(obj);
253
254
// Check non-nullable fields
255
if (!isNullable(field) && value == null) {
256
throw new IllegalArgumentException(
257
"Non-nullable field '" + field.getName() + "' cannot be null");
258
}
259
} catch (IllegalAccessException e) {
260
// Handle reflection error
261
System.err.println("Cannot access field: " + field.getName());
262
}
263
}
264
}
265
}
266
```
267
268
### Integration with Reflection
269
270
Using utilities and annotations with Java reflection for advanced Thrift operations.
271
272
```java
273
import org.apache.thrift.annotation.Nullable;
274
import java.lang.reflect.Field;
275
import java.lang.reflect.Method;
276
277
// Advanced reflection utilities for Thrift objects
278
public class ReflectionUtils {
279
280
/**
281
* Get all nullable fields in a Thrift object
282
*/
283
public static List<Field> getNullableFields(Class<?> clazz) {
284
List<Field> nullableFields = new ArrayList<>();
285
286
for (Field field : clazz.getDeclaredFields()) {
287
if (field.isAnnotationPresent(Nullable.class)) {
288
nullableFields.add(field);
289
}
290
}
291
292
return nullableFields;
293
}
294
295
/**
296
* Create a validation report for a Thrift object
297
*/
298
public static ValidationReport validate(Object obj) {
299
ValidationReport report = new ValidationReport();
300
Class<?> clazz = obj.getClass();
301
302
// Check nullable annotations
303
for (Field field : clazz.getDeclaredFields()) {
304
field.setAccessible(true);
305
try {
306
Object value = field.get(obj);
307
boolean isNullable = field.isAnnotationPresent(Nullable.class);
308
309
if (!isNullable && value == null) {
310
report.addError("Non-nullable field '" + field.getName() + "' is null");
311
} else if (isNullable && value == null) {
312
report.addWarning("Nullable field '" + field.getName() + "' is null");
313
}
314
} catch (IllegalAccessException e) {
315
report.addError("Cannot access field: " + field.getName());
316
}
317
}
318
319
return report;
320
}
321
322
public static class ValidationReport {
323
private List<String> errors = new ArrayList<>();
324
private List<String> warnings = new ArrayList<>();
325
326
public void addError(String error) { errors.add(error); }
327
public void addWarning(String warning) { warnings.add(warning); }
328
329
public boolean hasErrors() { return !errors.isEmpty(); }
330
public List<String> getErrors() { return errors; }
331
public List<String> getWarnings() { return warnings; }
332
333
@Override
334
public String toString() {
335
StringBuilder sb = new StringBuilder();
336
if (!errors.isEmpty()) {
337
sb.append("Errors:\n");
338
for (String error : errors) {
339
sb.append(" - ").append(error).append("\n");
340
}
341
}
342
if (!warnings.isEmpty()) {
343
sb.append("Warnings:\n");
344
for (String warning : warnings) {
345
sb.append(" - ").append(warning).append("\n");
346
}
347
}
348
return sb.toString();
349
}
350
}
351
}
352
353
// Usage example
354
public class ValidationExample {
355
public void validateStruct() {
356
AnnotatedStruct struct = new AnnotatedStruct();
357
struct.setRequiredField("test");
358
// optionalField is left null
359
360
ReflectionUtils.ValidationReport report = ReflectionUtils.validate(struct);
361
362
if (report.hasErrors()) {
363
System.err.println("Validation failed:");
364
System.err.println(report);
365
} else {
366
System.out.println("Validation passed");
367
if (!report.getWarnings().isEmpty()) {
368
System.out.println("Warnings:");
369
System.out.println(report);
370
}
371
}
372
}
373
}
374
```
375
376
### Performance Utilities
377
378
Utilities for optimizing Thrift operations and monitoring performance.
379
380
```java
381
// Performance monitoring utilities
382
public class ThriftPerformanceUtils {
383
384
/**
385
* Measure serialization performance
386
*/
387
public static PerformanceResult measureSerialization(TBase<?, ?> object, TProtocolFactory protocolFactory, int iterations) {
388
long startTime = System.nanoTime();
389
long totalBytes = 0;
390
391
try {
392
for (int i = 0; i < iterations; i++) {
393
TSerializer serializer = new TSerializer(protocolFactory);
394
byte[] data = serializer.serialize(object);
395
totalBytes += data.length;
396
}
397
} catch (TException e) {
398
throw new RuntimeException("Serialization failed", e);
399
}
400
401
long endTime = System.nanoTime();
402
long duration = endTime - startTime;
403
404
return new PerformanceResult(iterations, duration, totalBytes);
405
}
406
407
public static class PerformanceResult {
408
public final int iterations;
409
public final long durationNanos;
410
public final long totalBytes;
411
public final double avgBytesPerObject;
412
public final double objectsPerSecond;
413
414
public PerformanceResult(int iterations, long durationNanos, long totalBytes) {
415
this.iterations = iterations;
416
this.durationNanos = durationNanos;
417
this.totalBytes = totalBytes;
418
this.avgBytesPerObject = (double) totalBytes / iterations;
419
this.objectsPerSecond = iterations / (durationNanos / 1_000_000_000.0);
420
}
421
422
@Override
423
public String toString() {
424
return String.format("Performance: %.2f objects/sec, %.1f bytes/object, %d total bytes",
425
objectsPerSecond, avgBytesPerObject, totalBytes);
426
}
427
}
428
}
429
```
430
431
These utilities and annotations provide additional functionality for working with Thrift objects, including enhanced debugging capabilities, validation support, and performance monitoring tools that complement the core Thrift framework.