6.8 KiB
Type System
Base Class Hierarchy
Every type Clotho knows about descends from ClothoEntity:
ClothoEntity (abstract)
├── ClothoVertex (abstract)
│ └── Employee, Person, Company, ... (developer-defined @VertexType classes)
└── ClothoEdge (abstract)
└── WorksAt, PlacedBy, ... (developer-defined @EdgeType classes)
@SubgraphType classes do NOT extend ClothoEntity — they are plain Java classes
that aggregate ClothoVertex / ClothoEdge instances.
ClothoEntity
Carries the identity and metadata common to all graph elements:
| Member | Purpose |
|---|---|
ARID getId() |
ArcadeDB record ID; null for unsaved elements |
String getLabel() |
ArcadeDB type name (e.g. "Employee") |
Object getProperty(String key) |
Raw property access; bypass typed fields when needed |
boolean hasLabel(String label) |
Convenience type check |
ClothoVertex
Adds vertex-specific behavior. All @VertexType classes must extend this.
ClothoEdge
Adds edge-specific behavior. Carries outVertexId and inVertexId as ARID values.
All @EdgeType classes must extend this.
ARID — ArcadeDB Record ID
ARID is a typed value object wrapping the ArcadeDB record ID string (e.g. #10:0).
It is deliberately opaque to avoid coupling call sites to ArcadeDB's ID format.
ARID id = ARID.of("#10:0");
String raw = id.asString();
Using ARID rather than String everywhere:
- Makes it impossible to accidentally pass an arbitrary string as a record ID
- Allows the internal representation to evolve (e.g., for future DB portability)
- Null
ARIDreliably indicates "not yet persisted"
Vertex Types
@VertexType("Employee")
public class Employee extends ClothoVertex {
@Property("name") String name;
@Property("dept") String department;
}
The @VertexType label must match the ArcadeDB vertex type name exactly (case-sensitive).
Field names that match the ArcadeDB property name do not need @Property; use it when
names differ or for explicit documentation.
Edge Types
@EdgeType("WORKS_AT")
public class WorksAt extends ClothoEdge {
public static final String LABEL = "WORKS_AT"; // avoids magic strings at call sites
@OutVertex Employee employee;
@InVertex Company company;
@Property("startDate") LocalDate startDate;
@Property("role") String role;
}
Declaring @InVertex is optional. Omitting it means the edge is loaded for its own
properties only — the target vertex is not fetched. See docs/OBJECT_BOUNDARY.md.
Subgraph Types
@SubgraphType
public class EmployeeProfile {
Employee employee; // matches Gremlin as("employee")
Manager manager; // matches Gremlin as("manager")
@Alias("dept")
Department department; // @Alias when field name ≠ Gremlin alias
List<WorksAt> workHistory;
}
- Has no
ARID; does not extendClothoEntity - Assembled by
SubgraphTypeAssemblerfrom a Gremlinselect()result session.save(profile)iterates allClothoEntityfields and saves each; the session identity map ensures each element is persisted exactly once- See
docs/QUERY_MODEL.mdfor how@Querypopulates subgraph types
Inheritance
Standard Single-Parent Inheritance
Mirror the ArcadeDB EXTENDS hierarchy in Java:
@VertexType("Person")
public abstract class Person extends ClothoVertex {
String name;
}
@VertexType("Employee")
public class Employee extends Person {
String employeeId;
}
@VertexType("HourlyEmployee")
public class HourlyEmployee extends Employee {
BigDecimal hourlyRate;
}
Clotho infers: "HourlyEmployee" is a subtype of "Employee" is a subtype of "Person".
Diamond Inheritance
ArcadeDB supports multi-parent inheritance. Java does not allow extending multiple classes. Declare the second (and further) ArcadeDB parents explicitly:
// ArcadeDB schema: ContractEmployee EXTENDS Employee, Contractor
@VertexType(value = "ContractEmployee", additionalParents = {"Contractor"})
public class ContractEmployee extends Employee {
// Java hierarchy: ContractEmployee IS-A Employee
// ArcadeDB hierarchy: ContractEmployee is also subtype of Contractor (via annotation)
}
Clotho uses additionalParents only for type registry resolution — not for Java polymorphism.
If you need ContractEmployee to be usable as a Contractor in Java, use an interface:
public interface ContractorType { /* shared interface */ }
@VertexType("Contractor")
public class Contractor extends ClothoVertex implements ContractorType { ... }
@VertexType(value = "ContractEmployee", additionalParents = {"Contractor"})
public class ContractEmployee extends Employee implements ContractorType { ... }
Divergent Hierarchies
When the ArcadeDB hierarchy cannot be represented via Java extends at all, declare the
parent explicitly:
@VertexType(value = "ExternalEmployee", parentLabel = "Employee")
public class ExternalEmployee extends ClothoVertex {
// Does not extend Employee in Java, but is a subtype in ArcadeDB
}
Result Mapping Rule
Clotho always instantiates the most specific registered class matching the vertex/edge label.
The declared return type is an upper bound — the actual runtime instances are the narrowest match in the TypeRegistry.
// The query may return HourlyEmployee and SalariedEmployee vertices
List<Employee> staff = repo.findAllEmployees();
// → List contains HourlyEmployee and SalariedEmployee instances
// (both assignable to Employee; caller may instanceof-check if needed)
List<ClothoVertex> anything = repo.findMixed();
// → List contains whatever registered types the traversal returned
Unknown Types
When a vertex/edge label has no registered Java class, behavior depends on the configured
UnknownTypeBehavior:
| Mode | Behavior |
|---|---|
STRICT (default) |
Throw UnknownTypeException |
NEAREST_ANCESTOR |
Instantiate closest registered ancestor; subtype-specific fields are null |
GENERIC |
Wrap in ClothoVertex/ClothoEdge with raw getProperty() access |
Configure globally:
clotho.unknown-type-behavior=STRICT
Or per session factory:
ClothoSessionFactory.builder()
.unknownTypeBehavior(UnknownTypeBehavior.NEAREST_ANCESTOR)
...
TypeRegistry
The TypeRegistry is built once at ClothoSessionFactory creation time.
It scans the declared packages for @VertexType and @EdgeType classes and builds:
label → Class<? extends ClothoEntity>direct lookup- Inheritance tree (for
NEAREST_ANCESTORresolution and polymorphic query hints) - Validation: duplicate labels, missing
extends ClothoVertex/ClothoEdge, etc.
Startup failure is preferred over silent misconfiguration at runtime.