Complex types and fields
A complex type groups fields and may also contain operations and appendices. The CMN grammar distinguishes contained values, references, reusable field definitions, field sets, relations, and includes.
1. Type declaration
[description] [abstract] type [<stereotypes>] Name ["Label"]
[(specialization of | extends) BaseType]
[implements ImplementedType]
[property ...] {
fields
operations
appendices
}Example:
package com.example.customer
import org.joinedworkz.facilities.common.base
platform Base
abstract type Identified {
id**: Id
}
type Named {
name*: Name
}
type Customer "Customer" extends Identified implements Named {
}specialization of and extends are alternative spellings in this grammar position. implements references one complex type, and the transformation materializes the implemented type's features in the resulting type. A cartridge decides how the remaining relationship maps to a target language.
Documentation can precede the type and any individual field. See Documentation, descriptions and examples for authoring syntax, including a request example with a nested complex type, and the Base OpenAPI mapping for schema descriptions and generated media examples.
2. Containment and references
package com.example.customer
import org.joinedworkz.facilities.common.base
platform Base
type Address {
city*: String
}
type Employee {
id**: Id
name*: Name
}
type Customer {
id**: Id
address: Address
manager -> Employee
accountManager <> Employee
}address: Addressis a containment field.manager -> Employeeis a reference.accountManager <> Employeeis the grammar's one-to-one reference form.id**: Idmarks a key field.**identifies the field; it is not another spelling of mandatory*.
A referenced complex type must have a key field. This is an active CMN validation rule. The exact persistence, serialization, and target-language representation of containment and references is facility-specific. The key marker itself does not select how a missing value is created. For a persistent SpringBoot entity, see the facility-specific ID generation strategy.
3. Cardinalities
The cardinality suffix follows a field, parameter, operation result, or other typed occurrence:
| Syntax | Core Model bounds | Meaning |
|---|---|---|
| no suffix | not explicitly set | no explicit cardinality; normally treated as an optional single value |
* | 1..1 | exactly one |
[] | 0..* | zero or more |
[n] | 0..n | at most n; it does not mean exactly n |
[min..max] | min..max | explicit finite bounds |
[min..*] | min..* | lower bound with no upper bound |
[KeyType] | 0..*; dictionary key type = KeyType | values addressed by keys of KeyType |
package com.example.cardinality
import org.joinedworkz.facilities.common.base
platform Base
type CardinalityExample {
optionalName: Name
requiredName*: Name
aliases: Name[]
recentAliases: Name[3]
contacts: Name[1..5]
labels: Name[1..*]
translations: String[String]
}In translations: String[String], the type before the brackets is the value type and the type inside the brackets is the key type. In general, ValueType[KeyType] therefore models values addressed by keys; it is not a position-indexed collection. The Core Model retains both types and an unbounded 0..* cardinality.
The dictionary notation is part of CMN and can occur wherever that grammar position accepts the general cardinality suffix, including operation parameters and results, resource representations, and additional resource method results. Support in generated target artifacts remains a facility capability. See Services and operations, Resources and resource methods, and the selected facility documentation before relying on a target-language or wire mapping.
4. Standalone fields and field sets
A field can be declared once at model level and included by name. A fieldset groups reusable fields:
package com.example.reuse
import org.joinedworkz.facilities.common.base
platform Base
field state: String
fieldset AuditFields {
createdAt*: Timestamp
changedAt: Timestamp
}
type Customer {
state
AuditFields.createdAt
lastChange ..AuditFields.changedAt
}stateincludes the standalone field without renaming it.AuditFields.createdAtincludes one field from a field set.lastChange ..AuditFields.changedAtincludes and renames a field.
An include may also override cardinality, mark the included field as a key, use as to replace its type, add a label, or add properties. Linking and semantic validation occur in model context, not in the Markdown snippet parser.
5. Wildcard includes
...Container or Container.* includes all fields from a complex type, field set, or relation:
package com.example.views
import org.joinedworkz.facilities.common.base
platform Base
type Person {
firstName*: Name
lastName*: Name
}
type Customer {
id**: Id
internalNote: Text
}
type CustomerView {
...Person
...Customer exclude internalNote
}exclude accepts a comma-separated list. The grammar also has map clauses for field renaming, dereferencing, cardinality, key, and type adjustments. Use those advanced transformations only when the active facility documents support for the intended generated effect.
6. Relations
A relation names two complex-type roles and may be directional (->) or bidirectional (<->). It can contain additional fields and operations:
package com.example.relations
import org.joinedworkz.facilities.common.base
platform Base
type Customer {
id**: Id
}
relation Partnership
partner ..Customer <-> otherPartner ..Customer {
since: Date
}Relations and relation-field includes are public CMN model elements. Their storage and generated API shape depend on the chosen facility. The stable Java example exercises them.
7. Operations and appendices
Operations inside a complex type use the same syntax as service operations:
package com.example.operations
import org.joinedworkz.facilities.common.base
platform Base
type Customer {
id**: Id
firstName*: Name
lastName*: Name
displayName(): Name
++ index()
firstName & lastName
}An appendix starts with ++ or °°. The reliably transformed public form applies a profile constraint such as Base's index() to one or more field selections. Constraint selections may combine fields with &.
The grammar also accepts a property name, assignment, or flag in this position, but those forms are not transferred as a general appendix contract. Do not rely on them for generated behavior. The active validator also rejects multi-field combinations for a property-name appendix.
8. Entities and DTOs
entity is a stereotype supplied by Base, not a CMN grammar keyword:
package com.example.persistence
import org.joinedworkz.facilities.common.base
platform Base
type<entity> Customer {
id**: Id
name*: Name
}Likewise, “DTO” describes a role or generated artifact; it is not a separate core declaration keyword. See Entities and DTOs for the conceptual distinction and the selected facility's documentation for concrete output.
9. Facility and generator semantics
The declaration, field, include, relation, cardinality, operation, and appendix forms are CMN grammar syntax. Base supplies the types and entity stereotype used in these examples. The stable Java example exercises standalone fields, field sets, includes, relations, inheritance, and appendices; the focused SpringBoot walkthrough is available at Build a CRUD backend.
