Serialization Architecture
1. Component Overview
┌─────────────────────────────────────────────────────────────────┐
│ CodecResource │
│ (EMF Resource implementation) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ ConfigurationMerger │ │ EffectiveCodecConfig │ │
│ │ (merges all levels) │──▶│ (immutable snapshot) │ │
│ └──────────────────┘ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Jackson Integration │ │
│ │ ┌────────────────┐ ┌────────────────┐ │ │
│ │ │ CodecJsonFactory │ │ CodecJsonParser │ │ │
│ │ └────────────────┘ └────────────────┘ │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ CodecJsonReadContext / CodecJsonWriteContext │ │ │
│ │ │ (carries EMF state during parsing/generation) │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘2. Configuration Merging
The ConfigurationMerger combines all configuration levels into a single EffectiveCodecConfig:
Load/Save Options (highest priority)
↓
ResourceFactory Defaults
↓
Codec Module Config
↓
Configuration Properties
↓
EAnnotations (MetadataService)
↓
Built-in Defaults (lowest priority)
↓
═══════════════════════════
│ EffectiveCodecConfig │
│ (per-step, instance-keyed)│
═══════════════════════════See also: Configuration Resolution for the complete two-dimensional configuration model (Source Hierarchy × Scope Chain).
Per-step, not process-global.
EffectiveCodecConfigis a per-load/per-operation derived view, immutable per selected package version, with per-class/per-feature config cached by EClass / EStructuralFeature instance — not a single process-wide snapshot (see 02 §8). Naming caveat: in code the resolved value objects areClassConfig/FeatureConfigand access isresolveClassConfig(EClass)/resolveFeatureConfig(EStructuralFeature); theEffectiveClassConfig/getClassConfignames used in the diagrams below are illustrative aliases pending a spec-wide naming cleanup.
3. Context Hierarchy
During serialization/deserialization, context objects carry EMF state:
EMFContextHolder (internal holder)
│
├── EffectiveCodecConfig (single source of truth)
│ ├── getClassConfig(EClass) → EffectiveClassConfig
│ └── getFeatureConfig(EStructuralFeature) → EffectiveFeatureConfig
│
├── Current EObject
├── Current EStructuralFeature
├── Current Type Hint (for deserialization)
└── EMF Resource4. Serialization Flow
CodecResource.doSave()createsEffectiveCodecConfigviaConfigurationMergerCodecJsonFactorycreates generator withCodecJsonWriteContextCodecEObjectSerializerwrites metadata fields, then iterates features:- Metadata field ordering: The
idOnTopproperty (from effective ID config) determines whether_idor_typeis written first:idOnTop=true:_id→_type→_supertype→ featuresidOnTop=false(default):_type→_supertype→_id→ features
- Get
EffectiveFeatureConfigfor each feature - Delegate to
SerializationEntry(Attribute, Reference, etc.)
- Metadata field ordering: The
- Each entry uses pre-merged config (no fallback logic needed)
See also: Type (§5.0.2), ID (§8.7, §10 step 6), Reference, Feature for serialization details per target.
5. Deserialization Flow
CodecResource.doLoad()createsEffectiveCodecConfigviaConfigurationMergerCodecJsonFactorycreates parser withCodecJsonReadContextCodecEObjectDeserializer:- Resolve type (from content or hint)
- Create EObject
- Iterate JSON fields, match to
DeserializationEntry
- Post-processing: resolve references
See also: Load/Save Options for root type hints and feature type hints during deserialization.
5.1 Deferred Properties (Order-Independent Parsing)
JSON field order is irrelevant for deserialization. Metadata fields (_type, _id, etc.) can appear anywhere in the object - before, after, or between data fields.
When data fields appear before metadata fields, they are deferred and processed after metadata resolution:
{
"name": "John",
"age": 30,
"_type": "http://example.org/1.0#//Person",
"_id": "john-123"
}Processing:
nameandageencountered before_type→ stored in deferred buffer_typeencountered → EClass resolved, EObject created_idencountered → ID set on EObject- Deferred properties replayed →
nameandageset on EObject
Supported deferred value types:
- Primitives: String, Number, Boolean, null
- Nested objects: Stored as
Map<String, Object>, replayed as JSON objects - Arrays: Stored as
List<Object>, replayed as JSON arrays - Deep nesting: Fully supported
Why this matters:
- JSON spec does not guarantee object key order
- Different serializers/APIs may emit fields in different orders
- Allows natural JSON authoring without worrying about metadata position
- ID-based references within the same document work regardless of order
6. Key Classes
| Class | Purpose |
|---|---|
CodecResource | EMF Resource implementation |
ConfigurationMerger | Merges configuration levels |
EffectiveCodecConfig | Immutable merged config |
EffectiveClassConfig | Per-EClass effective config |
EffectiveFeatureConfig | Per-feature effective config |
CodecJsonFactory | Creates parser/generator |
CodecJsonReadContext | Read-side EMF context |
CodecJsonWriteContext | Write-side EMF context |
EMFContextHolder | Internal state holder |
SerializationEntry | Per-feature serializer |
DeserializationEntry | Per-feature deserializer |
See also: Annotation Reference for all EAnnotation keys and their corresponding Java configuration.
