Skip to content

Polymorphism and Inheritance

← Feature Serialization | Next: Load/Save Options →


See also:


1. Reference Type vs Instance Type

When serializing references, the serializer decides which type information to write based on the actual instance type and the serializeInstanceType setting.

1.1 Configuration

Annotation KeyProperty KeyGlobalERefDefaultDescription
serializeInstanceTypecodec.serializeInstanceTypetrueWrite instance type (true) or reference type (false)

1.2 Default Behavior (serializeInstanceType=true)

Core Rule: The serializer uses the concrete instance type (from eObject.eClass()), not the declared reference type.

Smart Compression Interaction:

Smart CompressionInstance Type == Reference TypeAction
ONYesOmit _type (can be inferred)
ONNoWrite instance type
OFFYesWrite instance type
OFFNoWrite instance type

Examples:

java
// Reference typed as Person, contains FancyPerson instance
EReference employeeRef;  // type = Person
EObject instance;        // eClass = FancyPerson

Smart Compression ON, instance type differs from reference type:

json
{
  "employee": {
    "_type": "http://example.org/person/1.0#//FancyPerson",
    "_ref": "john-doe"
  }
}

Smart Compression ON, instance type equals reference type:

json
{
  "employee": {
    "_ref": "john-doe"
  }
}

(Type omitted because it can be inferred from the reference declaration)

Smart Compression OFF (always writes instance type):

json
{
  "employee": {
    "_type": "http://example.org/person/1.0#//FancyPerson",
    "_ref": "john-doe"
  }
}

1.3 Writing Reference Type (serializeInstanceType=false)

When serializeInstanceType=false, the serializer writes the declared reference type instead of the instance type:

EAnnotation (on EReference):

xml
<eStructuralFeatures xsi:type="ecore:EReference" name="employee" eType="#//Person">
  <eAnnotations source="http://eclipse.org/fennec/codec">
    <details key="serializeInstanceType" value="false"/>
  </eAnnotations>
</eStructuralFeatures>

Java Builder:

java
ReferenceConfigBuilder.forReference(PersonPackage.Literals.COMPANY__EMPLOYEE)
    .serializeInstanceType(false)  // Write declared type, not instance type
    .build();

Property Map:

java
Map<String, Object> options = Map.of(
    "codec.serializeInstanceType", false
);

Result (reference typed as Person, instance is FancyPerson):

json
{
  "employee": {
    "_type": "http://example.org/person/1.0#//Person",
    "_ref": "john-doe"
  }
}

⚠️ Warning: This is a serialization-only option. Using serializeInstanceType=false may cause deserialization failures if:

  • The reference type is an interface (cannot instantiate)
  • The reference type is abstract (cannot instantiate)
  • Instance-specific features from subclass are lost

Use only when the consuming system specifically requires the declared type.


2. Annotation Inheritance Levels

Controls how codec annotations are inherited across the EClass hierarchy.

2.1 Configuration

Annotation KeyProperty KeyGlobalEClassDefaultDescription
inheritcodec.inheritDIRECTAnnotation inheritance level

Inheritance Level Values:

LevelDescriptionInherits From
DIRECT (default)Only direct parentImmediate superclass/interface
ALLFull hierarchyAll ancestors up to EObject
NONENo inheritanceOnly concrete class annotations

Rationale for DIRECT as default:

  • Avoids accidentally inheriting annotations from external library base classes
  • Predictable behavior - only looks one level up
  • Matches OSGi DS component annotation inheritance semantics

2.2 EAnnotation (on EClass)

xml
<!-- Force inheritance from parent even if parent is from different EPackage -->
<eClassifiers xsi:type="ecore:EClass" name="Employee" eSuperTypes="#//Person">
  <eAnnotations source="http://eclipse.org/fennec/codec">
    <details key="inherit" value="ALL"/>
  </eAnnotations>
</eClassifiers>

2.3 Java Builder (Runtime Override)

java
// Global setting
CodecConfiguration config = CodecConfiguration.builder()
    .inherit(AnnotationInheritance.DIRECT)  // Default
    .build();

// Per-class override
ClassConfigBuilder.forEClass(EmployeePackage.Literals.EMPLOYEE)
    .inherit(AnnotationInheritance.ALL)
    .build();

Property Map:

java
Map<String, Object> options = Map.of(
    "codec.inherit", "DIRECT"
);

2.4 Example Hierarchy

EObject (EMF base)
  └── Entity (library class, has idStrategy annotation)
        └── Person (your model, has typeStrategy annotation)
              └── Employee (your model, no annotations)
Inheritance LevelEmployee sees annotations from
NONEEmployee only (none)
DIRECTEmployee + Person (typeStrategy)
ALLEmployee + Person + Entity (typeStrategy, idStrategy)

3. Inheritance Resolution Order

When the same annotation exists at multiple levels, the most specific (closest to concrete class) wins:

  1. Concrete class annotations (highest priority)
  2. Direct parent annotations
  3. Grandparent annotations (only if inherit=ALL)
  4. Global codec defaults (lowest priority)

3.1 inherit=ALL Across Package Boundaries

inherit=ALL is the only setting that walks out of the concrete class's own package, and that has a consequence worth stating: the inherited configuration comes from the base package version that the instance chain actually points at — the concrete EClass instances reachable through eSuperTypes — not from whichever version of that base nsURI happens to be resolved elsewhere in the load.

This matters when several versions of a base model are registered at once. The same concrete class, built against two different versions of its base package, has two different effective configurations, and each is correct for its own instance chain. Configuration follows instance identity, exactly as 02 §8 resolves it.

The declared eReferenceType of a reference is therefore only an upper bound on what may arrive there: a subtype from another package version satisfies it. Version-correct resolution at read time is what makes that safe — see 10 §1.2.1.


4. Default Polymorphism Settings

SettingProperty KeyDefault Value
Serialize Instance Typecodec.serializeInstanceTypetrue
Annotation Inheritancecodec.inheritDIRECT

Next: Load/Save Options →

Released under the EPL-2.0 License. Eclipse Fennec is part of the Eclipse Foundation.