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
—
Serialization schemes control how Thrift objects are encoded and decoded using different strategies. The scheme system provides pluggable serialization implementations that can optimize for different use cases like memory efficiency or compatibility.
Core interface that all serialization schemes implement.
/**
* Interface for serialization schemes that control how Thrift objects are encoded/decoded
* @param <T> The TBase type this scheme handles
*/
public interface IScheme<T extends TBase> {
/** Read (deserialize) a Thrift object from protocol */
public void read(TProtocol iproto, T struct) throws TException;
/** Write (serialize) a Thrift object to protocol */
public void write(TProtocol oproto, T struct) throws TException;
}
/**
* Factory interface for creating scheme instances
*/
public interface SchemeFactory {
/** Create a new scheme instance for the given type */
public IScheme getScheme();
}Default serialization scheme used by most generated Thrift classes.
/**
* Standard serialization scheme that reads/writes all fields with full metadata
*/
public class StandardScheme<T extends TBase> implements IScheme<T> {
/** Read object from protocol using standard field-by-field approach */
public void read(TProtocol iproto, T struct) throws TException;
/** Write object to protocol using standard field-by-field approach */
public void write(TProtocol oproto, T struct) throws TException;
}Usage Examples:
import org.apache.thrift.scheme.StandardScheme;
import org.apache.thrift.scheme.IScheme;
// Standard scheme is typically used automatically by generated code
public class MyStruct implements TBase<MyStruct, MyStruct._Fields> {
private static final IScheme<MyStruct> STANDARD_SCHEME = new StandardScheme<MyStruct>();
// Generated read method
public void read(TProtocol iprot) throws TException {
STANDARD_SCHEME.read(iprot, this);
}
// Generated write method
public void write(TProtocol oprot) throws TException {
STANDARD_SCHEME.write(oprot, this);
}
}Memory-efficient serialization scheme that omits field metadata for smaller payloads.
/**
* Tuple-based serialization scheme for memory efficiency
* Serializes fields in order without field IDs or names
*/
public class TupleScheme<T extends TBase> implements IScheme<T> {
/** Read object from protocol using tuple approach (no field metadata) */
public void read(TProtocol iproto, T struct) throws TException;
/** Write object to protocol using tuple approach (no field metadata) */
public void write(TProtocol oproto, T struct) throws TException;
}Usage Examples:
import org.apache.thrift.scheme.TupleScheme;
import org.apache.thrift.protocol.TTupleProtocol;
// Tuple scheme is often used with TTupleProtocol for efficiency
public class MyStruct implements TBase<MyStruct, MyStruct._Fields> {
private static final IScheme<MyStruct> TUPLE_SCHEME = new TupleScheme<MyStruct>();
// Use tuple scheme for efficient serialization
public void write(TTupleProtocol oprot) throws TException {
TUPLE_SCHEME.write(oprot, this);
}
public void read(TTupleProtocol iprot) throws TException {
TUPLE_SCHEME.read(iprot, this);
}
}Generated Thrift classes typically support both schemes and select based on the protocol type.
// Example of scheme selection in generated code
public class MyStruct implements TBase<MyStruct, MyStruct._Fields> {
private static final IScheme<MyStruct> STANDARD_SCHEME = new StandardScheme<MyStruct>();
private static final IScheme<MyStruct> TUPLE_SCHEME = new TupleScheme<MyStruct>();
public void read(TProtocol iprot) throws TException {
IScheme<MyStruct> scheme = getScheme(iprot);
scheme.read(iprot, this);
}
public void write(TProtocol oprot) throws TException {
IScheme<MyStruct> scheme = getScheme(oprot);
scheme.write(oprot, this);
}
private IScheme<MyStruct> getScheme(TProtocol proto) {
return (proto instanceof TTupleProtocol) ? TUPLE_SCHEME : STANDARD_SCHEME;
}
}Factories enable dynamic scheme creation and configuration.
/**
* Example scheme factory implementation
*/
public class MyStructSchemeFactory implements SchemeFactory {
public StandardScheme<MyStruct> getScheme() {
return new StandardScheme<MyStruct>();
}
}
/**
* Tuple scheme factory implementation
*/
public class MyStructTupleSchemeFactory implements SchemeFactory {
public TupleScheme<MyStruct> getScheme() {
return new TupleScheme<MyStruct>();
}
}Usage Examples:
import org.apache.thrift.scheme.SchemeFactory;
// Using scheme factories in generated code
public class MyStruct implements TBase<MyStruct, MyStruct._Fields> {
private static final Map<Class<? extends IScheme>, SchemeFactory> schemes =
new HashMap<Class<? extends IScheme>, SchemeFactory>();
static {
schemes.put(StandardScheme.class, new MyStructSchemeFactory());
schemes.put(TupleScheme.class, new MyStructTupleSchemeFactory());
}
public static SchemeFactory getSchemeFactory(Class<? extends IScheme> schemeClass) {
return schemes.get(schemeClass);
}
}Different protocols may prefer different schemes for optimal performance.
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TTupleProtocol;
import org.apache.thrift.transport.TMemoryBuffer;
// Example showing scheme selection based on protocol
public class SchemeExample {
public void demonstrateSchemes() throws TException {
MyStruct obj = new MyStruct();
obj.setName("example");
obj.setValue(42);
// Standard scheme with binary protocol
TMemoryBuffer buffer1 = new TMemoryBuffer(1024);
TBinaryProtocol binaryProto = new TBinaryProtocol(buffer1);
obj.write(binaryProto); // Uses StandardScheme automatically
// Tuple scheme with tuple protocol (more compact)
TMemoryBuffer buffer2 = new TMemoryBuffer(1024);
TTupleProtocol tupleProto = new TTupleProtocol(buffer2);
obj.write(tupleProto); // Uses TupleScheme automatically
// Tuple serialization is typically more compact
System.out.println("Binary protocol size: " + buffer1.length());
System.out.println("Tuple protocol size: " + buffer2.length());
}
}Advanced users can implement custom schemes for specialized serialization needs.
import org.apache.thrift.scheme.IScheme;
import org.apache.thrift.protocol.TProtocol;
// Example custom scheme that adds compression
public class CompressedScheme<T extends TBase> implements IScheme<T> {
private final IScheme<T> delegate;
public CompressedScheme(IScheme<T> delegate) {
this.delegate = delegate;
}
public void read(TProtocol iproto, T struct) throws TException {
// Add decompression logic here
// Then delegate to standard scheme
delegate.read(iproto, struct);
}
public void write(TProtocol oproto, T struct) throws TException {
// Delegate to standard scheme
delegate.write(oproto, struct);
// Add compression logic here
}
}
// Custom scheme factory
public class CompressedSchemeFactory implements SchemeFactory {
private final SchemeFactory delegateFactory;
public CompressedSchemeFactory(SchemeFactory delegateFactory) {
this.delegateFactory = delegateFactory;
}
public IScheme getScheme() {
return new CompressedScheme<>(delegateFactory.getScheme());
}
}Thrift code generators automatically create scheme support in generated classes:
// Typical generated class structure with scheme support
public class GeneratedStruct implements TBase<GeneratedStruct, GeneratedStruct._Fields> {
// Scheme instances
private static final IScheme<GeneratedStruct> STANDARD_SCHEME = new StandardScheme<GeneratedStruct>();
private static final IScheme<GeneratedStruct> TUPLE_SCHEME = new TupleScheme<GeneratedStruct>();
// Scheme selection based on protocol
private IScheme<GeneratedStruct> getScheme(TProtocol proto) {
return (proto instanceof TTupleProtocol) ? TUPLE_SCHEME : STANDARD_SCHEME;
}
// TBase implementation using schemes
public void read(TProtocol iprot) throws TException {
getScheme(iprot).read(iprot, this);
}
public void write(TProtocol oprot) throws TException {
getScheme(oprot).write(oprot, this);
}
}Schemes provide a powerful abstraction that allows Thrift objects to be serialized efficiently with different strategies while maintaining a consistent API. The choice between StandardScheme and TupleScheme typically depends on whether you need full field metadata (StandardScheme) or prefer compact serialization (TupleScheme).
Install with Tessl CLI
npx tessl i tessl/maven-org-apache-thrift--libthrift