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
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 8acdc97..20de963 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;
@@ -501,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
@@ -674,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));
@@ -733,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);
@@ -810,7 +810,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 (ElementUtil.isPrimitive(type)
+ || ElementUtil.isType(type, TypeKind.TYPEVAR) || ElementUtil.isType(type, TypeKind.WILDCARD)
+ || type instanceof NoType
|| c.toString().equals(ElementUtil.getTypeElement(type).toString())) {
continue;
}
@@ -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, "", "", "");
}
@@ -856,10 +858,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 (ElementUtil.isPrimitive(type) || 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 +869,49 @@ class ClassGraph {
Options opt = optionProvider.getOptionsFor(docTrees, ElementUtil.getTypeElement(type));
if (opt.matchesCollPackageExpression(ElementUtil.getQualifiedName(types, type))) {
List extends TypeMirror> 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 extends TypeMirror> getInterfaceTypeArguments(TypeElement iface, TypeMirror t) {
+ private List extends TypeMirror> 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 extends TypeMirror> 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 extends TypeMirror> 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/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 f5b4175..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);
}
/**
@@ -1161,8 +1150,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..6bee5af 100644
--- a/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java
+++ b/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java
@@ -123,13 +123,12 @@ 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);
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("([Hh]2>)|()|( getInterfacesTypes(TypeElement element) {
- return element.getInterfaces();
+ public static List extends TypeMirror> getInterfacesTypes(Element element) {
+ if (element instanceof TypeElement) {
+ return ((TypeElement) element).getInterfaces();
+ }
+ return Collections.emptyList();
}
public static List getInterfaces(TypeElement element) {