Configurable import pipeline for Unity
This document describes what happens inside the import pipeline and which supported extension points participate in each stage.
The public execution path goes through ImportJobRunner.RunAsync(...). ImportJobCorePipeline is an internal layer that builds preview and applies already prepared source inside one runner session.
Practical code templates are in Custom Import Extensions. Safe apply, backup/restore, and incremental state are described in Backup / Restore / Incremental State.
ImportSourceConfig
-> ImportJobDefinition
-> ImportJobRunner.RunAsync(...)
-> Source Provider
-> Parser
-> Parser Diagnostics
-> TargetAdapter.GetTargetEntries
-> Metadata Descriptor
-> Identity Strategy
-> Reference Lookup
-> Validation
-> Diff
-> Fingerprint
-> Preview / Validate / Apply decision
-> Apply Strategy
-> Incremental Skip Check
-> Backup Capture
-> TargetAdapter.SetTargetEntries
-> Final Fingerprint
-> Last Applied State
Preview, Validate, and Apply start with the same preview path. The difference appears after preview: Preview returns the result immediately, Validate checks validation policy, and Apply runs incremental skip check, backup, and only then applies prepared source.
| Stage | What it does | Extension point | Important details |
|---|---|---|---|
| Source Provider | Reads raw source data and returns ImportSourceData. |
IImportSourceProvider |
Provider does not parse entries and does not change the target. Unity text assets usually use TextAssetImportSourceProvider. |
| Parser | Turns sourceData.RawContent into a list of source entries. |
IImportParser, IImportParser<TEntry> |
parser.EntryType matches profile.EntryType. Result is stored as prepared source inside the pipeline session. |
| Parser Diagnostics | Reads diagnostics from the parser after parse. | IImportParserDiagnosticsProvider |
These diagnostics are added to the shared ValidationMessages list, so parser can show warnings/errors next to validation. |
| Target Entries | Reads current entries from the target asset. | IImportTargetAdapter.GetTargetEntries |
These entries are used for validation context, diff, target fingerprint, and backup. |
| Metadata Descriptor | Builds a normalized description of entry type. | Attributes and field policies | ImportTypeDescriptor is used by validation, diff, fingerprint, and apply. Usually users affect it through attributes, not custom code. |
| Identity Strategy | Defines stable identity/key for entries. | IIdentityStrategy |
Identity is used for reference checks, diff, fingerprint, and apply strategy. |
| Reference Lookup | Collects external reference entries before validation. | IImportReferenceLookupProvider |
If entry type contains reference members to other entry types, lookup provider injects entries/descriptors/identity strategies into validation context. |
| Validation | Checks prepared source with target entries and reference lookup. | IImportValidator |
Parser diagnostics and validation diagnostics are combined in ImportPreview.ValidationMessages. |
| Diff | Compares source entries and target entries. | IImportDiffEngine, IImportDiffEngineWithResult |
If diff engine throws an exception, pipeline isolates the error as a warning diagnostic and continues preview without changes. |
| Fingerprint | Builds canonical fingerprints for prepared source and current target. | IImportFingerprintBuilder |
Fingerprint is computed by ImportJobRunner, not ImportJobCorePipeline. It uses prepared source from pipeline and target entries from adapter. |
Apply does not parse source again. It works only with prepared source created on the preview stage in the same ImportJobRunner session.
Preview already built
-> validation errors policy check
-> apply strategy resolution
-> incremental skip check
-> if unchanged: return Skipped
-> otherwise continue
-> optional backup capture
-> ImportJobCorePipeline.ApplyPreparedSource(...)
-> TargetAdapter.GetTargetEntries
-> Metadata Descriptor
-> Identity Strategy
-> Apply Strategy.BuildFinalEntries
-> TargetAdapter.SetTargetEntries
-> final source/target fingerprints
-> config.MarkLastAppliedState(...)
| Stage | What it does | Extension point | Important details |
|---|---|---|---|
| Validation policy check | Blocks apply when validation errors exist and fail policy is enabled. | ImportExecutionProfile.failOnValidationErrors, ImportJobDefinition.FailOnValidationErrors |
When blocked, returns ApplyBlocked; target does not change. |
| Apply Strategy Resolution | Selects strategy from override or default profile strategy. | IImportApplyStrategy, IImportProfile.GetDefaultApplyStrategy() |
If strategy is not found, job finishes as Failed. |
| Incremental Skip Check | Compares current source/target fingerprints and selected apply strategy against lastApplied* state. |
IImportFingerprintBuilder, ImportExecutionProfile.enableIncrementalSkip, ImportJobDefinition.EnableIncrementalSkip |
If unchanged, returns Skipped; backup and target write do not run. |
| Backup Capture | Saves current target entries before apply when enabled. | IImportBackupCodec, ImportBackupHistory |
Backup reads entries through TargetAdapter.GetTargetEntries, not through parser. |
| Prepared Source Read | Takes entries saved after parser. | No public extension point | If prepared source is missing, apply returns MissingPreparedSource. |
| Current Target Read | Reads target entries before final entries are built. | IImportTargetAdapter.GetTargetEntries |
Apply strategy receives both source entries and current target entries. |
| Build Final Entries | Builds the final entries list. | IImportApplyStrategy.BuildFinalEntries |
Replace/merge/update behavior is decided here. Writing to the Unity asset happens at the Target Write stage. |
| Target Write | Writes final entries into the target asset. | IImportTargetAdapter.SetTargetEntries |
This is the actual target asset mutation point. |
| Final Fingerprint | Computes fingerprints after apply. | IImportFingerprintBuilder |
If fingerprints are computed, config updates lastApplied* state. If not, state is cleared. |
Parser can implement IImportParserDiagnosticsProvider. After ParseEntries(...), pipeline calls GetDiagnostics() and adds those messages to ImportPreview.ValidationMessages.
This means:
Before validators run, pipeline builds reference dictionaries:
profile.EntryType;profile.EntryType;profile.EntryType;IImportReferenceLookupProvider.Validators receive a ready ImportValidationContext, where references can be checked not only inside the current source but also against data from other import targets.
Minimal shape of a project-specific lookup provider:
#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using JsonDataImporter.Runtime.Core;
using JsonDataImporter.Runtime.Core.Identity;
using JsonDataImporter.Runtime.Core.Validation;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
[InitializeOnLoad]
public static class ProjectImportReferenceBootstrap
{
static ProjectImportReferenceBootstrap()
{
ImportReferenceLookupProviderRegistry.Provider =
new ProjectImportReferenceLookupProvider();
}
}
public sealed class ProjectImportReferenceLookupProvider : IImportReferenceLookupProvider
{
public bool TryResolve(
Type entryType,
IImportProfile activeProfile,
Object activeTargetAsset,
out ImportReferenceLookupResult result)
{
result = null;
if (entryType != typeof(ItemRecord))
return false;
ItemDatabase database = LoadItemDatabase(activeTargetAsset);
if (database == null)
return false;
result = new ImportReferenceLookupResult
{
TargetTypeId = "items_database",
EntryType = typeof(ItemRecord),
Entries = ToObjects(database.items),
IdentityStrategy = new DefaultIdentityStrategy()
};
return true;
}
private static ItemDatabase LoadItemDatabase(Object activeTargetAsset)
{
string[] guids = AssetDatabase.FindAssets("t:ItemDatabase");
for (int i = 0; i < guids.Length; i++)
{
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
var database = AssetDatabase.LoadAssetAtPath<ItemDatabase>(path);
if (database != null && !ReferenceEquals(database, activeTargetAsset))
return database;
}
return null;
}
private static IReadOnlyList<object> ToObjects(IReadOnlyList<ItemRecord> items)
{
var result = new List<object>();
if (items == null)
return result;
for (int i = 0; i < items.Count; i++)
result.Add(items[i]);
return result;
}
}
#endif
This provider is responsible only for supplying reference entries. The actual [ImportReference] check is performed by the built-in default_reference validator.
If a diff engine fails, ImportJobCorePipeline catches the exception and returns an ImportDiffDiagnostic with Warning severity.
Result:
Parser, source provider, target adapter, and apply strategy are not isolated this way. Their errors can finish the job with Failed.
Prepared source means source entries produced by the parser during preview. Apply takes exactly those entries through internal pipeline state.
Apply does not reread the source provider and does not run parser again. Parsing behavior is defined by the preview stage, and apply strategy receives already prepared source entries.
TargetAdapter.SetTargetEntries receives only final entries; source provider, parser, and reference lookup are no longer involved at that point.| Task | Extension point | Where it is selected |
|---|---|---|
| Read data from a custom source | IImportSourceProvider |
Source provider settings in ImportSourceConfig. |
| Parse a custom source shape | IImportParser |
selectedParserId or auto parser resolution. |
| Show parser warnings/errors | IImportParserDiagnosticsProvider |
Automatically, when parser implements the interface. |
| Describe a new target shape | IImportProfile + IImportTargetAdapter |
Profile resolution by target asset and preferredTargetTypeId. |
| Change target read/write behavior | IImportTargetAdapter |
Through the selected profile. |
| Change entry comparison keys | IIdentityStrategy |
Identity strategy resolution for profile/entry type. |
| Check data before apply | IImportValidator |
selectedValidatorIds. |
| Attach external reference data | IImportReferenceLookupProvider |
Global provider registry, used before validation. |
| Change how changes are displayed | IImportDiffEngine or IImportDiffEngineWithResult |
selectedDiffEngineId. |
| Change incremental fingerprints | IImportFingerprintBuilder |
selectedFingerprintBuilderId, execution profile fingerprint settings. |
| Change replace/merge behavior | IImportApplyStrategy |
selectedApplyStrategyId, job override, or default profile strategy. |
| Change backup payload | IImportBackupCodec |
Through the selected profile. |
This table shows where each task plugs into the pipeline; implementation templates live in the linked custom sections.