UML DSL Reference
kUML supports all 13 UML 2.x diagram types defined by OMG. Every type uses the same
authoring pattern: a top-level diagram builder, optionally wrapped in a umlModel { … }
container.
Diagram types at a glance
| Type | Builder | Use it for |
|---|---|---|
Class |
|
Static structure: classes, interfaces, enums, generalisation, association. |
Object |
|
Concrete snapshots: instances and links between them at a point in time. |
Package |
|
Logical grouping: packages, nested packages, package dependencies. |
Component |
|
Software architecture: components, ports, provided/required interfaces. |
Deployment |
|
Physical mapping: nodes, artifacts, deployment relationships. |
Use case |
|
Actor goals: actors, use cases, include/extend relationships. |
Sequence |
|
Time-ordered interaction: lifelines, messages, fragments. |
Communication |
|
Spatially-ordered interaction: lifelines connected by numbered messages. |
State machine |
|
Discrete behaviour: states, transitions, triggers, guards, effects. |
Activity |
|
Workflow: actions, control flow, decisions, parallel splits. |
Profile |
|
Stereotype definitions: extensions of the UML metamodel. |
Timing |
|
State-over-time: lifelines with state changes along a timeline. |
Interaction overview |
|
Control flow over interactions: combines activity + sequence semantics. |
Composite structure |
|
Internal structure: parts, ports, connectors within a classifier. |
Class diagrams
The most common starting point. All classifier-level constructs go inside classDiagram { … }.
classDiagram(name = "Domain") {
// Enumerations
val status = enumOf(name = "OrderStatus") {
literal(name = "DRAFT")
literal(name = "CONFIRMED")
}
// Interfaces
val payable = interfaceOf(name = "Payable") {
operation(name = "amountDue") { returnType = "BigDecimal" }
}
// Classes
val order = classOf(name = "Order") {
// Attributes
attribute(name = "id", type = "UUID") { visibility = Visibility.Private }
attribute(name = "status", type = status) // enum val as type
attribute(name = "total", type = "BigDecimal")
// Operations
operation(name = "confirm")
operation(name = "cancel") {
visibility = Visibility.Public
returnType = "Boolean"
}
// OCL invariants
constraint(name = "PositiveTotal", body = "self.total >= 0")
}
val customer = classOf(name = "Customer")
// Relationships
generalization(child = order, parent = "AbstractEntity")
realization(client = order, supplier = payable)
association(source = order, target = customer) {
sourceMultiplicity = "*"
targetMultiplicity = "1"
targetRole = "customer"
}
}
Classifier features in detail
| Element | Notes |
|---|---|
|
|
|
Block-form: add |
|
Inside an |
|
Applies an applied-stereotype to the surrounding element. Requires a matching profile
to be |
|
Adds an OCL invariant. Evaluated by |
|
Aggregation kind on an |
Object diagrams
Object diagrams show concrete instances. Use them for examples and snapshots.
objectDiagram(name = "Order #42") {
val order = objectOf(name = "order42", classifier = "Order") {
slot(name = "status", value = "CONFIRMED")
slot(name = "total", value = "99.50")
}
val item1 = objectOf(name = "item1", classifier = "OrderItem")
val item2 = objectOf(name = "item2", classifier = "OrderItem")
link(source = order, target = item1)
link(source = order, target = item2)
}
Component diagrams
Component diagrams describe software architecture: which components exist, what they provide, what they require.
componentDiagram(name = "Order service architecture") {
val orderService = component(name = "OrderService") {
port(name = "rest")
operation(name = "placeOrder")
attribute(name = "config", type = "OrderConfig")
}
val paymentService = component(name = "PaymentService") {
port(name = "rest")
}
dependency(source = orderService, target = paymentService) {
// technology = "REST" (V1.2)
}
}
Components can carry attributes and operations as of v0.3.0 — they are full classifiers.
State machines
State machines have their own scope inside a stateDiagram { … }.
stateDiagram(name = "Order lifecycle") {
stateMachine(name = "Order") {
initial(name = "start")
state(name = "draft")
state(name = "confirmed")
state(name = "shipped") { final() }
// Composite state with substates
state(name = "processing") {
initial(name = "picking")
state(name = "picking")
state(name = "packing")
transition(from = "picking", to = "packing", trigger = "packed")
}
// Transitions: trigger, guard, effect
transition(from = "start", to = "draft")
transition(from = "draft", to = "confirmed", trigger = "confirm",
guard = "self.total > 0", effect = "log('confirmed')")
transition(from = "confirmed", to = "shipped", trigger = "ship")
transition(from = "confirmed", to = "processing", trigger = "process")
transition(from = "processing", to = "shipped", trigger = "complete")
}
}
Triggers, guards, and effects are free-form strings. The runtime parses guards as OCL and evaluates them against the current state; effects are recorded in the trace but not executed in v0.3.0 (effect execution is V2). Triggers match by exact string equality.
See state-machine simulation for the operational semantics and how to run a machine against a stream of events.
Sequence diagrams
sequenceDiagram(name = "Place order flow") {
val customer = lifeline(name = "Customer", classifier = "Customer")
val service = lifeline(name = "OrderService", classifier = "OrderService")
val payment = lifeline(name = "PaymentService", classifier = "PaymentService")
message(from = customer, to = service, label = "placeOrder()")
message(from = service, to = payment, label = "authorise()")
message(from = payment, to = service, label = "OK", style = MessageStyle.Reply)
message(from = service, to = customer, label = "confirmation", style = MessageStyle.Reply)
}
Use case diagrams
useCaseDiagram(name = "Customer goals") {
val customer = actor(name = "Customer")
val staff = actor(name = "Staff")
val placeOrder = useCase(name = "Place order")
val payOrder = useCase(name = "Pay order")
val refundOrder = useCase(name = "Refund order")
customer.uses(placeOrder)
customer.uses(payOrder)
staff.uses(refundOrder)
placeOrder.includes(payOrder)
refundOrder.extends(payOrder)
}
Other types
The remaining diagram types (deployment, activity, communication, profile, timing, interaction overview, composite structure, package) all follow the same pattern: a top-level builder, classifier-like inner constructs, relationships drawn with infix helpers or DSL functions. See the examples directory for a script for each type.
Composing diagrams
A single script can contain multiple diagrams by wrapping them in umlModel:
umlModel(name = "Order subsystem") {
classDiagram(name = "Domain") {
// ...
}
componentDiagram(name = "Architecture") {
// ...
}
stateDiagram(name = "Lifecycle") {
stateMachine(name = "Order") { /* ... */ }
}
}
Each contained diagram renders to its own SVG when invoked through the CLI or Gradle plugin.