Skip to content

Commit 7c93b27

Browse files
committed
GH-43 - Improve consistency in Documenter API.
Consistent method overloads to avoid the need to create default instances of customization options. Renamed Options to DiagramOptions for consistency with CanvasOptions.
1 parent c192a7d commit 7c93b27

File tree

3 files changed

+103
-65
lines changed

3 files changed

+103
-65
lines changed

spring-modulith-docs/src/main/java/org/springframework/modulith/docs/Documenter.java

Lines changed: 99 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -137,25 +137,11 @@ private Documenter(ApplicationModules modules, String outputFolder) {
137137
this.properties = new ConfigurationProperties();
138138
}
139139

140-
private Map<ApplicationModule, Component> getComponents(Options options) {
141-
142-
if (components == null) {
143-
144-
this.components = modules.stream() //
145-
.collect(Collectors.toMap(Function.identity(),
146-
it -> container.addComponent(options.getDefaultDisplayName().apply(it), "", "Module")));
147-
148-
this.components.forEach((key, value) -> addDependencies(key, value, options));
149-
}
150-
151-
return components;
152-
}
153-
154140
/**
155141
* Customize the output folder to write the generated files to. Defaults to {@value #DEFAULT_LOCATION}.
156142
*
157143
* @param outputFolder must not be {@literal null} or empty.
158-
* @return
144+
* @return the current instance, will never be {@literal null}.
159145
* @see #DEFAULT_LOCATION
160146
*/
161147
public Documenter withOutputFolder(String outputFolder) {
@@ -169,24 +155,49 @@ public Documenter withOutputFolder(String outputFolder) {
169155
* <li>Individual component diagrams per module to include all upstream modules.</li>
170156
* <li>The Module Canvas for each module.</li>
171157
* </ul>
158+
* using {@link DiagramOptions#defaults()} and {@link CanvasOptions#defaults()}.
172159
*
173-
* @param options must not be {@literal null}, use {@link Options#defaults()} for default.
174-
* @param canvasOptions must not be {@literal null}, use {@link CanvasOptions#defaults()} for default.
175160
* @return the current instance, will never be {@literal null}.
176161
*/
177-
public Documenter writeDocumentation(Options options, CanvasOptions canvasOptions) {
162+
public Documenter writeDocumentation() {
163+
return writeDocumentation(DiagramOptions.defaults(), CanvasOptions.defaults());
164+
}
165+
166+
/**
167+
* Writes all available documentation:
168+
* <ul>
169+
* <li>The entire set of modules as overview component diagram.</li>
170+
* <li>Individual component diagrams per module to include all upstream modules.</li>
171+
* <li>The Module Canvas for each module.</li>
172+
* </ul>
173+
*
174+
* @param options must not be {@literal null}.
175+
* @param canvasOptions must not be {@literal null}.
176+
* @return the current instance, will never be {@literal null}.
177+
*/
178+
public Documenter writeDocumentation(DiagramOptions options, CanvasOptions canvasOptions) {
178179

179180
return writeModulesAsPlantUml(options)
180181
.writeIndividualModulesAsPlantUml(options) //
181182
.writeModuleCanvases(canvasOptions);
182183
}
183184

184185
/**
185-
* Writes the PlantUML component diagram for all {@link ApplicationModules}.
186+
* Writes the PlantUML component diagram for all {@link ApplicationModules} using {@link DiagramOptions#defaults()}.
187+
*
188+
* @return the current instance, will never be {@literal null}.
189+
*/
190+
public Documenter writeModulesAsPlantUml() {
191+
return writeModulesAsPlantUml(DiagramOptions.defaults());
192+
}
193+
194+
/**
195+
* Writes the PlantUML component diagram for all {@link ApplicationModules} with the given {@link DiagramOptions}.
186196
*
187197
* @param options must not be {@literal null}.
198+
* @return the current instance, will never be {@literal null}.
188199
*/
189-
public Documenter writeModulesAsPlantUml(Options options) {
200+
public Documenter writeModulesAsPlantUml(DiagramOptions options) {
190201

191202
Assert.notNull(options, "Options must not be null!");
192203

@@ -201,13 +212,19 @@ public Documenter writeModulesAsPlantUml(Options options) {
201212
return this;
202213
}
203214

215+
public Documenter writeIndividualModulesAsPlantUml() {
216+
return writeIndividualModulesAsPlantUml(DiagramOptions.defaults());
217+
}
218+
204219
/**
205220
* Writes the component diagrams for all individual modules.
206221
*
207222
* @param options must not be {@literal null}.
208223
* @return the current instance, will never be {@literal null}.
209224
*/
210-
public Documenter writeIndividualModulesAsPlantUml(Options options) {
225+
public Documenter writeIndividualModulesAsPlantUml(DiagramOptions options) {
226+
227+
Assert.notNull(options, "DiagramOptions must not be null!");
211228

212229
modules.forEach(it -> writeModuleAsPlantUml(it, options));
213230

@@ -224,18 +241,18 @@ public Documenter writeModuleAsPlantUml(ApplicationModule module) {
224241

225242
Assert.notNull(module, "Module must not be null!");
226243

227-
return writeModuleAsPlantUml(module, Options.defaults());
244+
return writeModuleAsPlantUml(module, DiagramOptions.defaults());
228245
}
229246

230247
/**
231248
* Writes the PlantUML component diagram for the given {@link ApplicationModule} with the given rendering
232-
* {@link Options}.
249+
* {@link DiagramOptions}.
233250
*
234251
* @param module must not be {@literal null}.
235252
* @param options must not be {@literal null}.
236253
* @return the current instance, will never be {@literal null}.
237254
*/
238-
public Documenter writeModuleAsPlantUml(ApplicationModule module, Options options) {
255+
public Documenter writeModuleAsPlantUml(ApplicationModule module, DiagramOptions options) {
239256

240257
Assert.notNull(module, "Module must not be null!");
241258
Assert.notNull(options, "Options must not be null!");
@@ -253,16 +270,24 @@ public Documenter writeModuleAsPlantUml(ApplicationModule module, Options option
253270
}
254271

255272
/**
256-
* Writes all module canvases using {@link Options#defaults()}.
273+
* Writes all module canvases using {@link DiagramOptions#defaults()}.
257274
*
258275
* @return the current instance, will never be {@literal null}.
259276
*/
260277
public Documenter writeModuleCanvases() {
261278
return writeModuleCanvases(CanvasOptions.defaults());
262279
}
263280

281+
/**
282+
* Writes all module canvases using the given {@link DiagramOptions}.
283+
*
284+
* @param options must not be {@literal null}.
285+
* @return the current instance, will never be {@literal null}.
286+
*/
264287
public Documenter writeModuleCanvases(CanvasOptions options) {
265288

289+
Assert.notNull(options, "CanvasOptions must not be null!");
290+
266291
modules.forEach(module -> {
267292

268293
String filename = String.format(options.getTargetFileName().orElse("module-%s.adoc"), module.getName());
@@ -280,15 +305,15 @@ public Documenter writeModuleCanvases(CanvasOptions options) {
280305
return this;
281306
}
282307

283-
public String toModuleCanvas(ApplicationModule module) {
308+
String toModuleCanvas(ApplicationModule module) {
284309
return toModuleCanvas(module, CanvasOptions.defaults());
285310
}
286311

287-
public String toModuleCanvas(ApplicationModule module, String apiBase) {
312+
String toModuleCanvas(ApplicationModule module, String apiBase) {
288313
return toModuleCanvas(module, CanvasOptions.defaults().withApiBase(apiBase));
289314
}
290315

291-
public String toModuleCanvas(ApplicationModule module, CanvasOptions options) {
316+
String toModuleCanvas(ApplicationModule module, CanvasOptions options) {
292317

293318
Asciidoctor asciidoctor = Asciidoctor.withJavadocBase(modules, options.getApiBase());
294319
Function<List<JavaClass>, String> mapper = asciidoctor::typesToBulletPoints;
@@ -314,11 +339,11 @@ private <T> String addTableRow(List<T> types, String header, Function<List<T>, S
314339
return types.isEmpty() ? "" : writeTableRow(header, mapper.apply(types));
315340
}
316341

317-
public String toPlantUml() {
318-
return createPlantUml(Options.defaults());
342+
String toPlantUml() {
343+
return createPlantUml(DiagramOptions.defaults());
319344
}
320345

321-
private void addDependencies(ApplicationModule module, Component component, Options options) {
346+
private void addDependencies(ApplicationModule module, Component component, DiagramOptions options) {
322347

323348
DEPENDENCY_DESCRIPTIONS.entrySet().stream().forEach(entry -> {
324349

@@ -339,7 +364,21 @@ private void addDependencies(ApplicationModule module, Component component, Opti
339364
});
340365
}
341366

342-
private void addComponentsToView(ApplicationModule module, ComponentView view, Options options) {
367+
private Map<ApplicationModule, Component> getComponents(DiagramOptions options) {
368+
369+
if (components == null) {
370+
371+
this.components = modules.stream() //
372+
.collect(Collectors.toMap(Function.identity(),
373+
it -> container.addComponent(options.getDefaultDisplayName().apply(it), "", "Module")));
374+
375+
this.components.forEach((key, value) -> addDependencies(key, value, options));
376+
}
377+
378+
return components;
379+
}
380+
381+
private void addComponentsToView(ApplicationModule module, ComponentView view, DiagramOptions options) {
343382

344383
Supplier<Stream<ApplicationModule>> bootstrapDependencies = () -> module.getBootstrapDependencies(modules,
345384
options.getDependencyDepth());
@@ -352,7 +391,8 @@ private void addComponentsToView(ApplicationModule module, ComponentView view, O
352391
addComponentsToView(dependencies, view, options, it -> it.add(getComponents(options).get(module)));
353392
}
354393

355-
private void addComponentsToView(Supplier<Stream<ApplicationModule>> modules, ComponentView view, Options options,
394+
private void addComponentsToView(Supplier<Stream<ApplicationModule>> modules, ComponentView view,
395+
DiagramOptions options,
356396
Consumer<ComponentView> afterCleanup) {
357397

358398
Styles styles = view.getViewSet().getConfiguration().getStyles();
@@ -409,8 +449,9 @@ private void potentiallyRemoveDefaultRelationship(View view, Collection<Relation
409449
.findFirst().ifPresent(view::remove);
410450
}
411451

412-
private static Component applyBackgroundColor(ApplicationModule module, Map<ApplicationModule, Component> components,
413-
Options options,
452+
private static Component applyBackgroundColor(ApplicationModule module,
453+
Map<ApplicationModule, Component> components,
454+
DiagramOptions options,
414455
Styles styles) {
415456

416457
Component component = components.get(module);
@@ -433,7 +474,7 @@ private static Component applyBackgroundColor(ApplicationModule module, Map<Appl
433474
return component;
434475
}
435476

436-
private Documenter writeViewAsPlantUml(ComponentView view, String filename, Options options) {
477+
private Documenter writeViewAsPlantUml(ComponentView view, String filename, DiagramOptions options) {
437478

438479
Path file = recreateFile(filename);
439480

@@ -448,7 +489,7 @@ private Documenter writeViewAsPlantUml(ComponentView view, String filename, Opti
448489
}
449490
}
450491

451-
private String render(ComponentView view, Options options) {
492+
private String render(ComponentView view, DiagramOptions options) {
452493

453494
switch (options.style) {
454495

@@ -470,7 +511,7 @@ private String render(ComponentView view, Options options) {
470511
}
471512
}
472513

473-
private String createPlantUml(Options options) {
514+
private String createPlantUml(DiagramOptions options) {
474515

475516
ComponentView componentView = createComponentView(options);
476517
componentView.setTitle(modules.getSystemName().orElse("Modules"));
@@ -480,11 +521,11 @@ private String createPlantUml(Options options) {
480521
return render(componentView, options);
481522
}
482523

483-
private ComponentView createComponentView(Options options) {
524+
private ComponentView createComponentView(DiagramOptions options) {
484525
return createComponentView(options, null);
485526
}
486527

487-
private ComponentView createComponentView(Options options, @Nullable ApplicationModule module) {
528+
private ComponentView createComponentView(DiagramOptions options, @Nullable ApplicationModule module) {
488529

489530
String prefix = module == null ? "modules-" : module.getName();
490531

@@ -533,7 +574,7 @@ public static Connection of(Relationship relationship) {
533574
*/
534575
@Getter(AccessLevel.PRIVATE)
535576
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
536-
public static class Options {
577+
public static class DiagramOptions {
537578

538579
private static final Set<DependencyType> ALL_TYPES = Arrays.stream(DependencyType.values())
539580
.collect(Collectors.toSet());
@@ -551,7 +592,8 @@ public static class Options {
551592
private final @With Predicate<ApplicationModule> exclusions;
552593

553594
/**
554-
* A {@link Predicate} to define which Structurizr {@link Component}s to be included in the diagram to be created.
595+
* A {@link Predicate} to define which Structurizr {@link Component}s to be included in the diagram to be
596+
* created.
555597
*/
556598
private final @With Predicate<Component> componentFilter;
557599

@@ -574,8 +616,8 @@ public static class Options {
574616
private final @With Function<ApplicationModule, Optional<String>> colorSelector;
575617

576618
/**
577-
* A callback to return a default display names for a given {@link ApplicationModule}. Default implementation just
578-
* forwards to {@link ApplicationModule#getDisplayName()}.
619+
* A callback to return a default display names for a given {@link ApplicationModule}. Default implementation
620+
* just forwards to {@link ApplicationModule#getDisplayName()}.
579621
*/
580622
private final @With Function<ApplicationModule, String> defaultDisplayName;
581623

@@ -587,23 +629,24 @@ public static class Options {
587629
/**
588630
* Configuration setting to define whether modules that do not have a relationship to any other module shall be
589631
* retained in the diagrams created. The default is {@value ElementsWithoutRelationships#HIDDEN}. See
590-
* {@link Options#withExclusions(Predicate)} for a more fine-grained way of defining which modules to exclude in
591-
* case you flip this to {@link ElementsWithoutRelationships#VISIBLE}.
632+
* {@link DiagramOptions#withExclusions(Predicate)} for a more fine-grained way of defining which modules to
633+
* exclude in case you flip this to {@link ElementsWithoutRelationships#VISIBLE}.
592634
*
593635
* @see #withExclusions(Predicate)
594636
*/
595637
private final @With ElementsWithoutRelationships elementsWithoutRelationships;
596638

597639
/**
598-
* Creates a new default {@link Options} instance configured to use all dependency types, list immediate
640+
* Creates a new default {@link DiagramOptions} instance configured to use all dependency types, list immediate
599641
* dependencies for individual module instances, not applying any kind of {@link ApplicationModule} or
600642
* {@link Component} filters and default file names.
601643
*
602644
* @return will never be {@literal null}.
603645
*/
604-
public static Options defaults() {
605-
return new Options(ALL_TYPES, DependencyDepth.IMMEDIATE, it -> false, it -> true, it -> false, null,
606-
__ -> Optional.empty(), it -> it.getDisplayName(), DiagramStyle.C4, ElementsWithoutRelationships.HIDDEN);
646+
public static DiagramOptions defaults() {
647+
return new DiagramOptions(ALL_TYPES, DependencyDepth.IMMEDIATE, it -> false, it -> true, it -> false, null,
648+
__ -> Optional.empty(), it -> it.getDisplayName(), DiagramStyle.C4,
649+
ElementsWithoutRelationships.HIDDEN);
607650
}
608651

609652
/**
@@ -612,13 +655,14 @@ public static Options defaults() {
612655
* @param types must not be {@literal null}.
613656
* @return
614657
*/
615-
public Options withDependencyTypes(DependencyType... types) {
658+
public DiagramOptions withDependencyTypes(DependencyType... types) {
616659

617660
Assert.notNull(types, "Dependency types must not be null!");
618661

619662
Set<DependencyType> dependencyTypes = Arrays.stream(types).collect(Collectors.toSet());
620663

621-
return new Options(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly, targetFileName,
664+
return new DiagramOptions(dependencyTypes, dependencyDepth, exclusions, componentFilter, targetOnly,
665+
targetFileName,
622666
colorSelector, defaultDisplayName, style, elementsWithoutRelationships);
623667
}
624668

@@ -657,11 +701,11 @@ public enum DiagramStyle {
657701
/**
658702
* Configuration setting to define whether modules that do not have a relationship to any other module shall be
659703
* retained in the diagrams created. The default is {@value ElementsWithoutRelationships#HIDDEN}. See
660-
* {@link Options#withExclusions(Predicate)} for a more fine-grained way of defining which modules to exclude in
661-
* case you flip this to {@link ElementsWithoutRelationships#VISIBLE}.
704+
* {@link DiagramOptions#withExclusions(Predicate)} for a more fine-grained way of defining which modules to
705+
* exclude in case you flip this to {@link ElementsWithoutRelationships#VISIBLE}.
662706
*
663707
* @author Oliver Drotbohm
664-
* @see Options#withExclusions(Predicate)
708+
* @see DiagramOptions#withExclusions(Predicate)
665709
*/
666710
public enum ElementsWithoutRelationships {
667711
HIDDEN, VISIBLE;

spring-modulith-example/src/test/java/example/ModularityTests.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717

1818
import org.junit.jupiter.api.Test;
1919
import org.springframework.modulith.docs.Documenter;
20-
import org.springframework.modulith.docs.Documenter.CanvasOptions;
21-
import org.springframework.modulith.docs.Documenter.Options;
2220
import org.springframework.modulith.model.ApplicationModules;
2321

2422
/**
@@ -37,10 +35,6 @@ void verifiesModularStructure() {
3735

3836
@Test
3937
void createModuleDocumentation() {
40-
41-
var canvasOptions = CanvasOptions.defaults();
42-
43-
new Documenter(modules) //
44-
.writeDocumentation(Options.defaults(), canvasOptions);
38+
new Documenter(modules).writeDocumentation();
4539
}
4640
}

0 commit comments

Comments
 (0)