Skip to content

InstantClasses

Unit: InstantClassesCategory: Core

Overview

The InstantClasses unit provides fundamental infrastructure classes for InstantObjects. These base classes handle exceptions, streaming, serialization, collections, and XML support used throughout the framework.

Key Components:

  • Exception System - Hierarchical exception classes
  • Streaming - Binary and XML serialization
  • Collections - Extended collection classes with naming
  • Readers/Writers - Low-level stream reading/writing
  • Converters - Binary ↔ XML conversion
  • Abstract Bases - Base classes for objects and attributes
  • Utilities - Helper functions and classes

Exception Hierarchy

EInstantError

Base exception class for all InstantObjects exceptions.

Inheritance: ExceptionEInstantError

Key Features

  • Wraps original exceptions
  • Resource string support
  • Formatted messages
  • Exception chaining

Properties

PropertyTypeDescription
OriginalExceptionTObjectWrapped original exception (if any)

Constructors

pascal
constructor Create(const Msg: string; E: TObject = nil);
constructor CreateFmt(const Msg: string; const Args: array of const; E: TObject = nil);
constructor CreateRes(ResStringRec: PResStringRec; E: TObject = nil);
constructor CreateResFmt(ResStringRec: PResStringRec; const Args: array of const; E: TObject = nil);

Example Usage

pascal
// Simple message
raise EInstantError.Create('Object not found');

// Formatted message
raise EInstantError.CreateFmt('Object %s not found', [ObjectId]);

// Wrap exception
try
  // Database operation
except
  on E: EDatabaseError do
    raise EInstantError.Create('Database operation failed', E);
end;

// Resource string
raise EInstantError.CreateRes(@SInstantObjectNotFound);

// Formatted resource string
raise EInstantError.CreateResFmt(@SInstantInvalidValue, [FieldName, Value]);

Exception Handling

pascal
try
  Contact.Store;
except
  on E: EInstantError do
  begin
    ShowMessage('InstantObjects error: ' + E.Message);

    // Check for original exception
    if Assigned(E.OriginalException) then
      if E.OriginalException is EDatabaseError then
        ShowMessage('Database error: ' + EDatabaseError(E.OriginalException).Message);
  end;
end;

Specialized Exception Classes

pascal
EInstantStreamError = class(EInstantError)       // Stream operations
EInstantValidationError = class(EInstantError)   // Validation failures
EInstantRangeError = class(EInstantError)        // Value out of range
EInstantConversionError = class(EInstantError)   // Type conversion errors

Usage:

pascal
// Validation error
if not IsValidEmail(Email) then
  raise EInstantValidationError.CreateFmt('Invalid email: %s', [Email]);

// Range error
if Age < 0 then
  raise EInstantRangeError.CreateFmt('Age must be >= 0, got %d', [Age]);

// Conversion error
try
  IntValue := StrToInt(StringValue);
except
  on E: EConvertError do
    raise EInstantConversionError.Create('Cannot convert to integer', E);
end;

TInstantStreamable

Base class for objects that can be serialized to/from streams.

Inheritance: TPersistentTInstantStreamable

Key Methods

pascal
// Streaming
procedure LoadFromStream(Stream: TStream; ProcessEvent: TInstantProcessObjectEvent = nil);
procedure SaveToStream(Stream: TStream; ProcessEvent: TInstantProcessObjectEvent = nil);

// Assign from another instance
procedure Assign(Source: TPersistent); override;

Protected Methods

pascal
// Override in descendants for custom serialization
procedure ReadObject(Reader: TInstantReader); virtual;
procedure WriteObject(Writer: TInstantWriter); virtual;

// Conversion support
class procedure ConvertToBinary(Converter: TInstantTextToBinaryConverter); virtual;
class procedure ConvertToText(Converter: TInstantBinaryToTextConverter); virtual;

// Factory method
class function CreateInstance(Arg: Pointer = nil): TInstantStreamable; virtual;

Example Usage

pascal
type
  TMyData = class(TInstantStreamable)
  private
    FName: string;
    FValue: Integer;
  protected
    procedure ReadObject(Reader: TInstantReader); override;
    procedure WriteObject(Writer: TInstantWriter); override;
  end;

procedure TMyData.ReadObject(Reader: TInstantReader);
begin
  inherited;
  FName := Reader.ReadString;
  FValue := Reader.ReadInteger;
end;

procedure TMyData.WriteObject(Writer: TInstantWriter);
begin
  inherited;
  Writer.WriteString(FName);
  Writer.WriteInteger(FValue);
end;

// Usage
var
  Data: TMyData;
  Stream: TFileStream;
begin
  Data := TMyData.Create;
  try
    Data.FName := 'Test';
    Data.FValue := 42;

    Stream := TFileStream.Create('data.bin', fmCreate);
    try
      Data.SaveToStream(Stream);
    finally
      Stream.Free;
    end;
  finally
    Data.Free;
  end;
end;

Collection Classes

TInstantCollectionItem

Enhanced TCollectionItem with name support.

Inheritance: TCollectionItemTInstantCollectionItem

Key Properties

PropertyTypeDescription
NamestringItem name
DisplayNamestringDisplay name (defaults to Name)

Key Methods

pascal
procedure Assign(Source: TPersistent); override;

// Streaming support
procedure ReadObject(Reader: TInstantReader); virtual;
procedure WriteObject(Writer: TInstantWriter); virtual;

// Factory
class function CreateInstance(Arg: Pointer = nil): TInstantCollectionItem; virtual;

Example

pascal
type
  TMyItem = class(TInstantCollectionItem)
  private
    FValue: Integer;
  published
    property Value: Integer read FValue write FValue;
  end;

var
  Item: TMyItem;
begin
  Item := TMyItem(Collection.Add);
  Item.Name := 'Item1';
  Item.Value := 100;
end;

TInstantCollection

Enhanced TCollection with name-based access.

Inheritance: TCollectionTInstantCollection

Key Methods

pascal
constructor Create(ItemClass: TInstantCollectionItemClass);

// Name-based access
function Find(const AName: string): TInstantCollectionItem;
function IndexOf(const AName: string): Integer; overload;
function IndexOf(Item: TInstantCollectionItem): Integer; overload;
function Remove(Item: TInstantCollectionItem): Integer;

// Utilities
procedure GetItemNames(List: TStrings);

// Streaming
procedure ReadObject(Reader: TInstantReader); virtual;
procedure WriteObject(Writer: TInstantWriter); virtual;

// Factory
class function CreateInstance(Arg: Pointer = nil): TInstantCollection; virtual;

Example Usage

pascal
var
  Collection: TInstantCollection;
  Item: TInstantCollectionItem;
  Names: TStringList;
begin
  Collection := TInstantCollection.Create(TMyItem);
  try
    // Add items
    Item := Collection.Add;
    Item.Name := 'First';

    Item := Collection.Add;
    Item.Name := 'Second';

    // Find by name
    Item := Collection.Find('First');
    if Assigned(Item) then
      ShowMessage('Found: ' + Item.Name);

    // Get all names
    Names := TStringList.Create;
    try
      Collection.GetItemNames(Names);
      ShowMessage(Names.CommaText);
    finally
      Names.Free;
    end;

    // Remove by name
    Item := Collection.Find('Second');
    if Assigned(Item) then
      Collection.Remove(Item);
  finally
    Collection.Free;
  end;
end;

TInstantOwnedCollection

Collection with owner reference.

Inheritance: TInstantCollectionTInstantOwnedCollection

Key Properties

PropertyTypeDescription
OwnerTPersistentCollection owner

Constructor

pascal
constructor Create(AOwner: TPersistent; ItemClass: TInstantCollectionItemClass);

Example

pascal
type
  TMyObject = class(TPersistent)
  private
    FItems: TInstantOwnedCollection;
  public
    constructor Create;
    destructor Destroy; override;
    property Items: TInstantOwnedCollection read FItems;
  end;

constructor TMyObject.Create;
begin
  inherited;
  FItems := TInstantOwnedCollection.Create(Self, TMyItem);
end;

destructor TMyObject.Destroy;
begin
  FItems.Free;
  inherited;
end;

// Usage
var
  MyObj: TMyObject;
begin
  MyObj := TMyObject.Create;
  try
    ShowMessage('Owner: ' + MyObj.Items.Owner.ClassName);  // TMyObject
  finally
    MyObj.Free;
  end;
end;

Reader and Writer Classes

TInstantReader

Low-level stream reader for object serialization.

Inheritance: TAbstractReaderTInstantReader

Key Methods

pascal
constructor Create(Stream: TStream; BufSize: Integer = InstantBufferSize);

// Read operations
function ReadObject(AObject: TPersistent = nil; Arg: Pointer = nil): TPersistent; virtual;
procedure ReadProperties(AObject: TPersistent);
procedure ReadBinary(ReadData: TStreamProc);
procedure SkipValue;

Properties

PropertyTypeDescription
StreamTStreamUnderlying stream

Example

pascal
var
  Reader: TInstantReader;
  Stream: TFileStream;
  Obj: TMyObject;
begin
  Stream := TFileStream.Create('object.bin', fmOpenRead);
  try
    Reader := TInstantReader.Create(Stream);
    try
      Obj := Reader.ReadObject as TMyObject;
      try
        // Use object
      finally
        Obj.Free;
      end;
    finally
      Reader.Free;
    end;
  finally
    Stream.Free;
  end;
end;

TInstantWriter

Low-level stream writer for object serialization.

Inheritance: TAbstractWriterTInstantWriter

Key Methods

pascal
constructor Create(Stream: TStream; BufSize: Integer = InstantBufferSize);

// Write operations
procedure WriteObject(AObject: TPersistent); virtual;
procedure WriteProperties(AObject: TPersistent);
procedure WriteBinary(WriteData: TStreamProc);
procedure WriteValue(Value: TValueType);

Properties

PropertyTypeDescription
StreamTStreamUnderlying stream

Example

pascal
var
  Writer: TInstantWriter;
  Stream: TFileStream;
  Obj: TMyObject;
begin
  Obj := TMyObject.Create;
  try
    Stream := TFileStream.Create('object.bin', fmCreate);
    try
      Writer := TInstantWriter.Create(Stream);
      try
        Writer.WriteObject(Obj);
      finally
        Writer.Free;
      end;
    finally
      Stream.Free;
    end;
  finally
    Obj.Free;
  end;
end;

Stream Classes

TInstantStream

Enhanced stream with object serialization support.

Inheritance: TStreamTInstantStream

Key Properties

PropertyTypeDescription
SourceTStreamUnderlying stream
FreeSourceBooleanFree source on destroy
OnProcessObjectTInstantProcessObjectEventObject processing callback

Key Methods

pascal
constructor Create(ASource: TStream = nil; AFreeSource: Boolean = False);

// Object operations
function ReadObject(AObject: TPersistent = nil; Arg: Pointer = nil): TPersistent;
procedure WriteObject(AObject: TPersistent);

// Resource operations
function ReadObjectRes(AObject: TPersistent = nil; Arg: Pointer = nil): TPersistent;
procedure WriteObjectRes(const ResName: string; AObject: TPersistent);

// Alignment
procedure AlignStream;

Example

pascal
var
  InstStream: TInstantStream;
  FileStream: TFileStream;
  Obj: TMyObject;
begin
  FileStream := TFileStream.Create('data.dat', fmOpenRead);
  try
    InstStream := TInstantStream.Create(FileStream, True);  // Will free FileStream
    try
      Obj := InstStream.ReadObject as TMyObject;
      try
        // Use object
      finally
        Obj.Free;
      end;
    finally
      InstStream.Free;  // Also frees FileStream
    end;
  except
    FileStream.Free;  // Only if InstantStream creation failed
    raise;
  end;
end;

TInstantResourceStream

Stream for reading Windows resources.

Inheritance: TInstantStreamTInstantResourceStream

Constructors

pascal
constructor Create(Instance: THandle; const ResName: string; ResType: PChar);
constructor CreateFromId(Instance: THandle; ResID: Integer; ResType: PChar);

Example

pascal
var
  ResStream: TInstantResourceStream;
  Model: TInstantModel;
begin
  ResStream := TInstantResourceStream.Create(HInstance, 'MODEL', RT_RCDATA);
  try
    Model := ResStream.ReadObject as TInstantModel;
    try
      // Use model
    finally
      Model.Free;
    end;
  finally
    ResStream.Free;
  end;
end;

TInstantFileStream

Simplified file stream with object support.

Inheritance: TInstantStreamTInstantFileStream

Constructor

pascal
constructor Create(const FileName: string; Mode: Word);

Example

pascal
var
  FileStream: TInstantFileStream;
  Obj: TMyObject;
begin
  FileStream := TInstantFileStream.Create('data.dat', fmOpenRead);
  try
    Obj := FileStream.ReadObject as TMyObject;
    try
      // Use object
    finally
      Obj.Free;
    end;
  finally
    FileStream.Free;
  end;
end;

XML Support Classes

TInstantXMLProducer

Generates XML from binary stream.

Inheritance: TObjectTInstantXMLProducer

Key Properties

PropertyTypeDescription
StreamTStreamOutput XML stream
CurrentTagstringCurrent open tag
EofBooleanEnd of output reached
PositionIntegerCurrent stream position

Key Methods

pascal
// Tag operations
procedure WriteStartTag(const TagName: string);
procedure WriteEndTag;
procedure WriteAnyTag(const TagName: string);

// Data operations
procedure WriteData(const Data: string);

TInstantXMLProcessor

Parses XML into binary stream.

Inheritance: TObjectTInstantXMLProcessor

Key Properties

PropertyTypeDescription
StreamTStreamInput XML stream
CurrentTagstringCurrent tag being processed
TokenTInstantXMLTokenCurrent token type

Key Methods

pascal
// Token reading
function ReadToken: TInstantXMLToken;
procedure MatchToken(AToken: TInstantXMLToken);
function MatchText(const AText: string): Boolean;

// Tag matching
function MatchStartTag(const TagName: string): Boolean;
function MatchEndTag: Boolean;
procedure MatchAnyTag;

Token Types

pascal
type
  TInstantXMLToken = (
    xtNone,      // No token
    xtStartTag,  // <Tag>
    xtEndTag,    // </Tag>
    xtAnyTag,    // <Tag/>
    xtData       // Text content
  );

Converter Classes

TInstantBinaryToTextConverter

Converts binary stream to XML.

Inheritance: TInstantConverterTInstantBinaryToTextConverter

Constructor

pascal
constructor Create(Input, Output: TStream);

Key Methods

pascal
procedure Convert;
procedure ConvertProperties;

Example

pascal
var
  BinaryStream, XMLStream: TStream;
  Converter: TInstantBinaryToTextConverter;
begin
  BinaryStream := TFileStream.Create('data.bin', fmOpenRead);
  try
    XMLStream := TFileStream.Create('data.xml', fmCreate);
    try
      Converter := TInstantBinaryToTextConverter.Create(BinaryStream, XMLStream);
      try
        Converter.Convert;
      finally
        Converter.Free;
      end;
    finally
      XMLStream.Free;
    end;
  finally
    BinaryStream.Free;
  end;
end;

TInstantTextToBinaryConverter

Converts XML to binary stream.

Inheritance: TInstantConverterTInstantTextToBinaryConverter

Constructor

pascal
constructor Create(Input, Output: TStream);

Key Methods

pascal
procedure Convert;
procedure ConvertProperties;
procedure ConvertProperties(const StopTag: string); overload;

Example

pascal
var
  XMLStream, BinaryStream: TStream;
  Converter: TInstantTextToBinaryConverter;
begin
  XMLStream := TFileStream.Create('data.xml', fmOpenRead);
  try
    BinaryStream := TFileStream.Create('data.bin', fmCreate);
    try
      Converter := TInstantTextToBinaryConverter.Create(XMLStream, BinaryStream);
      try
        Converter.Convert;
      finally
        Converter.Free;
      end;
    finally
      BinaryStream.Free;
    end;
  finally
    XMLStream.Free;
  end;
end;

Abstract Base Classes

TInstantAbstractObject

Abstract base for persistent objects (parent of TInstantObject).

Inheritance: TInstantStreamableTInstantAbstractObject

Key Properties

PropertyTypeDescription
ConnectorTComponentAssociated connector

Abstract Methods

pascal
constructor Retrieve(const AObjectId: string; CreateIfMissing: Boolean = False;
  Refresh: Boolean = False; AConnector: TComponent = nil;
  const AObjectData: TInstantAbstractObjectData = nil); virtual; abstract;

TInstantAbstractAttribute

Abstract base for attributes.

Inheritance: TInstantStreamableTInstantAbstractAttribute

Key Properties

PropertyTypeDescription
OwnerTInstantAbstractObjectOwning object
MetadataTInstantCollectionItemAttribute metadata

Constructor

pascal
constructor Create(AOwner: TInstantAbstractObject; AMetadata: TInstantCollectionItem); virtual;

Abstract Methods

pascal
procedure Initialize; virtual; abstract;

Stream Format Enumeration

TInstantStreamFormat

Defines serialization formats.

pascal
type
  TInstantStreamFormat = (
    sfBinary,    // Binary format (default)
    sfXML,       // XML text format
    sfJSON       // JSON format (if DELPHI_NEON defined)
  );

Format Descriptions:

pascal
const
  AInstantStreamFormatStr: array[TInstantStreamFormat] of string = (
    'Binary format',
    'XML format'
    {$IFDEF DELPHI_NEON}
    , 'JSON format'
    {$ENDIF}
  );

Utility Functions

Object Streaming Functions

pascal
// Read object from stream
function InstantReadObject(Stream: TStream; Format: TInstantStreamFormat;
  AObject: TPersistent = nil): TPersistent;

function InstantReadObjectFromStream(Stream: TStream;
  AObject: TPersistent = nil;
  ProcessEvent: TInstantProcessObjectEvent = nil;
  Arg: Pointer = nil): TPersistent;

// Write object to stream
procedure InstantWriteObject(Stream: TStream; Format: TInstantStreamFormat;
  AObject: TPersistent);

procedure InstantWriteObjectToStream(Stream: TStream; AObject: TPersistent;
  ProcessEvent: TInstantProcessObjectEvent = nil);

Multiple Objects

pascal
// Read multiple objects
procedure InstantReadObjects(Stream: TStream; Format: TInstantStreamFormat;
  Objects: TList);

// Write multiple objects
procedure InstantWriteObjects(Stream: TStream; Format: TInstantStreamFormat;
  Objects: TList);

Conversion Functions

pascal
// Convert between binary and XML
procedure InstantObjectBinaryToText(Input, Output: TStream);
procedure InstantObjectTextToBinary(Input, Output: TStream);

XML Tag Functions

pascal
// Build XML tags
function InstantBuildStartTag(const TagName: string): string;
function InstantBuildEndTag(const TagName: string): string;

Class Checking

pascal
// Verify class inheritance
procedure InstantCheckClass(AClass: TClass; MinimumClass: TClass);

Usage Examples

Save/Load with Different Formats

pascal
procedure SaveObject(Obj: TPersistent; const FileName: string;
  Format: TInstantStreamFormat);
var
  Stream: TFileStream;
begin
  Stream := TFileStream.Create(FileName, fmCreate);
  try
    InstantWriteObject(Stream, Format, Obj);
  finally
    Stream.Free;
  end;
end;

function LoadObject(const FileName: string;
  Format: TInstantStreamFormat): TPersistent;
var
  Stream: TFileStream;
begin
  Stream := TFileStream.Create(FileName, fmOpenRead);
  try
    Result := InstantReadObject(Stream, Format);
  finally
    Stream.Free;
  end;
end;

// Usage
var
  Contact: TContact;
begin
  Contact := TContact.Create;
  try
    Contact.Name := 'John Doe';

    // Save as binary
    SaveObject(Contact, 'contact.bin', sfBinary);

    // Save as XML
    SaveObject(Contact, 'contact.xml', sfXML);

    {$IFDEF DELPHI_NEON}
    // Save as JSON
    SaveObject(Contact, 'contact.json', sfJSON);
    {$ENDIF}
  finally
    Contact.Free;
  end;

  // Load
  Contact := LoadObject('contact.xml', sfXML) as TContact;
  try
    ShowMessage(Contact.Name);
  finally
    Contact.Free;
  end;
end;

Convert Binary to XML

pascal
procedure ConvertBinaryFileToXML(const BinaryFile, XMLFile: string);
var
  BinStream, XMLStream: TStream;
begin
  BinStream := TFileStream.Create(BinaryFile, fmOpenRead);
  try
    XMLStream := TFileStream.Create(XMLFile, fmCreate);
    try
      InstantObjectBinaryToText(BinStream, XMLStream);
    finally
      XMLStream.Free;
    end;
  finally
    BinStream.Free;
  end;
end;

// Usage
ConvertBinaryFileToXML('model.bin', 'model.xml');

Save Multiple Objects

pascal
procedure SaveMultipleObjects(Objects: TObjectList; const FileName: string);
var
  Stream: TFileStream;
  List: TList;
  I: Integer;
begin
  List := TList.Create;
  try
    for I := 0 to Objects.Count - 1 do
      List.Add(Objects[I]);

    Stream := TFileStream.Create(FileName, fmCreate);
    try
      InstantWriteObjects(Stream, sfXML, List);
    finally
      Stream.Free;
    end;
  finally
    List.Free;
  end;
end;

procedure LoadMultipleObjects(const FileName: string; Objects: TObjectList);
var
  Stream: TFileStream;
  List: TList;
  I: Integer;
begin
  List := TList.Create;
  try
    Stream := TFileStream.Create(FileName, fmOpenRead);
    try
      InstantReadObjects(Stream, sfXML, List);
    finally
      Stream.Free;
    end;

    Objects.Clear;
    for I := 0 to List.Count - 1 do
      Objects.Add(List[I]);
  finally
    List.Free;
  end;
end;

Custom Exception with Original

pascal
procedure SafeDatabaseOperation;
begin
  try
    // Database operation that might fail
    Connector.Broker.Execute('INVALID SQL');
  except
    on E: EDatabaseError do
    begin
      // Wrap with InstantObjects exception
      raise EInstantError.CreateFmt(
        'Database operation failed: %s', [E.Message], E);
    end;
  end;
end;

// Catch and analyze
try
  SafeDatabaseOperation;
except
  on E: EInstantError do
  begin
    ShowMessage('Error: ' + E.Message);

    if Assigned(E.OriginalException) and
       (E.OriginalException is EDatabaseError) then
    begin
      ShowMessage('Original DB Error: ' +
        EDatabaseError(E.OriginalException).Message);
    end;
  end;
end;

Best Practices

  1. Exception Handling

    • Always catch specific exception types
    • Wrap external exceptions in EInstantError
    • Preserve original exception for debugging
    • Use resource strings for messages
  2. Streaming

    • Use appropriate format (sfBinary for speed, sfXML for debugging)
    • Always free streams in try-finally
    • Consider FreeSource for nested streams
    • Use process events for progress feedback
  3. Collections

    • Use named access for clarity
    • Prefer TInstantOwnedCollection for ownership
    • Call GetItemNames for UI population
  4. XML Conversion

    • Convert to XML for version control
    • Keep binary for runtime performance
    • Use converters for migration
  5. Custom Streamable Classes

    • Override ReadObject/WriteObject
    • Call inherited first
    • Handle versioning explicitly
    • Test round-trip serialization

See Also

Version History

  • Version 3.0 - Initial infrastructure
  • Version 3.5 - XML support added
  • Version 4.0 - Enhanced exception system
  • Version 4.2 - 64-bit support
  • Version 4.3 - JSON format support (with Neon)

Released under Mozilla License, Version 2.0.