Protobuf serialization for pre-existing objects with runtime schema generation and polymorphic type handling
npx @tessl/cli install tessl/maven-io-protostuff--protostuff-runtime@1.8.0Protostuff Runtime provides runtime schema generation and serialization capabilities for protocol buffers in Java, enabling efficient serialization of pre-existing Java objects without requiring compile-time code generation. It offers dynamic schema creation at runtime, automatic field mapping and validation, support for complex object hierarchies including inheritance and polymorphism, and pluggable serialization formats.
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.8.0</version>
</dependency>import io.protostuff.runtime.RuntimeSchema;
import io.protostuff.runtime.DefaultIdStrategy;
import io.protostuff.runtime.RuntimeEnv;
import io.protostuff.runtime.IdStrategy;
import io.protostuff.runtime.Delegate;
import io.protostuff.Tag;
import io.protostuff.Exclude;
import io.protostuff.Schema;import io.protostuff.runtime.RuntimeSchema;
import io.protostuff.Schema;
import io.protostuff.Tag;
import io.protostuff.Exclude;
// Create and use a schema for your class with annotations
public class User {
@Tag(1)
public String name;
@Tag(2)
public int age;
@Tag(3)
public boolean active;
@Exclude // This field will not be serialized
public String password;
}
// Get schema for the User class
Schema<User> schema = RuntimeSchema.getSchema(User.class);
// Register schema for better performance (optional)
RuntimeSchema.register(User.class);
// Create and populate user object
User user = new User();
user.name = "Alice";
user.age = 25;
user.active = true;
user.password = "secret"; // Will be ignored during serialization
// The schema can now be used with any protostuff serialization format
// (requires protostuff-core dependency for actual serialization)
// Example: byte[] data = ProtostuffIOUtil.toByteArray(user, schema, buffer);Protostuff Runtime is built around several key components:
RuntimeSchema creates schemas dynamically at runtime by introspecting Java classesIdStrategy and DefaultIdStrategy handle polymorphic type identification and serializationField, FieldMap, and Accessor abstractionsDelegate system allows custom serialization for specific typesRuntimeEnv provides configuration and optimization settings@Tag, @Exclude, and @Morph annotations for field-level configurationInstantiator implementationsCore functionality for creating, registering, and managing runtime schemas for Java classes. Essential for all serialization operations.
// Main schema operations
public static <T> Schema<T> getSchema(Class<T> typeClass);
public static <T> Schema<T> getSchema(Class<T> typeClass, IdStrategy strategy);
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass);
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass, IdStrategy strategy);
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass, String[] exclusions, IdStrategy strategy);
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass, Set<String> exclusions, IdStrategy strategy);
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass, Map<String, String> declaredFields, IdStrategy strategy);
// Registration for performance optimization
public static <T> boolean register(Class<T> typeClass);
public static <T> boolean register(Class<T> typeClass, Schema<T> schema);
public static <T> boolean map(Class<? super T> baseClass, Class<T> typeClass);
public static boolean isRegistered(Class<?> typeClass);
public static boolean isRegistered(Class<?> typeClass, IdStrategy strategy);
// Schema constants
public static final int MIN_TAG_VALUE = 1;
public static final int MAX_TAG_VALUE = 536870911;Advanced type identification and polymorphic serialization strategies for handling inheritance hierarchies, collections, and complex object structures.
// IdStrategy base functionality
public abstract boolean isDelegateRegistered(Class<?> typeClass);
public abstract <T> HasDelegate<T> getDelegateWrapper(Class<? super T> typeClass);
public abstract <T> Delegate<T> getDelegate(Class<? super T> typeClass);
public abstract boolean isRegistered(Class<?> typeClass);
public abstract <T> HasSchema<T> getSchemaWrapper(Class<T> typeClass, boolean create);
// DefaultIdStrategy implementation
public <T> boolean registerPojo(Class<T> typeClass);
public <T> boolean registerPojo(Class<T> typeClass, Schema<T> schema);
public <T extends Enum<T>> boolean registerEnum(Class<T> enumClass);
public <T> boolean registerDelegate(Delegate<T> delegate);System for implementing custom serialization logic for specific types, providing higher priority than default serializers.
// Delegate interface
public interface Delegate<V> {
FieldType getFieldType();
V readFrom(Input input) throws IOException;
void writeTo(Output output, int number, V value, boolean repeated) throws IOException;
void transfer(Pipe pipe, Input input, Output output, int number, boolean repeated) throws IOException;
Class<?> typeClass();
}
// HasDelegate wrapper
public Delegate<T> getDelegate();Environment configuration, optimization settings, and utility classes for controlling runtime behavior and performance characteristics.
// Runtime environment constants and settings
public static final boolean ENUMS_BY_NAME;
public static final boolean AUTO_LOAD_POLYMORPHIC_CLASSES;
public static final boolean PRESERVE_NULL_ELEMENTS;
public static final boolean USE_SUN_MISC_UNSAFE;
public static final IdStrategy ID_STRATEGY;
// Object instantiation utilities
public static <T> Instantiator<T> newInstantiator(Class<T> clazz);
// Instantiator interface
public abstract class Instantiator<T> {
public abstract T newInstance();
}Low-level field access optimization and reflection utilities for high-performance field operations.
// Field access abstraction
public abstract class Field<T> {
public final WireFormat.FieldType type;
public final int number;
public final String name;
public final boolean repeated;
public final int groupFilter;
}
// Field value accessor for optimization
public abstract class Accessor {
public abstract void set(Object owner, Object value);
public abstract <T> T get(Object owner);
}Factory system for creating polymorphic schemas that handle inheritance, collections, and complex object hierarchies.
// Polymorphic schema factory enum
public enum PolymorphicSchemaFactories implements PolymorphicSchema.Factory {
ARRAY, NUMBER, CLASS, ENUM, COLLECTION, MAP, THROWABLE, POJO, POJO_MAP, POJO_COLLECTION, OBJECT;
}
// Factory methods for polymorphic handling
public static PolymorphicSchema.Factory getFactoryFromField(java.lang.reflect.Field f, IdStrategy strategy);
public static PolymorphicSchema getSchemaFromCollectionOrMapGenericType(Class<?> clazz, IdStrategy strategy);Field-level configuration annotations for controlling serialization behavior, field numbers, and exclusions.
// Tag annotation for field number assignment
@Target(ElementType.FIELD)
public @interface Tag {
int value();
String alias() default "";
int groupFilter() default 0;
}
// Exclude annotation for skipping fields
@Target(ElementType.FIELD)
public @interface Exclude {
}
// Morph annotation for polymorphic behavior
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface Morph {
boolean value() default true;
}Protostuff Runtime may throw the following exceptions:
IllegalArgumentException - Invalid field numbers, null class parameters, or invalid configurationIdStrategy.UnknownTypeException - Unknown polymorphic types when using strict type strategiesRuntimeException - General runtime errors during schema generation or field accessIOException - I/O errors during serialization/deserialization operations (when used with serialization libraries)// Core schema interface (implemented by RuntimeSchema)
public interface Schema<T> {
String messageName();
String messageFullName();
Class<T> typeClass();
T newMessage();
boolean isInitialized(T message);
void mergeFrom(Input input, T message) throws IOException;
void writeTo(Output output, T message) throws IOException;
String getFieldName(int number);
int getFieldNumber(String name);
}
// Field map interface for schema field access
public interface FieldMap<T> {
Field<T> getFieldByNumber(int n);
Field<T> getFieldByName(String fieldName);
int getFieldCount();
List<Field<T>> getFields();
}
// Field representation
public abstract class Field<T> {
public final WireFormat.FieldType type;
public final int number;
public final String name;
public final boolean repeated;
public final int groupFilter;
protected abstract void writeTo(Output output, T message) throws IOException;
protected abstract void mergeFrom(Input input, T message) throws IOException;
}
// Schema wrapper for polymorphic contexts
public abstract class HasSchema<T> {
public abstract Schema<T> getSchema();
public abstract Pipe.Schema<T> getPipeSchema();
}
// Delegate wrapper for polymorphic contexts
public class HasDelegate<T> {
public Delegate<T> getDelegate();
}
// RuntimeSchema class extends Schema and implements FieldMap
public class RuntimeSchema<T> implements Schema<T>, FieldMap<T> {
public final Instantiator<T> instantiator;
// Constructors
public RuntimeSchema(Class<T> typeClass, Collection<Field<T>> fields, Constructor<T> constructor);
public RuntimeSchema(Class<T> typeClass, Collection<Field<T>> fields, Instantiator<T> instantiator);
// Schema interface methods
public Pipe.Schema<T> getPipeSchema();
}
// IdStrategy configuration flags
public abstract class IdStrategy {
public static final int ENUMS_BY_NAME = 1;
public static final int AUTO_LOAD_POLYMORPHIC_CLASSES = 2;
public static final int PRESERVE_NULL_ELEMENTS = 4;
public static final int MORPH_NON_FINAL_POJOS = 8;
public static final int MORPH_COLLECTION_INTERFACES = 16;
public static final int MORPH_MAP_INTERFACES = 32;
public static final int COLLECTION_SCHEMA_ON_REPEATED_FIELDS = 64;
public static final int POJO_SCHEMA_ON_COLLECTION_FIELDS = 128;
public static final int POJO_SCHEMA_ON_MAP_FIELDS = 256;
public static final int DEFAULT_FLAGS;
}