From f7b1c579c81ae75549b31aecdf0f90c925844d62 Mon Sep 17 00:00:00 2001 From: Alexander Miller Date: Wed, 11 Dec 2024 16:19:46 +0100 Subject: [PATCH] GH-988 - Allow registering skin parameters in generated PlantUML diagrams. --- .../modulith/docs/Documenter.java | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Documenter.java b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Documenter.java index 93ed13da..33787479 100644 --- a/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Documenter.java +++ b/spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Documenter.java @@ -34,6 +34,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.structurizr.export.plantuml.AbstractPlantUMLExporter; import org.springframework.lang.Nullable; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.core.ApplicationModules; @@ -553,6 +554,7 @@ public class Documenter { case C4: var c4PlantUmlExporter = new C4PlantUMLExporter(); + addSkinParamsFromOptions(c4PlantUmlExporter, options); var diagram = c4PlantUmlExporter.export(view); return diagram.getDefinition(); @@ -561,12 +563,19 @@ public class Documenter { default: var plantUmlExporter = new CustomizedPlantUmlExporter(); + addSkinParamsFromOptions(plantUmlExporter, options); plantUmlExporter.addSkinParam("componentStyle", "uml1"); return plantUmlExporter.export(view).getDefinition(); } } + private void addSkinParamsFromOptions(AbstractPlantUMLExporter exporter, DiagramOptions options) { + for (var skinParamEntry : options.skinParams.entrySet()) { + exporter.addSkinParam(skinParamEntry.getKey(), skinParamEntry.getValue()); + } + } + private String createPlantUml(DiagramOptions options) { ComponentView componentView = createComponentView(options); @@ -667,6 +676,7 @@ public class Documenter { private final Function defaultDisplayName; private final DiagramStyle style; private final ElementsWithoutRelationships elementsWithoutRelationships; + private final Map skinParams; /** * @param dependencyTypes must not be {@literal null}. @@ -679,13 +689,15 @@ public class Documenter { * @param defaultDisplayName must not be {@literal null}. * @param style must not be {@literal null}. * @param elementsWithoutRelationships must not be {@literal null}. + * @param skinParams must not be {@literal null}. */ DiagramOptions(Set dependencyTypes, DependencyDepth dependencyDepth, Predicate exclusions, Predicate componentFilter, Predicate targetOnly, @Nullable String targetFileName, Function> colorSelector, Function defaultDisplayName, DiagramStyle style, - ElementsWithoutRelationships elementsWithoutRelationships) { + ElementsWithoutRelationships elementsWithoutRelationships, + Map skinParams) { Assert.notNull(dependencyTypes, "Dependency types must not be null!"); Assert.notNull(dependencyDepth, "Dependency depth must not be null!"); @@ -696,6 +708,7 @@ public class Documenter { Assert.notNull(defaultDisplayName, "Default display name must not be null!"); Assert.notNull(style, "DiagramStyle must not be null!"); Assert.notNull(elementsWithoutRelationships, "ElementsWithoutRelationships must not be null!"); + Assert.notNull(skinParams, "SkinParams must not be null!"); this.dependencyTypes = dependencyTypes; this.dependencyDepth = dependencyDepth; @@ -707,6 +720,7 @@ public class Documenter { this.defaultDisplayName = defaultDisplayName; this.style = style; this.elementsWithoutRelationships = elementsWithoutRelationships; + this.skinParams = skinParams; } /** @@ -714,7 +728,7 @@ public class Documenter { */ public DiagramOptions withDependencyDepth(DependencyDepth dependencyDepth) { return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, - targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } /** @@ -722,7 +736,7 @@ public class Documenter { */ public DiagramOptions withExclusions(Predicate exclusions) { return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, - targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } /** @@ -730,7 +744,7 @@ public class Documenter { */ public DiagramOptions withComponentFilter(Predicate componentFilter) { return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, - targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } /** @@ -740,7 +754,7 @@ public class Documenter { */ public DiagramOptions withTargetOnly(Predicate targetOnly) { return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, - targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } /** @@ -752,7 +766,7 @@ public class Documenter { Assert.isTrue(targetFileName.contains("%s"), () -> INVALID_FILE_NAME_PATTERN.formatted(targetFileName)); return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, - targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } /** @@ -760,7 +774,7 @@ public class Documenter { */ public DiagramOptions withColorSelector(Function> colorSelector) { return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, - targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } /** @@ -769,7 +783,7 @@ public class Documenter { */ public DiagramOptions withDefaultDisplayName(Function defaultDisplayName) { return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, - targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } /** @@ -777,7 +791,7 @@ public class Documenter { */ public DiagramOptions withStyle(DiagramStyle style) { return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, - targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } /** @@ -790,7 +804,18 @@ public class Documenter { */ public DiagramOptions withElementsWithoutRelationships(ElementsWithoutRelationships elementsWithoutRelationships) { return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, - targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); + } + + /** + * Configuration setting to add arbitrary skin parameters to the created diagrams. + * + * Applies to both the UML and C4 {@link DiagramStyle styles}. + */ + public DiagramOptions withSkinParam(String name, String value) { + skinParams.put(name, value); + return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, + targetFileName, colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } /** @@ -803,7 +828,7 @@ public class Documenter { public static DiagramOptions defaults() { return new DiagramOptions(ALL_TYPES, DependencyDepth.IMMEDIATE, it -> false, it -> true, it -> false, null, __ -> Optional.empty(), it -> it.getDisplayName(), DiagramStyle.C4, - ElementsWithoutRelationships.HIDDEN); + ElementsWithoutRelationships.HIDDEN, new LinkedHashMap<>()); } /** @@ -820,7 +845,7 @@ public class Documenter { return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, targetFileName, - colorSelector, defaultDisplayName, style, elementsWithoutRelationships); + colorSelector, defaultDisplayName, style, elementsWithoutRelationships, skinParams); } private Optional getTargetFileName() {