Apache Thrift Java Library - A lightweight, language-independent software stack for point-to-point RPC implementation providing clean abstractions and implementations for data transport, data serialization, and application level processing
—
Utility classes and annotations that support Thrift operations, including string processing, partial deserialization support, and field annotations for enhanced functionality.
Utility methods for string processing and binary data handling in Thrift operations.
/**
* String utility methods for Thrift operations
*/
public class StringUtils {
/** Convert object to string representation for debugging */
public static String toString(Object obj);
/** Convert binary data to string representation */
public static String toBinaryString(byte[] bytes);
/** Fast binary data decoding */
public static byte[] fastBinaryDecode(String str);
/** Fast binary data encoding */
public static String fastBinaryEncode(byte[] bytes);
}Usage Examples:
import org.apache.thrift.utils.StringUtils;
// Using string utilities for debugging and data conversion
public class StringUtilsExample {
public void demonstrateStringUtils() {
// Convert binary data for logging
byte[] binaryData = {0x48, 0x65, 0x6C, 0x6C, 0x6F}; // "Hello"
String binaryString = StringUtils.toBinaryString(binaryData);
System.out.println("Binary representation: " + binaryString);
// Fast encoding/decoding for binary fields
String encoded = StringUtils.fastBinaryEncode(binaryData);
byte[] decoded = StringUtils.fastBinaryDecode(encoded);
// Object to string conversion for debugging
MyStruct struct = new MyStruct();
struct.setName("example");
String debugString = StringUtils.toString(struct);
System.out.println("Debug string: " + debugString);
}
}Additional utilities supporting partial deserialization operations beyond the basic TDeserializer functionality.
/**
* Metadata support for partial deserialization operations
*/
public class ThriftMetadata {
/** Get Thrift metadata for a class */
public static <T extends TBase> Map<String, Object> getThriftMetadata(Class<T> clazz);
/** Get field metadata by name */
public static <T extends TBase> Object getFieldMetadata(Class<T> clazz, String fieldName);
/** Get field ID by name */
public static <T extends TBase> Integer getFieldId(Class<T> clazz, String fieldName);
}
/**
* Utility class for field data encoding and decoding in partial deserialization
*/
public class TFieldData {
/** Encode field data for efficient storage/transmission */
public static byte[] encode(Object fieldValue, byte fieldType);
/** Decode field data from encoded format */
public static Object decode(byte[] encodedData, byte fieldType);
/** Encode field ID for compact representation */
public static byte[] encodeId(short fieldId);
/** Decode field ID from encoded format */
public static short decodeId(byte[] encodedId);
}
/**
* Comparison utilities for partial Thrift objects
*/
public class PartialThriftComparer {
/** Compare two partial objects for equality */
public static boolean isEqualTo(Object obj1, Object obj2);
/** Compare two partial objects with ordering */
public static int compareTo(Object obj1, Object obj2);
/** Resolve differences between partial objects */
public static <T extends TBase> T resolve(T obj1, T obj2, ConflictResolver resolver);
/**
* Interface for resolving conflicts between partial objects
*/
public interface ConflictResolver {
/** Resolve conflict between two field values */
Object resolve(String fieldName, Object value1, Object value2);
}
}Usage Examples:
import org.apache.thrift.partial.ThriftMetadata;
import org.apache.thrift.partial.TFieldData;
import org.apache.thrift.partial.PartialThriftComparer;
// Working with partial deserialization utilities
public class PartialUtilitiesExample {
public void demonstrateMetadata() {
// Get metadata for a Thrift class
Map<String, Object> metadata = ThriftMetadata.getThriftMetadata(MyStruct.class);
System.out.println("Available fields: " + metadata.keySet());
// Get specific field information
Integer fieldId = ThriftMetadata.getFieldId(MyStruct.class, "name");
System.out.println("Field 'name' has ID: " + fieldId);
}
public void demonstrateFieldDataEncoding() {
// Encode field data for compact storage
String originalValue = "example string";
byte[] encoded = TFieldData.encode(originalValue, TType.STRING);
// Decode field data
String decoded = (String) TFieldData.decode(encoded, TType.STRING);
System.out.println("Original: " + originalValue);
System.out.println("Decoded: " + decoded);
// Encode field IDs
short fieldId = 123;
byte[] encodedId = TFieldData.encodeId(fieldId);
short decodedId = TFieldData.decodeId(encodedId);
}
public void demonstrateComparison() {
MyStruct struct1 = new MyStruct();
struct1.setName("example");
struct1.setValue(42);
MyStruct struct2 = new MyStruct();
struct2.setName("example");
struct2.setValue(43);
// Compare partial objects
boolean isEqual = PartialThriftComparer.isEqualTo(struct1, struct2);
int comparison = PartialThriftComparer.compareTo(struct1, struct2);
// Resolve conflicts
PartialThriftComparer.ConflictResolver resolver = (fieldName, value1, value2) -> {
// Custom resolution logic
if ("value".equals(fieldName)) {
// Take the higher value
return ((Integer) value1) > ((Integer) value2) ? value1 : value2;
}
return value1; // Default to first value
};
MyStruct resolved = PartialThriftComparer.resolve(struct1, struct2, resolver);
System.out.println("Resolved value: " + resolved.getValue()); // Should be 43
}
}Annotations for marking field properties and behaviors in Thrift objects.
/**
* Annotation to mark fields as nullable at runtime
* Can be used for validation and code generation hints
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface Nullable {
/** Optional description of nullability conditions */
String value() default "";
}Usage Examples:
import org.apache.thrift.annotation.Nullable;
// Using nullable annotation in Thrift struct implementations
public class AnnotatedStruct implements TBase<AnnotatedStruct, AnnotatedStruct._Fields> {
@Nullable("This field may be null in some contexts")
private String optionalField;
private String requiredField; // Not annotated, assumed non-null
// Getters and setters
@Nullable
public String getOptionalField() {
return optionalField;
}
public void setOptionalField(@Nullable String optionalField) {
this.optionalField = optionalField;
}
public String getRequiredField() {
return requiredField;
}
public void setRequiredField(String requiredField) {
this.requiredField = requiredField;
}
}
// Utility for working with nullable annotations
public class NullableUtils {
public static boolean isNullable(Field field) {
return field.isAnnotationPresent(Nullable.class);
}
public static boolean isNullable(Method method) {
return method.isAnnotationPresent(Nullable.class);
}
public static String getNullableDescription(Field field) {
Nullable annotation = field.getAnnotation(Nullable.class);
return annotation != null ? annotation.value() : null;
}
// Validation method using nullable annotations
public static <T> void validateNullable(T obj) throws IllegalArgumentException {
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
Object value = field.get(obj);
// Check non-nullable fields
if (!isNullable(field) && value == null) {
throw new IllegalArgumentException(
"Non-nullable field '" + field.getName() + "' cannot be null");
}
} catch (IllegalAccessException e) {
// Handle reflection error
System.err.println("Cannot access field: " + field.getName());
}
}
}
}Using utilities and annotations with Java reflection for advanced Thrift operations.
import org.apache.thrift.annotation.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
// Advanced reflection utilities for Thrift objects
public class ReflectionUtils {
/**
* Get all nullable fields in a Thrift object
*/
public static List<Field> getNullableFields(Class<?> clazz) {
List<Field> nullableFields = new ArrayList<>();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Nullable.class)) {
nullableFields.add(field);
}
}
return nullableFields;
}
/**
* Create a validation report for a Thrift object
*/
public static ValidationReport validate(Object obj) {
ValidationReport report = new ValidationReport();
Class<?> clazz = obj.getClass();
// Check nullable annotations
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
try {
Object value = field.get(obj);
boolean isNullable = field.isAnnotationPresent(Nullable.class);
if (!isNullable && value == null) {
report.addError("Non-nullable field '" + field.getName() + "' is null");
} else if (isNullable && value == null) {
report.addWarning("Nullable field '" + field.getName() + "' is null");
}
} catch (IllegalAccessException e) {
report.addError("Cannot access field: " + field.getName());
}
}
return report;
}
public static class ValidationReport {
private List<String> errors = new ArrayList<>();
private List<String> warnings = new ArrayList<>();
public void addError(String error) { errors.add(error); }
public void addWarning(String warning) { warnings.add(warning); }
public boolean hasErrors() { return !errors.isEmpty(); }
public List<String> getErrors() { return errors; }
public List<String> getWarnings() { return warnings; }
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (!errors.isEmpty()) {
sb.append("Errors:\n");
for (String error : errors) {
sb.append(" - ").append(error).append("\n");
}
}
if (!warnings.isEmpty()) {
sb.append("Warnings:\n");
for (String warning : warnings) {
sb.append(" - ").append(warning).append("\n");
}
}
return sb.toString();
}
}
}
// Usage example
public class ValidationExample {
public void validateStruct() {
AnnotatedStruct struct = new AnnotatedStruct();
struct.setRequiredField("test");
// optionalField is left null
ReflectionUtils.ValidationReport report = ReflectionUtils.validate(struct);
if (report.hasErrors()) {
System.err.println("Validation failed:");
System.err.println(report);
} else {
System.out.println("Validation passed");
if (!report.getWarnings().isEmpty()) {
System.out.println("Warnings:");
System.out.println(report);
}
}
}
}Utilities for optimizing Thrift operations and monitoring performance.
// Performance monitoring utilities
public class ThriftPerformanceUtils {
/**
* Measure serialization performance
*/
public static PerformanceResult measureSerialization(TBase<?, ?> object, TProtocolFactory protocolFactory, int iterations) {
long startTime = System.nanoTime();
long totalBytes = 0;
try {
for (int i = 0; i < iterations; i++) {
TSerializer serializer = new TSerializer(protocolFactory);
byte[] data = serializer.serialize(object);
totalBytes += data.length;
}
} catch (TException e) {
throw new RuntimeException("Serialization failed", e);
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
return new PerformanceResult(iterations, duration, totalBytes);
}
public static class PerformanceResult {
public final int iterations;
public final long durationNanos;
public final long totalBytes;
public final double avgBytesPerObject;
public final double objectsPerSecond;
public PerformanceResult(int iterations, long durationNanos, long totalBytes) {
this.iterations = iterations;
this.durationNanos = durationNanos;
this.totalBytes = totalBytes;
this.avgBytesPerObject = (double) totalBytes / iterations;
this.objectsPerSecond = iterations / (durationNanos / 1_000_000_000.0);
}
@Override
public String toString() {
return String.format("Performance: %.2f objects/sec, %.1f bytes/object, %d total bytes",
objectsPerSecond, avgBytesPerObject, totalBytes);
}
}
}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.
Install with Tessl CLI
npx tessl i tessl/maven-org-apache-thrift--libthrift