diff --git a/pom.xml b/pom.xml
index cd6379e..813466d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,6 +91,12 @@
5.9.2
test
+
+ org.junit.jupiter
+ junit-jupiter-params
+ 5.9.2
+ test
+
org.assertj
assertj-core
diff --git a/src/main/java/ch/ifocusit/plantuml/PlantUmlBuilder.java b/src/main/java/ch/ifocusit/plantuml/PlantUmlBuilder.java
index d7d66ea..bf79436 100644
--- a/src/main/java/ch/ifocusit/plantuml/PlantUmlBuilder.java
+++ b/src/main/java/ch/ifocusit/plantuml/PlantUmlBuilder.java
@@ -21,6 +21,7 @@
import ch.ifocusit.plantuml.classdiagram.model.Association;
import ch.ifocusit.plantuml.classdiagram.model.Association.AssociationType;
import ch.ifocusit.plantuml.classdiagram.model.Cardinality;
+import ch.ifocusit.plantuml.classdiagram.model.Link;
import ch.ifocusit.plantuml.classdiagram.model.Package;
import ch.ifocusit.plantuml.classdiagram.model.attribute.Attribute;
import ch.ifocusit.plantuml.classdiagram.model.clazz.Clazz;
@@ -177,7 +178,7 @@ public PlantUmlBuilder addType(Clazz clazz) {
.append(String.join(", ", stereotypes))
.append(STEREOTYPE_CLOSE));
// class link
- clazz.getLink().ifPresent(link -> content.append(SPACE).append(link));
+ clazz.getLink().ifPresent(link -> content.append(SPACE).append(link.render(Link.LinkContext.CLASS)));
// class color
clazz.getBackgroundColor().ifPresent(color -> content.append(SPACE).append(color(color)));
@@ -192,7 +193,7 @@ public PlantUmlBuilder addType(Clazz clazz) {
attribute.getTypeName().ifPresent(
type -> content.append(SPACE).append(SEMICOLON).append(SPACE).append(type));
// field link
- attribute.getLink().ifPresent(link -> content.append(SPACE).append(link));
+ attribute.getLink().ifPresent(link -> content.append(SPACE).append(link.render(Link.LinkContext.FIELD)));
content.append(NEWLINE);
}
// add methods
@@ -211,7 +212,7 @@ public PlantUmlBuilder addType(Clazz clazz) {
method.getReturnTypeName().ifPresent(
type -> content.append(SPACE).append(SEMICOLON).append(SPACE).append(type));
// method link
- method.getLink().ifPresent(link -> content.append(SPACE).append(link));
+ method.getLink().ifPresent(link -> content.append(SPACE).append(link.render(Link.LinkContext.METHOD)));
content.append(NEWLINE);
});
if (clazz.hasContent()) {
diff --git a/src/main/java/ch/ifocusit/plantuml/classdiagram/model/Link.java b/src/main/java/ch/ifocusit/plantuml/classdiagram/model/Link.java
index 300d892..ac1cd63 100644
--- a/src/main/java/ch/ifocusit/plantuml/classdiagram/model/Link.java
+++ b/src/main/java/ch/ifocusit/plantuml/classdiagram/model/Link.java
@@ -1,30 +1,63 @@
package ch.ifocusit.plantuml.classdiagram.model;
+import org.apache.commons.lang3.StringUtils;
+
@SuppressWarnings("unused")
public class Link {
private String url;
private String label;
-
- public String getUrl() {
- return url;
- }
+ private String tooltip;
public void setUrl(String url) {
this.url = url;
}
- public String getLabel() {
- return label;
- }
-
public void setLabel(String label) {
this.label = label;
}
- @Override
- public String toString() {
- return String.format("[[%s{%s}]]", url, label);
+ public void setTooltip(String tooltip) {
+ this.tooltip = tooltip;
}
+ public String render(LinkContext context) {
+ if (LinkContext.CLASS.equals(context)) {
+ if (StringUtils.isNotBlank(tooltip) && StringUtils.isNotBlank(url)) {
+ return String.format("[[%s{%s}]]", url, tooltip);
+ }
+ if (StringUtils.isNotBlank(tooltip) && StringUtils.isBlank(url)) {
+ return String.format("[[{%s}]]", tooltip);
+ }
+ if (StringUtils.isNotBlank(url)) {
+ return String.format("[[%s]]", url);
+ }
+ return StringUtils.EMPTY;
+ }
+ if (StringUtils.isNotBlank(tooltip) && StringUtils.isNotBlank(url) && StringUtils.isNotBlank(label)) {
+ return String.format("[[[%s{%s} %s]]]", url, tooltip, label);
+ }
+ if (StringUtils.isNotBlank(tooltip) && StringUtils.isNotBlank(url) && StringUtils.isBlank(label)) {
+ return String.format("[[[%s{%s}]]]", url, tooltip);
+ }
+ if (StringUtils.isBlank(tooltip) && StringUtils.isNotBlank(url) && StringUtils.isNotBlank(label)) {
+ return String.format("[[[%s %s]]]", url, label);
+ }
+ if (StringUtils.isNotBlank(tooltip) && StringUtils.isBlank(url) && StringUtils.isBlank(label)) {
+ return String.format("[[[{%s}]]]", tooltip);
+ }
+ if (StringUtils.isNotBlank(url) && StringUtils.isBlank(tooltip) && StringUtils.isBlank(label)) {
+ return String.format("[[[%s]]]", url);
+ }
+ if (StringUtils.isNotBlank(url) && StringUtils.isNotBlank(label) && StringUtils.isBlank(tooltip)) {
+ return String.format("[[[%s %s]]]", url, label);
+ }
+ if (StringUtils.isNotBlank(tooltip) && StringUtils.isBlank(url)) {
+ return String.format("[[[{%s}]]]", tooltip);
+ }
+ return StringUtils.EMPTY;
+ }
+ public enum LinkContext {
+ CLASS, FIELD, METHOD
+ }
}
diff --git a/src/test/java/ch/ifocusit/plantuml/classdiagram/ClassDiagramBuilderTest.java b/src/test/java/ch/ifocusit/plantuml/classdiagram/ClassDiagramBuilderTest.java
index 1c4e703..e260968 100644
--- a/src/test/java/ch/ifocusit/plantuml/classdiagram/ClassDiagramBuilderTest.java
+++ b/src/test/java/ch/ifocusit/plantuml/classdiagram/ClassDiagramBuilderTest.java
@@ -19,6 +19,7 @@
package ch.ifocusit.plantuml.classdiagram;
import ch.ifocusit.plantuml.PlantUmlBuilder;
+import ch.ifocusit.plantuml.classdiagram.model.Link;
import ch.ifocusit.plantuml.test.helper.domain.Devise;
import ch.ifocusit.plantuml.test.helper.domain.Driver;
import ch.ifocusit.plantuml.test.helper.domain.Price;
@@ -31,9 +32,11 @@
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
+import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.Objects;
+import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
@@ -47,10 +50,7 @@ class ClassDiagramBuilderTest {
@Test
void buildShouldGenerateDiagram() throws Exception {
- String expected = IOUtils.toString(
- Objects.requireNonNull(
- this.getClass().getResourceAsStream("/domain-diagram.plantuml")),
- Charset.defaultCharset());
+ String expected = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/domain-diagram.plantuml")), Charset.defaultCharset());
// tag::createSimple[]
String diagram =
@@ -137,4 +137,49 @@ public String getFieldName(Field field) {
+ " attr.brand : String" + CR + " attr.model : String" + CR
+ " attr.wheels : Collection" + CR + "}" + CR + CR + CR + "@enduml");
}
+
+ @Test
+ public void testLinkRenderer() throws IOException {
+ String expected = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/links.puml")), Charset.defaultCharset());
+
+ String diagram = new ClassDiagramBuilder()
+ .addClasses(Car.class, Driver.class)
+ .withLinkMaker(new LinkMaker() {
+ @Override
+ public Optional getClassLink(Class aClass) {
+ String label = aClass.getSimpleName();
+ Link link = new Link();
+ link.setLabel(label);
+ link.setUrl("https://link.com/" + label.toLowerCase());
+ if (aClass.equals(Driver.class)) {
+ link.setTooltip("Taxi Driver");
+ }
+ return Optional.of(link);
+ }
+
+ @Override
+ public Optional getFieldLink(Field field) {
+ if (field.getName().equals("wheels") || field.getDeclaringClass().equals(Driver.class)) {
+ return Optional.empty();
+ }
+ Link link = new Link();
+ link.setUrl("https://link.com/car/" + field.getName().toLowerCase());
+ if (field.getName().equals("brand") ) {
+ link.setLabel("lien");
+ }
+ if (field.getName().equals("price") ) {
+ link.setTooltip("Show details");
+ }
+ if (field.getName().equals("model") ) {
+ link.setLabel("Car models");
+ link.setTooltip("Show all cars' models");
+ }
+ return Optional.of(link);
+ }
+ })
+ .excludes(".*\\.ignored")
+ .build();
+
+ assertThat(diagram).isEqualTo(expected);
+ }
}
diff --git a/src/test/java/ch/ifocusit/plantuml/classdiagram/model/LinkTest.java b/src/test/java/ch/ifocusit/plantuml/classdiagram/model/LinkTest.java
new file mode 100644
index 0000000..280259b
--- /dev/null
+++ b/src/test/java/ch/ifocusit/plantuml/classdiagram/model/LinkTest.java
@@ -0,0 +1,57 @@
+package ch.ifocusit.plantuml.classdiagram.model;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class LinkTest {
+
+ public static final String URL = "https://link.com";
+ public static final String LABEL = "label";
+ public static final String TOOLTIP = "tooltip";
+
+ @ParameterizedTest
+ @CsvSource({
+ ",,,,",
+ URL + ",,,[[" + URL + "]]",
+ URL + "," + LABEL + ",,[[" + URL + "]]",
+ URL + "," + LABEL + "," + TOOLTIP + ",[[" + URL + "{" + TOOLTIP + "}]]",
+ ",," + TOOLTIP + ",[[{" + TOOLTIP + "}]]",
+ })
+ void render_class(String url, String label, String tooltip, String expected) {
+ // given
+ Link link = new Link();
+ link.setUrl(url);
+ link.setLabel(label);
+ link.setTooltip(tooltip);
+ // when
+ String actual = link.render(Link.LinkContext.CLASS);
+ // then
+ assertThat(actual).isEqualTo(expected == null ? StringUtils.EMPTY : expected);
+ }
+
+ @ParameterizedTest
+ @CsvSource({
+ ",,,,",
+ URL + ",,,[[[" + URL + "]]]",
+ "," + LABEL + ",,",
+ ",," + TOOLTIP + ",[[[{" + TOOLTIP + "}]]]",
+ URL + "," + LABEL + ",,[[[" + URL + " " + LABEL + "]]]",
+ URL + ",," + TOOLTIP + ",[[[" + URL + "{" + TOOLTIP + "}]]]",
+ URL + "," + LABEL + "," + TOOLTIP + ",[[[" + URL + "{" + TOOLTIP + "} " + LABEL + "]]]",
+ "," + LABEL + "," + TOOLTIP + ",[[[{" + TOOLTIP + "}]]]",
+ })
+ void render_field(String url, String label, String tooltip, String expected) {
+ // given
+ Link link = new Link();
+ link.setUrl(url);
+ link.setLabel(label);
+ link.setTooltip(tooltip);
+ // when
+ String actual = link.render(Link.LinkContext.FIELD);
+ // then
+ assertThat(actual).isEqualTo(expected == null ? StringUtils.EMPTY : expected);
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/links.puml b/src/test/resources/links.puml
new file mode 100644
index 0000000..a902455
--- /dev/null
+++ b/src/test/resources/links.puml
@@ -0,0 +1,23 @@
+@startuml
+
+class "Car" [[https://link.com/car]] {
+ brand : String [[[https://link.com/car/brand lien]]]
+ model : String [[[https://link.com/car/model{Show all cars' models} Car models]]]
+ drivers : Set [[[https://link.com/car/drivers]]]
+ price : Price [[[https://link.com/car/price{Show details}]]]
+ wheels : Collection
+ addDriver(Driver) : Car
+ addWheel(Wheel)
+ buyBy(Driver, BigDecimal, Devise) : Driver
+}
+
+class "Driver" [[https://link.com/driver{Taxi Driver}]] {
+ name : String
+ cars : List
+ addCar(Car)
+ buy(Car)
+}
+
+"Car" "*" <-> "*" "Driver" : drivers/cars
+
+@enduml
\ No newline at end of file