Codegenerierung
Kurzantwort: Der cdms-generator ist ein Java-Annotation-Processor. Er
liest beim Maven-Build einen YAML-Cache mit der Modellbeschreibung und erzeugt
pro Modell rund 20 Java-Klassen nach target/generated-sources/annotations/.
Der YAML-Cache kommt vorher vom CdmsMetadataFetcher aus einer laufenden
CDMS-Instanz – oder liegt bereits lokal vor (Offline-Modus).
flowchart TB
subgraph "Maven: generate-sources"
F[CdmsMetadataFetcher]
K[(Keycloak)]
API[(CDMS REST-API)]
Y["YAML-Cache<br/>models.yaml · folders.yaml<br/>enumerations.yaml · system.yaml"]
F -->|Client-Credentials-Token| K
F -->|Modelle, Felder, Endpunkte| API
F --> Y
end
subgraph "Maven: compile"
L[Lombok] --> MS[MapStruct] --> G[CdmsProcessor]
Y --> G
G --> GEN["target/generated-sources/annotations/<br/>~20 Klassen je Modell"]
G --> SC["src/main/java/…<br/>Scaffold, nur wenn nicht vorhanden"]
end
Die Reihenfolge der Annotation-Processors ist verbindlich: Lombok → MapStruct → cdms-generator. Lombok erzeugt die Accessoren, auf die MapStruct aufsetzt; der CDMS-Generator kommt zuletzt.
Was erzeugt wird
Abschnitt betitelt „Was erzeugt wird“Pro Modell
Abschnitt betitelt „Pro Modell“| Klasse | Zweck |
|---|---|
{Model}Entity | JPA-Entity mit @Table, @Column, Beziehungen |
{Model}Dto | Antwortmodell |
{Model}CreatePayload / {Model}UpdatePayload | Eingabemodelle |
{Model}Payload2DtoMapper | Payload → DTO |
{Model}Entity2DtoMapper | Entity → DTO |
{Model}AbstractDto2EntityMapper / {Model}Dto2EntityMapper | DTO → Entity |
{Model}Map2AbstractEntityMapper / {Model}Map2EntityMapper | Map<String,Object> → Entity (für PATCH) |
{Model}MetaService | Feldmetadaten, Regeln, Rollen |
{Model}MapperService | zentraler Mapping-Einstieg |
{Model}Api | REST-Controller mit den konfigurierten Endpunkten |
{Model}System | System-Layer (Rekursion, Hooks, Validierung) |
{Model}Database | Persistenz-Layer |
{Model}AuthorizationLayer | Rollenprüfung |
{Model}AttributeFilter | attributbasierter Datenfilter |
{Model}TupleMapperService | Tuple-Projektion für Abfragen |
{Model}ApiHub | Router-Controller bei abstrakten Modellen |
{Model}ApiSingleton / {Model}SystemSingleton | bei @Singleton |
Einmal pro Build
Abschnitt betitelt „Einmal pro Build“| Klasse | Zweck |
|---|---|
com.codamai.cdms.EntityRegistryService | ordnet alle Entities den Gruppen System/Tenant/User zu |
com.codamai.cdms.RoleRegistryService | sammelt alle Rollen aus den Endpunkt-Konfigurationen |
com.codamai.cdms.config.JpaNativeHints | GraalVM-Hints für die Entity-Klassen |
com.codamai.cdms.config.JacksonNativeHints | GraalVM-Hints für DTOs und Payloads |
Scaffold – nur beim ersten Mal
Abschnitt betitelt „Scaffold – nur beim ersten Mal“Start (Spring-Boot-Hauptklasse), OpenApiConfiguration,
NativeHintsConfiguration. Diese Dateien landen in src/main/java und werden
nie überschrieben – sie dürfen frei angepasst werden.
Endpunkt-Kopplung
Abschnitt betitelt „Endpunkt-Kopplung“Aus den im Modell konfigurierten Endpunkt-Typen leitet der Generator ab, welche Methoden entstehen:
| Endpoint im Modell | aktiviert |
|---|---|
CreateEndpoint | create |
UpdateEndpoint | update und patch |
ReadEndpoint | read und query |
DeleteEndpoint | delete |
SearchEndpoint | search |
Ohne Endpunkt-Konfiguration werden alle Endpunkte aktiviert.
Die pom.xml wird mitgepflegt
Abschnitt betitelt „Die pom.xml wird mitgepflegt“Der Generator erzeugt nicht nur Java-Klassen, er hält auch die Abhängigkeiten der
Anwendung aktuell. Dazu markiert er in der pom.xml zwei Bereiche:
<!-- cdms-managed:dependencies:start -->…<!-- cdms-managed:dependencies:end -->Was zwischen den Markern steht, gehört dem Generator und wird bei jedem Lauf neu geschrieben. Alles außerhalb bleibt unangetastet – selbst hinzugefügte Abhängigkeiten, eigene Plugins und eigene Properties überstehen den Lauf.
Welche Abhängigkeiten das sind, ergibt sich aus system.yaml: der Datenbanktreiber
aus database, das Speicher-Backend aus storage, die Authentifizierung aus
authentication, dazu Envers, sobald ein Modell auditiert wird.
Eine abgewählte Abhängigkeit wird entfernt, nicht stehen gelassen. Wechselt ein System von MySQL auf PostgreSQL, verschwindet der MySQL-Treiber; wird ein Artefakt umbenannt, verschwindet der alte Name. Ohne das bliebe die alte Koordinate als vermeintlich handgepflegte Abhängigkeit liegen – und zwar ohne Version, weil der verwaltete Block seine Versionen vom Parent-POM bezieht. Genau diese Form kann Maven nicht lesen.
Eine Grenze hat das: Ist die pom.xml bereits unlesbar, kommt der Generator nicht
mehr zum Zug – Maven bricht vor dem Build ab. Wird ein vom Parent verwaltetes
Artefakt umbenannt, bleibt die alte Koordinate deshalb besser eine Release lang
im dependencyManagement stehen; dann räumt der nächste Lauf sie selbst weg.
Die POM-Pflege hängt nicht am Netz: Sie arbeitet aus dem Cache und läuft auch im
Offline-Modus. Abschalten lässt sie sich mit CODEGEN_POM_GENERATE=false.
Konfiguration
Abschnitt betitelt „Konfiguration“Priorität absteigend: Umgebungsvariable → JVM-Property →
cdms-generator.properties → Standardwert.
| Variable / Property | Bedeutung |
|---|---|
CODEGEN_KEYCLOAK_URL / cdms.generator.keycloakUrl | Keycloak-Basis-URL (Pflicht) |
CODEGEN_KEYCLOAK_REALM / …keycloakRealm | Realm, Standard master |
CODEGEN_CLIENT_ID / …clientId | OAuth2-Client des Generators (Pflicht) |
CODEGEN_CLIENT_SECRET / …clientSecret | Secret (Pflicht, nie ins Repo) |
CODEGEN_CDMS_URL / …cdmsUrl | Basis-URL der CDMS-API |
CODEGEN_SYSTEM_ID / …systemId | UUID des zu generierenden Systems (Pflicht) |
CODEGEN_CACHE_DIR / …cacheDir | Cache-Verzeichnis, Standard target/cache |
CODEGEN_OFFLINE / …offline | true = kein Netzzugriff, vorhandenen Cache nutzen |
Compiler-Argumente am maven-compiler-plugin:
| Argument | Bedeutung |
|---|---|
-Acdms.generator.cacheDir | Pfad zum YAML-Cache |
-Acdms.generator.basePackage | Basis-Package der generierten Klassen |
Regel: generierten Code nicht anfassen
Abschnitt betitelt „Regel: generierten Code nicht anfassen“Der generierte Code wird bei jedem Build neu erzeugt. Fachlogik gehört in
Hooks und eigene Klassen unter src/main/java.
Wer generierten Code editiert, verliert die Änderung beim nächsten Lauf.