CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-protostuff--protostuff-runtime

Protobuf serialization for pre-existing objects with runtime schema generation and polymorphic type handling

Pending
Overview
Eval results
Files

schema-generation.mddocs/

Schema Generation and Management

Core functionality for creating, registering, and managing runtime schemas for Java classes. The RuntimeSchema class serves as the main entry point for all schema operations and provides both creation and optimization capabilities.

Capabilities

Schema Creation and Retrieval

Primary methods for obtaining schemas for Java classes, with automatic caching and type safety.

/**
 * Get or create a cached schema for the specified class using the default ID strategy
 * @param typeClass The class to create a schema for
 * @return Schema instance for the class
 */
public static <T> Schema<T> getSchema(Class<T> typeClass);

/**
 * Get or create a cached schema for the specified class with a custom ID strategy
 * @param typeClass The class to create a schema for
 * @param strategy Custom ID strategy for polymorphic type handling
 * @return Schema instance for the class
 */
public static <T> Schema<T> getSchema(Class<T> typeClass, IdStrategy strategy);

/**
 * Create a new RuntimeSchema instance for the specified class
 * @param typeClass The class to create a schema for
 * @return New RuntimeSchema instance
 */
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass);

/**
 * Create a new RuntimeSchema instance with custom ID strategy
 * @param typeClass The class to create a schema for
 * @param strategy Custom ID strategy for polymorphic type handling
 * @return New RuntimeSchema instance
 */
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass, IdStrategy strategy);

/**
 * Create a new RuntimeSchema instance with field exclusions using String array
 * @param typeClass The class to create a schema for
 * @param exclusions Array of field names to exclude from the schema
 * @param strategy Custom ID strategy for polymorphic type handling
 * @return New RuntimeSchema instance
 */
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass, String[] exclusions, IdStrategy strategy);

/**
 * Create a new RuntimeSchema instance with field exclusions
 * @param typeClass The class to create a schema for
 * @param exclusions Set of field names to exclude from the schema
 * @param strategy Custom ID strategy for polymorphic type handling
 * @return New RuntimeSchema instance
 */
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass, Set<String> exclusions, IdStrategy strategy);

/**
 * Create a new RuntimeSchema instance with custom field mappings
 * @param typeClass The class to create a schema for
 * @param declaredFields Map of field names to custom field mappings
 * @param strategy Custom ID strategy for polymorphic type handling
 * @return New RuntimeSchema instance
 */
public static <T> RuntimeSchema<T> createFrom(Class<T> typeClass, Map<String, String> declaredFields, IdStrategy strategy);

RuntimeSchema Constructors and Fields

Constructor methods and public fields available on RuntimeSchema instances.

/**
 * Constructor for RuntimeSchema with reflection-based constructor
 * @param typeClass The class this schema represents
 * @param fields Collection of field definitions
 * @param constructor Java constructor for creating instances
 */
public RuntimeSchema(Class<T> typeClass, Collection<Field<T>> fields, Constructor<T> constructor);

/**
 * Constructor for RuntimeSchema with custom instantiator
 * @param typeClass The class this schema represents  
 * @param fields Collection of field definitions
 * @param instantiator Custom instantiator for creating instances
 */
public RuntimeSchema(Class<T> typeClass, Collection<Field<T>> fields, Instantiator<T> instantiator);

/**
 * Public field providing access to the instantiator
 * Used for optimized object creation
 */
public final Instantiator<T> instantiator;

Usage Examples:

import io.protostuff.runtime.RuntimeSchema;
import io.protostuff.runtime.DefaultIdStrategy;
import io.protostuff.Schema;
import java.util.Set;

// Basic schema creation
Schema<User> userSchema = RuntimeSchema.getSchema(User.class);

// Schema with custom strategy
IdStrategy strategy = new DefaultIdStrategy(IdStrategy.ENUMS_BY_NAME);
Schema<User> customSchema = RuntimeSchema.getSchema(User.class, strategy);

// Create schema instance directly
RuntimeSchema<User> runtimeSchema = RuntimeSchema.createFrom(User.class);

// Exclude sensitive fields using String array
String[] exclusionsArray = {"password", "ssn"};
RuntimeSchema<User> filteredSchema1 = RuntimeSchema.createFrom(
    User.class, exclusionsArray, strategy
);

// Exclude sensitive fields using Set
Set<String> exclusionsSet = Set.of("password", "ssn");
RuntimeSchema<User> filteredSchema2 = RuntimeSchema.createFrom(
    User.class, exclusionsSet, strategy
);

// Access instantiator for optimized object creation
RuntimeSchema<User> schema = RuntimeSchema.createFrom(User.class);
Instantiator<User> instantiator = schema.instantiator;

// Use instantiator for fast object creation
User user1 = instantiator.newInstance();
User user2 = instantiator.newInstance();

Schema Registration and Optimization

Performance optimization methods for pre-registering schemas and mapping inheritance hierarchies.

/**
 * Pre-register a schema for the specified class for improved performance
 * @param typeClass The class to register
 * @return true if registration was successful, false if already registered
 */
public static <T> boolean register(Class<T> typeClass);

/**
 * Register a custom schema for the specified class
 * @param typeClass The class to register
 * @param schema Custom schema implementation
 * @return true if registration was successful, false if already registered
 */
public static <T> boolean register(Class<T> typeClass, Schema<T> schema);

/**
 * Map a concrete class to its base class for inheritance handling
 * @param baseClass The base/parent class
 * @param typeClass The concrete/child class
 * @return true if mapping was successful
 */
public static <T> boolean map(Class<? super T> baseClass, Class<T> typeClass);

/**
 * Check if a class has been registered
 * @param typeClass The class to check
 * @return true if the class is registered
 */
public static boolean isRegistered(Class<?> typeClass);

/**
 * Check if a class has been registered with a specific strategy
 * @param typeClass The class to check
 * @param strategy The ID strategy to check against
 * @return true if the class is registered with the specified strategy
 */
public static boolean isRegistered(Class<?> typeClass, IdStrategy strategy);

Usage Examples:

// Pre-register for performance
RuntimeSchema.register(User.class);
RuntimeSchema.register(Order.class);
RuntimeSchema.register(Product.class);

// Register custom schema
Schema<SpecialObject> customSchema = new MyCustomSchema();
RuntimeSchema.register(SpecialObject.class, customSchema);

// Map inheritance hierarchy
RuntimeSchema.map(Animal.class, Dog.class);
RuntimeSchema.map(Animal.class, Cat.class);
RuntimeSchema.map(Vehicle.class, Car.class);

// Check registration status
if (!RuntimeSchema.isRegistered(User.class)) {
    RuntimeSchema.register(User.class);
}

Schema Constants and Configuration

Important constants for field number validation and schema configuration.

/**
 * Minimum valid protobuf tag/field number
 */
public static final int MIN_TAG_VALUE = 1;

/**
 * Maximum valid protobuf tag/field number (2^29 - 1)
 */
public static final int MAX_TAG_VALUE = 536870911;

/**
 * Threshold for using hash-based field maps instead of array-based maps
 */
public static final int MIN_TAG_FOR_HASH_FIELD_MAP = 100;

RuntimeSchema Instance Methods

Methods available on RuntimeSchema instances for field access and schema information.

/**
 * Get the Java class this schema represents
 * @return The class type
 */
public Class<T> typeClass();

/**
 * Get the message name for this schema
 * @return Message name string
 */
public String messageName();

/**
 * Get the full message name for this schema
 * @return Full message name string
 */
public String messageFullName();

/**
 * Get field by its protobuf field number
 * @param number The field number
 * @return Field instance or null if not found
 */
public Field<T> getFieldByNumber(int number);

/**
 * Get field by its name
 * @param fieldName The field name
 * @return Field instance or null if not found
 */
public Field<T> getFieldByName(String fieldName);

/**
 * Get the total number of fields in this schema
 * @return Field count
 */
public int getFieldCount();

/**
 * Get all fields as a list
 * @return List of all fields
 */
public List<Field<T>> getFields();

/**
 * Get the field name for a given field number
 * @param number The field number
 * @return Field name or null if not found
 */
public String getFieldName(int number);

/**
 * Get the field number for a given field name
 * @param name The field name
 * @return Field number or 0 if not found
 */
public int getFieldNumber(String name);

/**
 * Get the pipe schema for streaming operations
 * @return Pipe schema instance
 */
public Pipe.Schema<T> getPipeSchema();

/**
 * Create a new instance of the schema's type
 * @return New instance of T
 */
public T newMessage();

/**
 * Check if a message instance is fully initialized
 * @param message The message to check
 * @return true if initialized
 */
public boolean isInitialized(T message);

Usage Examples:

RuntimeSchema<User> schema = RuntimeSchema.createFrom(User.class);

// Access schema information  
Class<User> userClass = schema.typeClass();
String messageName = schema.messageName();
int fieldCount = schema.getFieldCount();

// Field access
Field<User> nameField = schema.getFieldByName("name");
Field<User> ageField = schema.getFieldByNumber(2);
List<Field<User>> allFields = schema.getFields();

// Create new instances
User newUser = schema.newMessage();

// Check field mappings
String fieldName = schema.getFieldName(1);
int fieldNumber = schema.getFieldNumber("email");

Field Number Management

Protostuff Runtime automatically assigns field numbers based on field discovery order, but you can control this through:

  1. Field ordering: Fields are processed in declaration order by default
  2. Custom field mappings: Use createFrom with custom field mappings
  3. Field exclusions: Use createFrom with exclusions to skip specific fields
  4. Annotations: Use protostuff annotations to explicitly control field numbers (requires additional dependencies)

Performance Considerations

  • Registration: Pre-register frequently used classes with register() for better performance
  • Caching: getSchema() automatically caches schemas, reuse the same Schema instances
  • Field Maps: Large schemas (>100 fields) automatically use hash-based field maps for better lookup performance
  • Inheritance Mapping: Use map() to establish inheritance relationships for polymorphic serialization

Common Patterns

// Application startup: register all schemas
public class SchemaRegistry {
    static {
        RuntimeSchema.register(User.class);
        RuntimeSchema.register(Order.class);
        RuntimeSchema.register(Product.class);
        
        // Inheritance mappings
        RuntimeSchema.map(BaseEntity.class, User.class);
        RuntimeSchema.map(BaseEntity.class, Order.class);
    }
}

// Service layer: use cached schemas
public class SerializationService {
    private static final Schema<User> USER_SCHEMA = RuntimeSchema.getSchema(User.class);
    
    public void processUser(User user) {
        // Use USER_SCHEMA for serialization operations
    }
}

// Dynamic schema creation with filtering
public <T> Schema<T> createFilteredSchema(Class<T> clazz, Set<String> sensitiveFields) {
    return RuntimeSchema.createFrom(clazz, sensitiveFields, RuntimeEnv.ID_STRATEGY);
}

Install with Tessl CLI

npx tessl i tessl/maven-io-protostuff--protostuff-runtime

docs

annotations.md

custom-serialization.md

field-access.md

index.md

polymorphic-schemas.md

runtime-environment.md

schema-generation.md

type-strategy.md

tile.json