Skip to content

Commit

Permalink
Fix new 'package' usage for recent PlantUML versions.
Browse files Browse the repository at this point in the history
Signed-off-by: Sjoerd Talsma <sjoerdtalsma@users.noreply.github.com>
  • Loading branch information
sjoerdtalsma committed Nov 24, 2023
1 parent ac443d3 commit 03e4ea5
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 Talsma ICT
* Copyright 2016-2023 Talsma ICT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,6 +18,7 @@
import nl.talsmasoftware.umldoclet.uml.TypeName;

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
Expand Down Expand Up @@ -75,17 +76,18 @@ private TypeName _visit(TypeMirror type, Void parameter) {
public TypeName visitPrimitive(PrimitiveType primitiveType, Void parameter) {
// "byte", "char", "short", "int", "long", "float", "double", "boolean"
final String primitive = primitiveType.getKind().name().toLowerCase();
return new TypeName(primitive, primitive);
return new TypeName(null, primitive, primitive);
}

@Override
public TypeName visitNoType(NoType noType, Void parameter) {
// "void", "package", "module", "none"
final String none = noType.getKind().name().toLowerCase();
return new TypeName(none, none);
return new TypeName(null, none, none);
}

@Override

public TypeName visitDeclared(DeclaredType declaredType, Void parameter) {
final Element el = declaredType.asElement();
final String simpleName = el.getSimpleName().toString();
Expand All @@ -94,7 +96,17 @@ public TypeName visitDeclared(DeclaredType declaredType, Void parameter) {
final TypeName[] generics = declaredType.getTypeArguments().stream()
.map(generic -> _visit(generic, parameter))
.toArray(TypeName[]::new);
return new TypeName(simpleName, qualifiedName, generics);
final String packagename;

Element enclosingElement = el.getEnclosingElement();
if (enclosingElement.getKind().isInterface() || enclosingElement.getKind().isClass())
{
packagename = visit(enclosingElement.asType()).packagename;
} else {
int dot = qualifiedName.lastIndexOf('.');
packagename = dot > 0 ? qualifiedName.substring(0, dot) : null;
}
return new TypeName(packagename, simpleName, qualifiedName, generics);
}

@Override
Expand All @@ -115,7 +127,6 @@ public TypeName visitTypeVariable(TypeVariable typeVariable, Void parameter) {
TypeMirror lowerBound = typeVariable.getLowerBound();
if (lowerBound != null && !NO_KNOWN_TYPES.contains(lowerBound.getKind())) {
return TypeName.Variable.superBound(typeVariable.toString(), _visit(lowerBound, parameter));

}

return defaultAction(typeVariable, parameter);
Expand All @@ -136,7 +147,8 @@ protected TypeName defaultAction(TypeMirror tp, Void parameter) {
String qualified = tp.toString();
int lt = qualified.lastIndexOf('<');
int dot = (lt < 0 ? qualified : qualified.substring(0, lt)).lastIndexOf('.');
return new TypeName(qualified.substring(dot + 1), qualified);
String packagename = dot < 0 ? null : qualified.substring(0, dot);
return new TypeName(packagename, qualified.substring(dot + 1), qualified);
}

}
36 changes: 21 additions & 15 deletions src/main/java/nl/talsmasoftware/umldoclet/javadoc/UMLFactory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 Talsma ICT
* Copyright 2016-2023 Talsma ICT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -202,7 +202,7 @@ public Diagram createPackageDiagram(PackageElement packageElement) {
Map<String, Collection<Type>> foreignTypes = new LinkedHashMap<>();
List<Reference> references = new ArrayList<>();

Namespace namespace = createPackage(packageDiagram, packageElement, foreignTypes, references);
Namespace namespace = createPackage(packageDiagram, packageElement, foreignTypes, references, "::");
packageDiagram.addChild(namespace);

// Filter "java.lang" or "java.util" references that occur >= 3 times
Expand Down Expand Up @@ -233,14 +233,16 @@ public Diagram createPackageDiagram(PackageElement packageElement) {
.forEach(packageDiagram::addChild);

namespace.addChild(UmlCharacters.NEWLINE);
references.stream().map(Reference::canonical).forEach(namespace::addChild);

if (config.methods().javaBeanPropertiesAsFields()) {
namespace.getChildren().stream()
.filter(Type.class::isInstance).map(Type.class::cast)
.forEach(POST_PROCESSORS.javaBeanPropertiesAsFieldsPostProcessor());
}

if (!references.isEmpty()) packageDiagram.addChild(UmlCharacters.NEWLINE);
references.stream().map(Reference::canonical).forEach(packageDiagram::addChild);

return packageDiagram;
}

Expand Down Expand Up @@ -438,7 +440,7 @@ private void addForeignType(Map<String, Collection<Type>> foreignTypes, Element
}

private Collection<Reference> findPackageReferences(
Namespace namespace, Map<String, Collection<Type>> foreignTypes, TypeElement typeElement, Type type) {
Namespace namespace, Map<String, Collection<Type>> foreignTypes, TypeElement typeElement, Type type, String separator) {
Collection<Reference> references = new LinkedHashSet<>();

// Superclass reference.
Expand All @@ -452,9 +454,9 @@ private Collection<Reference> findPackageReferences(
TypeName superclassName = TypeNameVisitor.INSTANCE.visit(superclassType);
if (!config.excludedTypeReferences().contains(superclassName.qualified)) {
references.add(new Reference(
Reference.from(type.getName().qualified, null),
Reference.from(type.getName().getQualified(separator), null),
"--|>",
Reference.to(superclassName.qualified, null)));
Reference.to(superclassName.getQualified(separator), null)));
if (!namespace.contains(superclassName)) {
addForeignType(foreignTypes, superclassElement);
}
Expand All @@ -466,9 +468,9 @@ private Collection<Reference> findPackageReferences(
TypeName interfaceName = TypeNameVisitor.INSTANCE.visit(interfaceType);
if (!config.excludedTypeReferences().contains(interfaceName.qualified)) {
references.add(new Reference(
Reference.from(type.getName().qualified, null),
Reference.from(type.getName().getQualified(separator), null),
interfaceRefTypeFrom(type),
Reference.to(interfaceName.qualified, null)));
Reference.to(interfaceName.getQualified(separator), null)));
// TODO Figure out what to do IF the interface is found BUT has a different typename
if (!namespace.contains(interfaceName)) {
addForeignType(foreignTypes, env.getTypeUtils().asElement(interfaceType));
Expand All @@ -480,7 +482,10 @@ private Collection<Reference> findPackageReferences(
ElementKind enclosingKind = typeElement.getEnclosingElement().getKind();
if (enclosingKind.isClass() || enclosingKind.isInterface()) {
TypeName parentType = TypeNameVisitor.INSTANCE.visit(typeElement.getEnclosingElement().asType());
references.add(new Reference(Reference.from(parentType.qualified, null), "+--", Reference.to(type.getName().qualified, null)));
references.add(new Reference(
Reference.from(parentType.getQualified(separator), null),
"+--",
Reference.to(type.getName().getQualified(separator), null)));
// No check needed whether parent type lives in our namespace.
}

Expand All @@ -494,9 +499,9 @@ private Collection<Reference> findPackageReferences(
TypeNameWithCardinality fieldType = typeNameWithCardinality.apply(field.asType());
if (namespace.contains(fieldType.typeName)) {
addReference(references, new Reference(
Reference.from(type.getName().qualified, null),
Reference.from(type.getName().getQualified(separator), null),
"-->",
Reference.to(fieldType.typeName.qualified, fieldType.cardinality),
Reference.to(fieldType.typeName.getQualified(separator), fieldType.cardinality),
fieldName));
type.removeChildren(child -> child instanceof Field && ((Field) child).name.equals(fieldName));
}
Expand All @@ -513,9 +518,9 @@ private Collection<Reference> findPackageReferences(
TypeNameWithCardinality returnType = typeNameWithCardinality.apply(propertyType(method));
if (namespace.contains(returnType.typeName)) {
addReference(references, new Reference(
Reference.from(type.getName().qualified, null),
Reference.from(type.getName().getQualified(separator), null),
"-->",
Reference.to(returnType.typeName.qualified, returnType.cardinality),
Reference.to(returnType.typeName.getQualified(separator), returnType.cardinality),
propertyName));
type.removeChildren(child -> child instanceof Method
&& ((Method) child).name.equals(method.getSimpleName().toString()));
Expand Down Expand Up @@ -591,7 +596,8 @@ private static Stream<TypeElement> innerTypes(TypeElement type) {
Namespace createPackage(Diagram diagram,
PackageElement packageElement,
Map<String, Collection<Type>> foreignTypes,
List<Reference> references) {
List<Reference> references,
String referenceSeparator) {
final ModuleElement module = env.getElementUtils().getModuleOf(packageElement);
Namespace pkg = new Namespace(diagram, packageElement.getQualifiedName().toString(),
module == null ? null : module.getQualifiedName().toString());
Expand All @@ -603,7 +609,7 @@ Namespace createPackage(Diagram diagram,
.filter(env::isIncluded)
.map(typeElement -> {
Type type = createAndPopulateType(pkg, typeElement);
references.addAll(findPackageReferences(pkg, foreignTypes, typeElement, type));
references.addAll(findPackageReferences(pkg, foreignTypes, typeElement, type, referenceSeparator));
return type;
})
.flatMap(type -> Stream.of(UmlCharacters.NEWLINE, type))
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/nl/talsmasoftware/umldoclet/uml/Diagram.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 Talsma ICT
* Copyright 2016-2023 Talsma ICT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -63,14 +63,16 @@ public <IPW extends IndentingPrintWriter> IPW writeTo(IPW output) {
IndentingPrintWriter indented = output.indent();
writeCustomDirectives(config.customPlantumlDirectives(), indented);
writeChildrenTo(indented);
indented.newline();
writeFooterTo(indented);
output.append("@enduml").newline();
return output;
}

protected <IPW extends IndentingPrintWriter> IPW writeCustomDirectives(List<String> customDirectives, IPW output) {
customDirectives.forEach(output::println);
if (!customDirectives.isEmpty()) {
output.newline();
}
return output;
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/nl/talsmasoftware/umldoclet/uml/Namespace.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 Talsma ICT
* Copyright 2016-2023 Talsma ICT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -59,7 +59,7 @@ private <IPW extends IndentingPrintWriter> IPW writeNameTo(IPW output) {

@Override
public <IPW extends IndentingPrintWriter> IPW writeTo(IPW output) {
writeNameTo(output.append("namespace").whitespace()).append('{').newline();
writeNameTo(output.append("package").whitespace()).append('{').newline();
writeChildrenTo(output.indent());
output.append('}').newline();
return output;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 Talsma ICT
* Copyright 2016-2023 Talsma ICT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,15 +16,21 @@
package nl.talsmasoftware.umldoclet.uml;

import nl.talsmasoftware.umldoclet.configuration.Configuration;
import nl.talsmasoftware.umldoclet.rendering.indent.IndentingPrintWriter;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static java.util.Objects.requireNonNull;

/**
* @author Sjoerd Talsma
*/
public class PackageDiagram extends Diagram {
private static final String SEPARATOR_DIRECTIVE = "set separator ";
public static final String SEPARATOR = "::";

final String moduleName;
final String packageName;
Expand All @@ -36,6 +42,14 @@ public PackageDiagram(Configuration config, String packageName, String moduleNam
this.moduleName = moduleName;
}

@Override
protected <IPW extends IndentingPrintWriter> IPW writeCustomDirectives(List<String> customDirectives, IPW output) {
final List<String> directives = new ArrayList<>(customDirectives == null ? Collections.emptyList() : customDirectives);
directives.removeIf(directive -> directive.startsWith(SEPARATOR_DIRECTIVE));
directives.add(SEPARATOR_DIRECTIVE + SEPARATOR);
return super.writeCustomDirectives(directives, output);
}

@Override
protected File getPlantUmlFile() {
if (pumlFile == null) {
Expand Down
23 changes: 15 additions & 8 deletions src/main/java/nl/talsmasoftware/umldoclet/uml/TypeName.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 Talsma ICT
* Copyright 2016-2023 Talsma ICT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -36,11 +36,13 @@
* @author Sjoerd Talsma
*/
public class TypeName {
public final String packagename;
public final String simple;
public final String qualified;
private final TypeName[] generics;

public TypeName(String simpleName, String qualifiedName, TypeName... generics) {
public TypeName(String packagename, String simpleName, String qualifiedName, TypeName... generics) {
this.packagename = packagename;
this.simple = simpleName;
this.qualified = requireNonNull(qualifiedName, "Type has no qualified name");
this.generics = generics.clone();
Expand All @@ -54,16 +56,21 @@ private static boolean isQualified(TypeDisplay display) {
return display != null && display.name().startsWith("QUALIFIED");
}

public String getQualified(String separator) {
int plen = packagename == null ? 0 : packagename.length();
if (qualified.length() > plen && plen > 0 && separator != null && !separator.isEmpty()) {
return packagename + separator + qualified.substring(plen + 1);
}
return qualified;
}

protected String toUml(TypeDisplay display, Namespace namespace) {
StringBuilder output = new StringBuilder();
if (display == null) display = TypeDisplay.SIMPLE;
if (!TypeDisplay.NONE.equals(display)) try {

if (namespace != null && this.qualified.startsWith(namespace.name + ".")) {
String name = this.qualified.substring(namespace.name.length() + 1);
// Workaround for PlantUML problem with namespace and inner classes
if (name.indexOf('.') > 0) name = this.qualified;
output.append(name);
output.append(this.qualified.substring(namespace.name.length() + 1));
} else if (isQualified(display)) {
output.append(this.qualified);
} else {
Expand Down Expand Up @@ -120,7 +127,7 @@ public String toString() {

public static class Array extends TypeName {
private Array(TypeName componentType) {
super(componentType.simple, componentType.qualified, componentType.generics);
super(componentType.packagename, componentType.simple, componentType.qualified, componentType.generics);
}

public static Array of(TypeName componentType) {
Expand All @@ -138,7 +145,7 @@ public static class Variable extends TypeName {
private final boolean isExtends;

private Variable(String variable, TypeName bound, boolean isExtends) {
super(bound.simple, bound.qualified, bound.generics);
super(bound.packagename, bound.simple, bound.qualified, bound.generics);
this.variable = variable;
this.isExtends = isExtends;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 Talsma ICT
* Copyright 2016-2023 Talsma ICT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -70,11 +70,12 @@ public void testPropertiesAsFieldsForPublicClass() {
@Test
public void testPropertiesAsFieldsForPackageDiagram() {
String umlFileName = StandardJavaBean.class.getPackageName().replace('.', '/') + "/package.puml";
String nameInPackage = StandardJavaBean.class.getPackageName() + "::" + StandardJavaBean.class.getSimpleName();
String uml = TestUtil.read(new File(outputdir, umlFileName));
assertThat(uml, containsString("+stringValue: String"));
assertThat(uml, containsString("+intValue: int"));
assertThat(uml, containsString("+booleanValue: boolean"));
assertThat(uml, containsString("StandardJavaBean --> StandardJavaBean: child"));
assertThat(uml, containsString(nameInPackage + " --> " + nameInPackage + ": child"));

assertThat(uml, not(containsString("getStringValue(")));
assertThat(uml, not(containsString("setStringValue(")));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 Talsma ICT
* Copyright 2016-2023 Talsma ICT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,7 +39,7 @@ public void testDefaultPackageDocumentation() {
), is(0));

String uml = TestUtil.read(new File("target/issues/107/package.puml"));
assertThat(uml, containsString("namespace unnamed"));
assertThat(uml, containsString("package unnamed"));
assertThat(uml, containsString("class Foo"));
}

Expand Down
Loading

0 comments on commit 03e4ea5

Please sign in to comment.