From 70929da1d0028b8352ded0ca106aff088bc27d7a Mon Sep 17 00:00:00 2001 From: Laurent SCHOELENS Date: Mon, 27 Mar 2023 12:18:46 +0200 Subject: [PATCH 1/4] make some fixes after run on bigger project --- .../java/org/umlgraph/doclet/ClassGraph.java | 40 +++++++++++++------ .../java/org/umlgraph/doclet/Options.java | 3 +- .../java/org/umlgraph/doclet/UmlGraphDoc.java | 2 +- .../org/umlgraph/doclet/util/ElementUtil.java | 28 +++++++++++-- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/umlgraph/doclet/ClassGraph.java b/src/main/java/org/umlgraph/doclet/ClassGraph.java index 8acdc97..e9974f1 100644 --- a/src/main/java/org/umlgraph/doclet/ClassGraph.java +++ b/src/main/java/org/umlgraph/doclet/ClassGraph.java @@ -57,8 +57,6 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.NoType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVariable; -import javax.lang.model.type.WildcardType; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.JavaFileManager; @@ -810,7 +808,9 @@ class ClassGraph { for (TypeMirror type : types) { // skip primitives and type variables, as well as dependencies // on the source class - if (type.getKind().isPrimitive() || type instanceof NoType || type instanceof WildcardType || type instanceof TypeVariable + if (type.getKind().isPrimitive() + || ElementUtil.isType(type, TypeKind.TYPEVAR) || ElementUtil.isType(type, TypeKind.WILDCARD) + || type instanceof NoType || c.toString().equals(ElementUtil.getTypeElement(type).toString())) { continue; } @@ -856,10 +856,10 @@ class ClassGraph { private FieldRelationInfo getFieldRelationInfo(VariableElement field) { TypeMirror type = field.asType(); - if (type.getKind().isPrimitive() || type.getKind() == TypeKind.WILDCARD || type.getKind() == TypeKind.TYPEVAR) { + if (type.getKind().isPrimitive() || ElementUtil.isType(type, TypeKind.WILDCARD) || ElementUtil.isType(type, TypeKind.TYPEVAR)) { return null; } - + if (ElementUtil.dimensions(type).endsWith("[]")) { return new FieldRelationInfo(ElementUtil.getTypeElement(type), true); } @@ -867,35 +867,49 @@ class ClassGraph { Options opt = optionProvider.getOptionsFor(docTrees, ElementUtil.getTypeElement(type)); if (opt.matchesCollPackageExpression(ElementUtil.getQualifiedName(types, type))) { List argTypes = getInterfaceTypeArguments(collectionClassDoc, type); - if (argTypes != null && argTypes.size() == 1 && !argTypes.get(0).getKind().isPrimitive()) { - return new FieldRelationInfo(ElementUtil.getTypeElement(argTypes.get(0)), true); + if (argTypes != null && argTypes.size() == 1 && !argTypes.get(0).getKind().isPrimitive() && !ElementUtil.isType(argTypes.get(0), TypeKind.TYPEVAR)) { + TypeMirror arg = argTypes.get(0); + return new FieldRelationInfo(ElementUtil.getTypeElement(arg), true); } argTypes = getInterfaceTypeArguments(mapClassDoc, type); - if (argTypes != null && argTypes.size() == 2 && !argTypes.get(1).getKind().isPrimitive()) { - return new FieldRelationInfo(ElementUtil.getTypeElement(argTypes.get(1)), true); + if (argTypes != null && argTypes.size() == 2 && !argTypes.get(1).getKind().isPrimitive() && !ElementUtil.isType(argTypes.get(1), TypeKind.TYPEVAR)) { + TypeMirror arg = argTypes.get(1); + return new FieldRelationInfo(ElementUtil.getTypeElement(arg), true); } } return new FieldRelationInfo(ElementUtil.getTypeElement(type), false); } - private List getInterfaceTypeArguments(TypeElement iface, TypeMirror t) { + private List getInterfaceTypeArguments(Element iface, TypeMirror t) { if (t instanceof DeclaredType) { DeclaredType pt = (DeclaredType) t; if (iface != null && iface.equals(pt.asElement())) { return pt.getTypeArguments(); } else { - for (TypeMirror pti : ElementUtil.getInterfacesTypes(iface)) { + for (TypeMirror pti : ElementUtil.getInterfacesTypes(pt.asElement())) { List result = getInterfaceTypeArguments(iface, pti); if (result != null) { return result; } } - if (ElementUtil.getSuperclassType(pt) != null) { - return getInterfaceTypeArguments(iface, ElementUtil.getSuperclassType(pt)); + TypeMirror superType = ElementUtil.getSuperclassType(pt); + if (superType != null && superType.getKind() != TypeKind.NONE) { + return getInterfaceTypeArguments(iface, superType); } } + } else if (iface instanceof TypeElement) { + for (TypeMirror pti : ElementUtil.getInterfacesTypes((TypeElement) iface)) { + List result = getInterfaceTypeArguments(iface, pti); + if (result != null) { + return result; + } + } + TypeElement superType = ElementUtil.getSuperclass((TypeElement) iface); + if (superType != null && superType.asType().getKind() != TypeKind.NONE) { + return getInterfaceTypeArguments(iface, superType.asType()); + } } return null; } diff --git a/src/main/java/org/umlgraph/doclet/Options.java b/src/main/java/org/umlgraph/doclet/Options.java index f5b4175..b5b9b77 100644 --- a/src/main/java/org/umlgraph/doclet/Options.java +++ b/src/main/java/org/umlgraph/doclet/Options.java @@ -1161,8 +1161,9 @@ public class Options implements Cloneable, OptionProvider { public boolean matchesCollPackageExpression(CharSequence s) { for (Pattern collPattern : collPackages) { Matcher m = collPattern.matcher(s); - if (strictMatching ? m.matches() : m.find()) + if (strictMatching ? m.matches() : m.find()) { return true; + } } return false; } diff --git a/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java b/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java index 6a8f796..93ec7d6 100644 --- a/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java +++ b/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java @@ -129,7 +129,7 @@ public class UmlGraphDoc implements Doclet { UmlGraph.buildGraph(reporter, root, opt, view, packageDoc); runGraphviz(opt.dotExecutable, outputFolder, ElementUtil.getModuleOf(root, packageDoc), packageDoc.getQualifiedName(), packageDoc.getSimpleName(), reporter); alterHtmlDocs(opt, outputFolder, ElementUtil.getModuleOf(root, packageDoc), packageDoc.getQualifiedName(), packageDoc.getSimpleName(), "package-summary.html", - Pattern.compile("()|(

)|(

getInterfacesTypes(TypeElement element) { - return element.getInterfaces(); + public static List getInterfacesTypes(Element element) { + if (element instanceof TypeElement) { + return ((TypeElement) element).getInterfaces(); + } + return Collections.emptyList(); } public static List getInterfaces(TypeElement element) { From 16c1937aad58d8f6addcfec7cf62e105150a6d16 Mon Sep 17 00:00:00 2001 From: Laurent SCHOELENS Date: Mon, 27 Mar 2023 12:24:31 +0200 Subject: [PATCH 2/4] update readme --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 905ce9e..49903ed 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,9 @@ Visit the project's [home page](http://www.spinellis.gr/umlgraph) for more infor ## Compatibility -Currently, only Java 8 is supported by the Doclet. +If you build against Java 8, please use latest version of 5.X of the Doclet. -In Java 9 the JavaDoc Doclet API changed substantially, and the doclet therefore -needs to be largely rewritten. - -Sorry, this has not happened yet - volunteers for this task are welcome. +Since Java 9 doclet APIs where completely rewritten, the Doclet in version 6 supports only supports Java 9 and above. ## Development versions From 27d782166661dd46cbd0d140ebd975739aa99498 Mon Sep 17 00:00:00 2001 From: Laurent SCHOELENS Date: Mon, 27 Mar 2023 12:31:35 +0200 Subject: [PATCH 3/4] fix generation with primitive array --- src/main/java/org/umlgraph/doclet/ClassGraph.java | 4 ++-- .../java/org/umlgraph/doclet/util/ElementUtil.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/umlgraph/doclet/ClassGraph.java b/src/main/java/org/umlgraph/doclet/ClassGraph.java index e9974f1..ce3e2c0 100644 --- a/src/main/java/org/umlgraph/doclet/ClassGraph.java +++ b/src/main/java/org/umlgraph/doclet/ClassGraph.java @@ -808,7 +808,7 @@ class ClassGraph { for (TypeMirror type : types) { // skip primitives and type variables, as well as dependencies // on the source class - if (type.getKind().isPrimitive() + if (ElementUtil.isPrimitive(type) || ElementUtil.isType(type, TypeKind.TYPEVAR) || ElementUtil.isType(type, TypeKind.WILDCARD) || type instanceof NoType || c.toString().equals(ElementUtil.getTypeElement(type).toString())) { @@ -856,7 +856,7 @@ class ClassGraph { private FieldRelationInfo getFieldRelationInfo(VariableElement field) { TypeMirror type = field.asType(); - if (type.getKind().isPrimitive() || ElementUtil.isType(type, TypeKind.WILDCARD) || ElementUtil.isType(type, TypeKind.TYPEVAR)) { + if (ElementUtil.isPrimitive(type) || ElementUtil.isType(type, TypeKind.WILDCARD) || ElementUtil.isType(type, TypeKind.TYPEVAR)) { return null; } diff --git a/src/main/java/org/umlgraph/doclet/util/ElementUtil.java b/src/main/java/org/umlgraph/doclet/util/ElementUtil.java index fe54ded..4597cbd 100644 --- a/src/main/java/org/umlgraph/doclet/util/ElementUtil.java +++ b/src/main/java/org/umlgraph/doclet/util/ElementUtil.java @@ -23,6 +23,16 @@ import jdk.javadoc.doclet.DocletEnvironment; public class ElementUtil { + public static boolean isPrimitive(TypeMirror type) { + if (type.getKind().isPrimitive()) { + return true; + } + if (type.getKind() == TypeKind.ARRAY) { + return isPrimitive(((ArrayType) type).getComponentType()); + } + return false; + } + public static boolean isType(TypeMirror type, TypeKind kind) { if (type.getKind() == kind) { return true; From de056154bd3575469cecda21e9ff9be13fea8bd2 Mon Sep 17 00:00:00 2001 From: Laurent SCHOELENS Date: Mon, 27 Mar 2023 14:52:04 +0200 Subject: [PATCH 4/4] remove reporter diagnostic / fix class graph / make javase api 9 default / fix package-list and element-list api fetch --- pom.xml | 30 ++++----- .../java/org/umlgraph/doclet/ClassGraph.java | 10 +-- .../java/org/umlgraph/doclet/ClassInfo.java | 8 +-- .../java/org/umlgraph/doclet/ContextView.java | 4 +- .../java/org/umlgraph/doclet/Options.java | 67 ++++++++----------- .../java/org/umlgraph/doclet/UmlGraphDoc.java | 2 - 6 files changed, 54 insertions(+), 67 deletions(-) diff --git a/pom.xml b/pom.xml index 7a9184d..67cf050 100644 --- a/pom.xml +++ b/pom.xml @@ -110,19 +110,19 @@ maven-javadoc-plugin 3.5.0 - - - depend - X - - - hidden - X - - - opt - X - + + + depend + X + + + hidden + X + + + opt + X + org.umlgraph.doclet.UmlGraphDoc ${project.build.directory}${file.separator}${project.build.finalName}.jar @@ -134,12 +134,10 @@ - - - + false true diff --git a/src/main/java/org/umlgraph/doclet/ClassGraph.java b/src/main/java/org/umlgraph/doclet/ClassGraph.java index ce3e2c0..20de963 100644 --- a/src/main/java/org/umlgraph/doclet/ClassGraph.java +++ b/src/main/java/org/umlgraph/doclet/ClassGraph.java @@ -499,8 +499,9 @@ class ClassGraph { } } externalTableEnd(); - if (url != null) + if (url != null) { w.print(", URL=\"" + url + "\""); + } nodeProperties(opt); // If needed, add a note for this node @@ -672,8 +673,9 @@ class ClassGraph { } // Handle missing classes: Options opt = optionProvider.getOptionsFor(className); - if (opt.matchesHideExpression(className)) + if (opt.matchesHideExpression(className)) { continue; + } w.println(linePrefix + "// " + className); w.print(linePrefix + info.name + "[label="); externalTableStart(opt, className, classToUrl(className)); @@ -731,7 +733,7 @@ class ClassGraph { } // if source and dest are not already linked, add a dependency - RelationPattern rp = getClassInfo(c, true).getRelation(fri.cd.toString()); + RelationPattern rp = getClassInfo(c, true).getRelation(fri.cd.getQualifiedName()); if (rp == null) { String destAdornment = fri.multiple ? "*" : ""; relation(opt, opt.inferRelationshipType, c, fri.cd, "", "", destAdornment); @@ -828,7 +830,7 @@ class ClassGraph { } // if source and dest are not already linked, add a dependency - RelationPattern rp = getClassInfo(c, true).getRelation(fc.toString()); + RelationPattern rp = getClassInfo(c, true).getRelation(fc.getQualifiedName()); if (rp == null || rp.matchesOne(new RelationPattern(RelationDirection.OUT))) { relation(opt, RelationType.DEPEND, c, fc, "", "", ""); } diff --git a/src/main/java/org/umlgraph/doclet/ClassInfo.java b/src/main/java/org/umlgraph/doclet/ClassInfo.java index 5939a0c..61194ab 100644 --- a/src/main/java/org/umlgraph/doclet/ClassInfo.java +++ b/src/main/java/org/umlgraph/doclet/ClassInfo.java @@ -44,7 +44,7 @@ class ClassInfo { * classes linked with a bi-directional relation , and the ones referred by a * directed relation */ - Map relatedClasses = new HashMap<>(); + Map relatedClasses = new HashMap<>(); ClassInfo(boolean h) { hidden = h; @@ -53,16 +53,16 @@ class ClassInfo { } public void addRelation(Name dest, RelationType rt, RelationDirection d) { - RelationPattern ri = relatedClasses.get(dest); + RelationPattern ri = relatedClasses.get(dest.toString()); if (ri == null) { ri = new RelationPattern(RelationDirection.NONE); - relatedClasses.put(dest, ri); + relatedClasses.put(dest.toString(), ri); } ri.addRelation(rt, d); } public RelationPattern getRelation(CharSequence dest) { - return relatedClasses.get(dest); + return relatedClasses.get(dest.toString()); } /** Start numbering from zero. */ diff --git a/src/main/java/org/umlgraph/doclet/ContextView.java b/src/main/java/org/umlgraph/doclet/ContextView.java index 5202315..837a1b7 100755 --- a/src/main/java/org/umlgraph/doclet/ContextView.java +++ b/src/main/java/org/umlgraph/doclet/ContextView.java @@ -61,7 +61,7 @@ public class ContextView implements OptionProvider { this.centerOptions.nodeFillColor = "lemonChiffon"; this.centerOptions.showQualified = false; - this.matcher = new ContextMatcher(root, Pattern.compile(Pattern.quote(cd.getQualifiedName().toString())), myGlobalOptions, true); + this.matcher = new ContextMatcher(root, Pattern.compile(Pattern.quote(cd.toString())), myGlobalOptions, true); } @@ -103,7 +103,7 @@ public class ContextView implements OptionProvider { Options opt; if (!matcher.matches(name)) { opt = hideOptions; - } else if (name.equals(cd.getQualifiedName())) { + } else if (name.equals(cd.getSimpleName())) { opt = centerOptions; } else { opt = globalOptions; diff --git a/src/main/java/org/umlgraph/doclet/Options.java b/src/main/java/org/umlgraph/doclet/Options.java index b5b9b77..8b1e2e8 100644 --- a/src/main/java/org/umlgraph/doclet/Options.java +++ b/src/main/java/org/umlgraph/doclet/Options.java @@ -589,7 +589,7 @@ public class Options implements Cloneable, OptionProvider { // reused often, especially in UmlGraphDoc, worth creating just once and reusing private static final Pattern allPattern = Pattern.compile(".*"); - protected static final String DEFAULT_EXTERNAL_APIDOC = "http://docs.oracle.com/javase/7/docs/api/"; + protected static final String DEFAULT_EXTERNAL_APIDOC = "https://docs.oracle.com/javase/9/docs/api/"; // instance fields List hidePatterns = new ArrayList<>(); @@ -975,28 +975,37 @@ public class Options implements Cloneable, OptionProvider { * @param packageListUrl */ private void addApiDocRoots(String packageListUrl) { + tryFetch(null, packageListUrl); + } + + private void tryFetch(String docUrl, String packageListUrl) { BufferedReader br = null; packageListUrl = fixApiDocRoot(packageListUrl); - try { - URL url = new URL(packageListUrl + "package-list"); - br = new BufferedReader(new InputStreamReader(url.openStream())); - String line; - while ((line = br.readLine()) != null) { - line = line + "."; - Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*"); - apiDocMap.put(pattern, packageListUrl); - } - } catch (IOException e) { - System.err.println("Errors happened while accessing the package-list file at " + packageListUrl); - } finally { - if (br != null) { - try { - br.close(); - } catch (IOException e) { + String finalDocUrl = docUrl == null ? null : fixApiDocRoot(docUrl); + for (String suffix : List.of("package-list", "element-list")) { + try { + URL url = new URL(packageListUrl + suffix); + br = new BufferedReader(new InputStreamReader(url.openStream())); + String line; + while ((line = br.readLine()) != null) { + if (!line.startsWith("module:")) { + line = line + "."; + Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*"); + apiDocMap.put(pattern, finalDocUrl == null ? packageListUrl : finalDocUrl); + } + } + break; + } catch (IOException e) { + System.err.println("Errors happened while accessing the " + suffix + " file at " + packageListUrl); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException e) { + } } } } - } /** @@ -1008,27 +1017,7 @@ public class Options implements Cloneable, OptionProvider { * @param packageListUrl folder containing the package-list */ private void addApiDocRootsOffline(String docUrl, String packageListUrl) { - BufferedReader br = null; - packageListUrl = fixApiDocRoot(packageListUrl); - try { - URL url = new URL(packageListUrl + "package-list"); - br = new BufferedReader(new InputStreamReader(url.openStream())); - String line; - while ((line = br.readLine()) != null) { - line = line + "."; - Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*"); - apiDocMap.put(pattern, fixApiDocRoot(docUrl)); - } - } catch (IOException e) { - System.err.println("Unable to access the package-list file at " + packageListUrl); - } finally { - if (br != null) { - try { - br.close(); - } catch (IOException e) { - } - } - } + tryFetch(docUrl, packageListUrl); } /** diff --git a/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java b/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java index 93ec7d6..6bee5af 100644 --- a/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java +++ b/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java @@ -123,7 +123,6 @@ public class UmlGraphDoc implements Doclet { continue; } if (!packages.contains(packageDoc.getSimpleName())) { - reporter.print(Diagnostic.Kind.WARNING, "Package processed " + packageDoc.getQualifiedName()); packages.add(packageDoc.getSimpleName()); OptionProvider view = new PackageView(outputFolder, packageDoc, root, opt); UmlGraph.buildGraph(reporter, root, opt, view, packageDoc); @@ -151,7 +150,6 @@ public class UmlGraphDoc implements Doclet { ContextView view = null; for (TypeElement classDoc : classDocs) { - reporter.print(Diagnostic.Kind.WARNING, "Class processed " + classDoc.getQualifiedName()); try { if (view == null) { view = new ContextView(outputFolder, classDoc, root, opt);