Skip to content

InstantJSON

Unit: InstantJSONCategory: Brokers

Overview

The InstantJSON unit provides a file-based broker that stores objects as JSON files. Each object is saved as a separate JSON file in a folder structure organized by class name. This broker is ideal for prototyping, small datasets, configuration storage, and REST service integration.

Key Classes:

  • TJSONFilesAccessor - Connection component for JSON file access
  • TInstantJSONConnector - Connector for JSON broker
  • TInstantJSONBroker - Broker implementing JSON persistence
  • TInstantJSONConnectionDef - Connection definition for Connection Manager

TJSONFilesAccessor

Connection component that manages access to JSON files on the file system.

Inheritance: TCustomConnectionTJSONFilesAccessor

Key Properties

PropertyTypeDescription
RootFolderstringBase directory for JSON file storage
JSONFileFormatTJSONFileFormatxffUtf8 (default) or xffIso encoding
ConnectedBooleanConnection status

Events

EventTypeDescription
OnCustomLoadJSONFileTJSONFileOpenEventCustom JSON file loading
OnCustomSaveToJSONFileTJSONFileSaveEventCustom JSON file saving

Example Usage

pascal
var
  Accessor: TJSONFilesAccessor;
begin
  Accessor := TJSONFilesAccessor.Create(Self);
  Accessor.RootFolder := 'C:\MyApp\Data';
  Accessor.JSONFileFormat := xffUtf8;
  Accessor.Connected := True;
end;

File Organization

The accessor creates this folder structure:

RootFolder/
├── TContact/
│   ├── CONT001.json
│   ├── CONT002.json
│   └── CONT003.json
├── TCompany/
│   └── COMP001.json
└── TCategory/
    ├── CAT001.json
    └── CAT002.json

TInstantJSONConnector

Connector component integrating the JSON broker with InstantObjects.

Inheritance: TInstantConnectionBasedConnectorTInstantJSONConnector

Key Properties

PropertyTypeDescription
ConnectionTJSONFilesAccessorJSON files accessor
IsDefaultBooleanSet as default connector
BrokerClassTInstantBrokerClassReturns TInstantJSONBroker

Example Usage

pascal
var
  Connector: TInstantJSONConnector;
begin
  Connector := TInstantJSONConnector.Create(Self);
  Connector.Connection := JSONFilesAccessor;
  Connector.IsDefault := True;

  // Now all objects use JSON storage by default
  var Contact := TContact.Create;
  try
    Contact.Name := 'John Doe';
    Contact.Store;  // Saved to JSON file
  finally
    Contact.Free;
  end;
end;

TInstantJSONBroker

Broker implementing JSON file-based persistence.

Inheritance: TInstantNavigationalBrokerTInstantJSONBroker

Key Methods

pascal
// Implemented from base broker
procedure DisposeObject(AObject: TInstantObject; ConflictAction: TInstantConflictAction = caFail);
procedure RetrieveObject(AObject: TInstantObject; const AObjectId: string; ARefresh: Boolean = False);
procedure StoreObject(AObject: TInstantObject; ConflictAction: TInstantConflictAction = caFail);

JSON File Format

Each JSON file contains:

json
{
  "ClassName": "TContact",
  "Id": "CONT001",
  "_UpdateCount": 1,
  "_Name": "John Doe",
  "_Email": "john@example.com",
  "_Category": {
    "ReferenceObject": "TCategory#CAT001"
  },
  "_Phones": [
    {
      "_Number": "+1234567890",
      "_PhoneType": 0
    }
  ]
}

TJSONFileFormat

File encoding format enumeration.

pascal
type
  TJSONFileFormat = (
    xffUtf8,  // UTF-8 encoding (default, recommended)
    xffIso    // ISO-8859-1 encoding (legacy)
  );

Usage Patterns

Quick Start - Prototyping

pascal
// Design-time setup
procedure TMainForm.FormCreate(Sender: TObject);
begin
  // Drop components on form
  JSONFilesAccessor1.RootFolder := 'Data';
  JSONFilesAccessor1.Connected := True;

  JSONConnector1.Connection := JSONFilesAccessor1;
  JSONConnector1.IsDefault := True;

  // No database setup needed!
end;

// Create and store objects
var
  Contact: TContact;
begin
  Contact := TContact.Create;
  try
    Contact.Id := InstantGenerateId;
    Contact.Name := 'Jane Smith';
    Contact.Email := 'jane@example.com';
    Contact.Store;  // Saved to Data\TContact\[ID].json
  finally
    Contact.Free;
  end;
end;

Configuration Storage

pascal
// Application settings as persistent object
type
  TAppConfig = class(TInstantObject)
    {IOMETADATA stored 'CONFIG';
      Theme: String(20);
      Language: String(5);
      AutoSave: Boolean;}
    _Theme: TInstantString;
    _Language: TInstantString;
    _AutoSave: TInstantBoolean;
  published
    property Theme: string read GetTheme write SetTheme;
    property Language: string read GetLanguage write SetLanguage;
    property AutoSave: Boolean read GetAutoSave write SetAutoSave;
  end;

// Load or create config
var
  Config: TAppConfig;
begin
  Config := TAppConfig.Retrieve('DEFAULT', True);  // Create if missing
  try
    ApplyTheme(Config.Theme);
    SetLanguage(Config.Language);
  finally
    Config.Free;
  end;
end;

Data Export/Import

pascal
// Export data to JSON
procedure ExportToJSON(const ABackupFolder: string);
var
  Contacts: TObjectList;
begin
  // Configure JSON accessor
  JSONAccessor.RootFolder := ABackupFolder;
  JSONConnector.IsDefault := True;

  // Retrieve and store (exports to JSON)
  Contacts := TObjectList.Create(False);
  try
    TContact.RetrieveAll(Contacts);
    // Objects are already in JSON format
  finally
    Contacts.Free;
  end;
end;

// Import from JSON
procedure ImportFromJSON(const ASourceFolder: string);
begin
  // Just copy JSON files to active RootFolder
  CopyDirectory(ASourceFolder, JSONAccessor.RootFolder);
end;

Migration Between Brokers

pascal
// Migrate from JSON to SQL using InstantPump
var
  Pump: TInstantPump;
begin
  Pump := TInstantPump.Create(nil);
  try
    Pump.SourceConnector := JSONConnector;
    Pump.DestinationConnector := FireDACConnector;
    Pump.Execute;
  finally
    Pump.Free;
  end;
end;

Best Practices

  1. Use UTF-8 encoding - Better international character support
  2. Limit object count - Not suitable for thousands of objects per class
  3. Backup regularly - JSON files are plain text, easy to backup
  4. Use relative paths - Makes app portable
  5. Version control friendly - JSON format works well with Git
  6. Monitor file count - Performance degrades with many files
  7. Test concurrency - Update count prevents lost updates but doesn't lock files

Features and Limitations

Features

✅ No database setup required ✅ Human-readable format ✅ Easy debugging and inspection ✅ Version control friendly ✅ Cross-platform compatible ✅ Perfect for prototyping ✅ Optimistic locking via update count

Limitations

❌ No complex SQL queries ❌ No JOINs or aggregations ❌ Poor performance with large datasets ❌ No server-side indexing ❌ No transactions across multiple objects ❌ File system permissions required

Performance Considerations

  • Best for: < 1,000 objects total
  • Acceptable for: 1,000 - 10,000 objects
  • Not recommended for: > 10,000 objects

Optimization tips:

  • Keep classes in separate folders
  • Use SSDs for better I/O
  • Consider JSON broker for read-heavy scenarios
  • Migrate to SQL broker when scaling up

Troubleshooting

Problem: "Access denied" when saving

  • Solution: Check write permissions on RootFolder

Problem: Files not appearing

  • Solution: Verify RootFolder path exists and is correct

Problem: Corrupt JSON file

  • Solution: JSON files are text - open and manually fix if needed

Problem: Poor performance

  • Solution: Too many objects - migrate to FireDAC or other SQL broker

Problem: Lost updates in multi-user scenario

  • Solution: JSON broker uses file-level locking, implement application-level coordination

See Also

Released under Mozilla License, Version 2.0.