Profiles
UML 2.x profiles are the OMG-standard extension mechanism: a profile defines stereotypes and tagged values that extend specific metaclasses. kUML treats profiles as first-class modules — five ship with v0.3.0, more are easy to add.
Built-in profiles
| Profile | Module | Stereotypes (selected) |
|---|---|---|
AUTOSAR |
|
|
JavaEE / Jakarta EE |
|
|
Spring |
|
|
OpenAPI |
|
|
SoaML |
|
|
All five are discovered through ServiceLoader — apply by name, no Maven coordinate gymnastics.
AUTOSAR example
AUTOSAR Classic Platform R22-11 modeled as type-safe Kotlin. Five stereotypes cover software components, communication interfaces, ports, runnables and behavior specs:
componentDiagram(name = "Brake Assist SWC") {
applyProfile("AUTOSAR")
component("BrakeAssist") {
stereotype("SoftwareComponent", "kind" to "Application", "packageName" to "powertrain")
port("wheelSpeedIn") { stereotype("AutosarPort", "direction" to "Required") }
port("brakeCmdOut") { stereotype("AutosarPort", "direction" to "Provided") }
operation("evaluate") { stereotype("Runnable", "kind" to "Periodic", "periodMs" to 10L) }
operation("onInit") { stereotype("Runnable", "kind" to "OnInit") }
}
interface("WheelSpeed") {
stereotype("ComInterface", "version" to "1.0", "isService" to false)
operation("read")
}
}
The «AutosarPort» stereotype is deliberately named that way (not Port) to avoid a
clash with the UML metamodel’s own Port metaclass.
Authoring your own profile
Profiles are plain Kotlin objects implementing KumlProfile. Drop the file in any module,
add a META-INF/services/dev.kuml.profile.KumlProfileProvider entry, and the CLI / Gradle
plugin / IDE picks it up.
object MyProfile : KumlProfile {
override val name: String = "MyCompany"
override fun stereotypes(): List<KumlStereotype> = listOf(
KumlStereotype(
name = "Aggregate",
extending = setOf(UmlMetaclass.Class),
taggedValues = listOf(
KumlTaggedValue(name = "boundedContext", type = "String"),
),
constraints = listOf(
KumlStereotypeConstraint(
name = "MustHaveIdAttribute",
body = "self.ownedAttribute->exists(a | a.appliedStereotype.name = 'Id')",
),
),
),
)
}
class MyProfileProvider : KumlProfileProvider {
override fun profile(): KumlProfile = MyProfile
}
META-INF/services/dev.kuml.profile.KumlProfileProvider:
com.example.MyProfileProvider
That’s the full registration. After applyProfile("MyCompany"), stereotype("Aggregate", …)
works in any class diagram.
Stereotype validation
When you applyProfile, kUML enforces:
-
The stereotype name exists in the profile.
-
The stereotype’s
extendingset contains the metaclass of the host element (so you can’t putEntityon anUmlOperation). -
Tagged values are typed — you can’t pass a
StringwhereIntis required. -
Any constraints attached to the stereotype validate at
kuml validatetime.
Mismatches are reported with the constraint name, the host element, and the OCL body — the same format as user-written constraints.
Profiles and code generation
The Java and SQL generators inspect applied stereotypes from the JavaEE profile and emit matching framework annotations / DDL:
| Stereotype | Java output | SQL output |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
(column omitted) |
The generators read stereotypes by name, not by class reference — they have no
compile-time dependency on the profile modules. You can apply the same Java codegen to a
model that uses a custom MyCompany-flavoured profile, as long as the stereotypes have the
same names.
See code generation.
Multi-profile diagrams
applyProfile is repeatable — apply as many as you need:
classDiagram(name = "Service domain") {
applyProfile("JavaEE")
applyProfile("Spring")
applyProfile("OpenAPI")
classOf("OrderService") {
operation("scheduleCleanup") { stereotype("Scheduled", "cron" to "0 0 * * *") }
operation("placeOrder") { stereotype("Operation", "method" to "POST") }
}
}
Stereotype names must be unique across applied profiles within a single diagram — the parser fails fast on collisions with a clear error.