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

type-strategy.mddocs/

Type Strategy and Polymorphic Handling

Advanced type identification and polymorphic serialization strategies for handling inheritance hierarchies, collections, and complex object structures. The type strategy system allows protostuff-runtime to handle polymorphic types, custom serialization delegates, and complex object graphs.

Capabilities

IdStrategy Base Class

Abstract base class defining the interface for type identification strategies used in polymorphic serialization.

/**
 * Abstract base class for type identification strategies
 */
public abstract class IdStrategy {
    
    /**
     * Configuration flags for strategy behavior
     */
    public final int flags;
    public final IdStrategy primaryGroup;
    public final int groupId;
    
    /**
     * Check if a delegate is registered for the specified type
     * @param typeClass The class to check
     * @return true if a delegate is registered
     */
    public abstract boolean isDelegateRegistered(Class<?> typeClass);
    
    /**
     * Get delegate wrapper for polymorphic contexts
     * @param typeClass The class to get delegate for
     * @return HasDelegate wrapper or null if not found
     */
    public abstract <T> HasDelegate<T> getDelegateWrapper(Class<? super T> typeClass);
    
    /**
     * Get delegate for the specified type
     * @param typeClass The class to get delegate for  
     * @return Delegate instance or null if not found
     */
    public abstract <T> Delegate<T> getDelegate(Class<? super T> typeClass);
    
    /**
     * Check if a type is registered with this strategy
     * @param typeClass The class to check
     * @return true if registered
     */
    public abstract boolean isRegistered(Class<?> typeClass);
    
    /**
     * Get schema wrapper for the specified type
     * @param typeClass The class to get schema for
     * @param create Whether to create if not found
     * @return HasSchema wrapper
     */
    public abstract <T> HasSchema<T> getSchemaWrapper(Class<T> typeClass, boolean create);
}

IdStrategy Configuration Flags

Configuration constants for controlling strategy behavior across various serialization scenarios.

/**
 * Serialize enums by name instead of ordinal value
 */
public static final int ENUMS_BY_NAME = 1;

/**
 * Automatically load polymorphic classes when encountered
 */
public static final int AUTO_LOAD_POLYMORPHIC_CLASSES = 1 << 1;

/**
 * Preserve null elements in collections and arrays
 */
public static final int PRESERVE_NULL_ELEMENTS = 1 << 2;

/**
 * Enable morphing for non-final POJO types
 */
public static final int MORPH_NON_FINAL_POJOS = 1 << 3;

/**
 * Enable morphing for collection interfaces (List, Set, etc.)
 */
public static final int MORPH_COLLECTION_INTERFACES = 1 << 4;

/**
 * Enable morphing for map interfaces
 */
public static final int MORPH_MAP_INTERFACES = 1 << 5;

/**
 * Use collection schema on repeated fields
 */
public static final int COLLECTION_SCHEMA_ON_REPEATED_FIELDS = 1 << 6;

/**
 * Use POJO schema on collection fields
 */
public static final int POJO_SCHEMA_ON_COLLECTION_FIELDS = 1 << 7;

/**
 * Use POJO schema on map fields
 */
public static final int POJO_SCHEMA_ON_MAP_FIELDS = 1 << 8;

/**
 * Default flags combining common settings
 */
public static final int DEFAULT_FLAGS;

DefaultIdStrategy Implementation

Concrete implementation of IdStrategy using fully qualified class names (FQCN) as type identifiers.

/**
 * Default ID strategy using fully qualified class names
 */
public final class DefaultIdStrategy extends IdStrategy {
    
    /**
     * Create DefaultIdStrategy with default settings
     */
    public DefaultIdStrategy();
    
    /**
     * Create DefaultIdStrategy with custom flags
     * @param flags Configuration flags
     */
    public DefaultIdStrategy(int flags);
    
    /**
     * Create DefaultIdStrategy with primary group
     * @param primaryGroup Primary strategy group
     * @param groupId Group identifier
     */
    public DefaultIdStrategy(IdStrategy primaryGroup, int groupId);
    
    /**
     * Create DefaultIdStrategy with all options
     * @param flags Configuration flags
     * @param primaryGroup Primary strategy group
     * @param groupId Group identifier
     */
    public DefaultIdStrategy(int flags, IdStrategy primaryGroup, int groupId);
}

POJO Type Registration

Methods for registering Plain Old Java Objects with the type strategy.

/**
 * Register a POJO type with automatic schema generation
 * @param typeClass The POJO class to register
 * @return true if registration was successful
 */
public <T> boolean registerPojo(Class<T> typeClass);

/**
 * Register a POJO type with custom schema
 * @param typeClass The POJO class to register
 * @param schema Custom schema for the POJO
 * @return true if registration was successful
 */
public <T> boolean registerPojo(Class<T> typeClass, Schema<T> schema);

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

Usage Examples:

DefaultIdStrategy strategy = new DefaultIdStrategy();

// Register POJOs
strategy.registerPojo(User.class);
strategy.registerPojo(Order.class);

// Register with custom schema
Schema<SpecialObject> customSchema = new MyCustomSchema();
strategy.registerPojo(SpecialObject.class, customSchema);

// Map inheritance hierarchies
strategy.map(Animal.class, Dog.class);
strategy.map(Animal.class, Cat.class);
strategy.map(Shape.class, Circle.class);
strategy.map(Shape.class, Rectangle.class);

Enum Type Registration

Support for registering and configuring enum serialization behavior.

/**
 * Register an enum type for polymorphic serialization
 * @param enumClass The enum class to register
 * @return true if registration was successful
 */
public <T extends Enum<T>> boolean registerEnum(Class<T> enumClass);

Usage Examples:

// Register enums for polymorphic handling
strategy.registerEnum(Status.class);
strategy.registerEnum(Priority.class);
strategy.registerEnum(Color.class);

// Configure enum serialization by name
DefaultIdStrategy strategyWithNames = new DefaultIdStrategy(IdStrategy.ENUMS_BY_NAME);
strategyWithNames.registerEnum(Status.class);

Delegate Registration

Register custom serialization delegates for specific types.

/**
 * Register a delegate for custom serialization
 * @param delegate The delegate implementation
 * @return true if registration was successful
 */
public <T> boolean registerDelegate(Delegate<T> delegate);

/**
 * Register a delegate by class name
 * @param className The fully qualified class name
 * @param delegate The delegate implementation
 * @return true if registration was successful
 */
public <T> boolean registerDelegate(String className, Delegate<T> delegate);

Usage Examples:

// Custom delegate for Date serialization
Delegate<Date> dateDelegate = new DateDelegate();
strategy.registerDelegate(dateDelegate);

// Register by class name (useful for optional dependencies)
strategy.registerDelegate("java.time.LocalDateTime", new LocalDateTimeDelegate());

Collection and Map Registration

Register factories for polymorphic collection and map handling.

/**
 * Register a collection factory for polymorphic collections
 * @param factory Collection message factory
 * @return true if registration was successful
 */
public boolean registerCollection(CollectionSchema.MessageFactory factory);

/**
 * Register a map factory for polymorphic maps
 * @param factory Map message factory
 * @return true if registration was successful
 */
public boolean registerMap(MapSchema.MessageFactory factory);

Usage Examples:

// Register custom collection factories
CollectionSchema.MessageFactory listFactory = new MyListFactory();
strategy.registerCollection(listFactory);

MapSchema.MessageFactory mapFactory = new MyMapFactory();
strategy.registerMap(mapFactory);

UnknownTypeException

Exception thrown when encountering unknown polymorphic types in strict mode.

/**
 * Exception thrown for unknown polymorphic types
 */
public static class UnknownTypeException extends RuntimeException {
    
    /**
     * Create exception with type information
     * @param type The unknown type
     */
    public UnknownTypeException(String type);
    
    /**
     * Create exception with type and cause
     * @param type The unknown type
     * @param cause The underlying cause
     */
    public UnknownTypeException(String type, Throwable cause);
}

IdStrategy Factory Interface

Factory interface for creating IdStrategy instances, useful for dependency injection and configuration.

/**
 * Factory interface for creating IdStrategy instances
 */
public interface Factory {
    
    /**
     * Create a new IdStrategy instance
     * @return New IdStrategy instance
     */
    IdStrategy create();
    
    /**
     * Post-creation configuration hook
     */
    void postCreate();
}

Configuration Examples

Basic Configuration

// Default strategy with standard settings
DefaultIdStrategy basicStrategy = new DefaultIdStrategy();

// Strategy with enum names instead of ordinals
DefaultIdStrategy enumNamesStrategy = new DefaultIdStrategy(IdStrategy.ENUMS_BY_NAME);

// Strategy with null preservation in collections
DefaultIdStrategy nullPreservingStrategy = new DefaultIdStrategy(
    IdStrategy.PRESERVE_NULL_ELEMENTS | IdStrategy.ENUMS_BY_NAME
);

Advanced Configuration

// Comprehensive strategy with multiple flags
int advancedFlags = IdStrategy.ENUMS_BY_NAME 
    | IdStrategy.AUTO_LOAD_POLYMORPHIC_CLASSES
    | IdStrategy.PRESERVE_NULL_ELEMENTS
    | IdStrategy.MORPH_NON_FINAL_POJOS
    | IdStrategy.COLLECTION_SCHEMA_ON_REPEATED_FIELDS;

DefaultIdStrategy advancedStrategy = new DefaultIdStrategy(advancedFlags);

// Register all application types
advancedStrategy.registerPojo(User.class);
advancedStrategy.registerPojo(Order.class);
advancedStrategy.registerPojo(Product.class);
advancedStrategy.registerEnum(Status.class);
advancedStrategy.registerEnum(Priority.class);

// Set up inheritance hierarchies
advancedStrategy.map(BaseEntity.class, User.class);
advancedStrategy.map(BaseEntity.class, Order.class);
advancedStrategy.map(BaseEntity.class, Product.class);

Custom Strategy Implementation

// Custom strategy extending DefaultIdStrategy
public class ApplicationIdStrategy extends DefaultIdStrategy {
    
    public ApplicationIdStrategy() {
        super(IdStrategy.ENUMS_BY_NAME | IdStrategy.PRESERVE_NULL_ELEMENTS);
        
        // Register application-specific types
        registerApplicationTypes();
    }
    
    private void registerApplicationTypes() {
        // POJOs
        registerPojo(User.class);
        registerPojo(Order.class);
        registerPojo(Product.class);
        
        // Enums
        registerEnum(Status.class);
        registerEnum(Priority.class);
        
        // Custom delegates
        registerDelegate(new TimestampDelegate());
        registerDelegate(new MoneyDelegate());
        
        // Inheritance mappings
        map(BaseEntity.class, User.class);
        map(BaseEntity.class, Order.class);
    }
}

Polymorphic Schema Factories

Enum defining factory types for different polymorphic schema scenarios.

/**
 * Predefined polymorphic schema factories
 */
public enum PolymorphicSchemaFactories {
    ARRAY,           // Array type factory
    NUMBER,          // Number type factory  
    CLASS,           // Class type factory
    ENUM,            // Enum type factory
    COLLECTION,      // Collection type factory
    MAP,             // Map type factory
    THROWABLE,       // Throwable type factory
    POJO,            // POJO type factory
    POJO_MAP,        // POJO map factory
    POJO_COLLECTION, // POJO collection factory
    OBJECT;          // Object type factory
    
    /**
     * Get factory from field information
     * @param f The field to analyze
     * @param strategy The ID strategy to use
     * @return Appropriate polymorphic schema factory
     */
    public static PolymorphicSchema.Factory getFactoryFromField(
        java.lang.reflect.Field f, IdStrategy strategy);
    
    /**
     * Get factory from generic type information
     * @param clazz The class with generic type information
     * @return Appropriate polymorphic schema factory
     */
    public static PolymorphicSchema.Factory getFactoryFromRepeatedValueGenericType(Class<?> clazz);
    
    /**
     * Get schema from collection or map generic type
     * @param clazz The collection or map class
     * @param strategy The ID strategy to use
     * @return Polymorphic schema instance
     */
    public static PolymorphicSchema getSchemaFromCollectionOrMapGenericType(
        Class<?> clazz, IdStrategy strategy);
}

Best Practices

  1. Strategy Configuration: Configure your IdStrategy with appropriate flags for your use case
  2. Type Registration: Register all polymorphic types upfront for better performance
  3. Inheritance Mapping: Use map() to establish clear inheritance relationships
  4. Custom Delegates: Implement delegates for types requiring special serialization logic
  5. Flag Combinations: Combine flags using bitwise OR operations for complex configurations
  6. Factory Pattern: Use IdStrategy.Factory for dependency injection scenarios

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