From 0477f4b82d4e75d1a44ae2802a3109da7f975d46 Mon Sep 17 00:00:00 2001 From: Erich Schubert Date: Sun, 21 Oct 2018 03:29:13 +0200 Subject: [PATCH] add -!qualifyGenerics option that strips package names only in generics This is useful in combination with `-qualify`; in particular with `-qualify -postfixpackage` This version also supports *inner* classes, where the outer class has a generic. Test case: `p1.Class.Inner` Depending on `-qualify` and `-qualifyGenerics` this can become either: ``` p1.Class.Inner p1.Class.Inner Class.Inner Class.Inner ``` on the long run, it may however be convenient to also allow hiding generics completely, and/or show them just as diamonds. For example `Class<>.Inner<>` as a shorthand. Other users will prefer to see the constraint only, e.g., `Class.Inner`... it may need a list of different named formatters. --- doc/ack.xml | 1 + doc/cd-opt.xml | 6 +- doc/ver.xml | 6 ++ .../java/org/umlgraph/doclet/ClassGraph.java | 75 ++++++++++--------- .../java/org/umlgraph/doclet/Options.java | 6 ++ 5 files changed, 58 insertions(+), 36 deletions(-) diff --git a/doc/ack.xml b/doc/ack.xml index aa7dc8a..e23805a 100644 --- a/doc/ack.xml +++ b/doc/ack.xml @@ -46,6 +46,7 @@ UMLGraph would not be in its current state without their contributions.
  • Soraya Santana de la Fe
  • Jonathan R. Santos
  • Jan Schlüter
  • +
  • Erich Schubert
  • Sebastian Setzer
  • Jörn Guy Süß
  • Andreas Studer
  • diff --git a/doc/cd-opt.xml b/doc/cd-opt.xml index 505457b..bdee2bb 100644 --- a/doc/cd-opt.xml +++ b/doc/cd-opt.xml @@ -1,9 +1,10 @@ -A number of options contol the operation of UMLGraph +A number of options control the operation of UMLGraph class diagram generator. These can be specified on the command line, and most can also -be specified through javadoc tags within the diagram, affecting all or some elements. +be specified through javadoc @opt tags within the diagram, affecting all or some elements. +Most have a negated version by prefixing an exclamation mark.

    What Gets Drawn

    @@ -32,6 +33,7 @@ be specified through javadoc tags within the diagram, affecting all or some elem in the package view (which would by default filter to only include package members).
    -operations
    Show class operations (Java methods)
    -qualify
    Produce fully-qualified class names.
    +
    -qualifyGenerics
    Use fully-qualified class names in Java generics.
    -types
    Add type information to attributes and operations
    -view
    Specify the fully qualified name of a class that contains a view definition. Only the class diagram specified by this view will be generated. diff --git a/doc/ver.xml b/doc/ver.xml index 683e43e..f89f6eb 100644 --- a/doc/ver.xml +++ b/doc/ver.xml @@ -7,6 +7,12 @@
  • The @opt include option can be used to include classes from foreign packages in the package view (unless hidden with @opt hide).
  • You can now also use @opt in package-info.java.
  • +
  • Added -qualifyGenerics option to separately control the inclusion of +package names for the class (-qualify) and its generics. In particular +this works well with -qualify -postfixpackage (and -!qualifyGenerics).
    +To get the old -qualify behavior, you need to add -qualifyGenerics, +the default is off, and it will not inherit from -qualify.
  • +
  • Better handling of complex names with generics and inner classes such as pkg.Outer<T>.Inner.
  • diff --git a/src/main/java/org/umlgraph/doclet/ClassGraph.java b/src/main/java/org/umlgraph/doclet/ClassGraph.java index 7d3d557..378cea7 100644 --- a/src/main/java/org/umlgraph/doclet/ClassGraph.java +++ b/src/main/java/org/umlgraph/doclet/ClassGraph.java @@ -129,24 +129,34 @@ class ClassGraph { /** Return the class's name, possibly by stripping the leading path */ - private String qualifiedName(Options opt, String r) { - if (!opt.showQualified) { - // Create readable string by stripping leading path - for (;;) { - int dotpos = r.lastIndexOf('.'); - if (dotpos == -1) break; // Work done! - /* - * Change all occurences of - * "p1.p2.myClass" into - * "myClass" - */ - int start = dotpos; - while (start > 0 && Character.isJavaIdentifierPart(r.charAt(start - 1))) - start--; - r = r.substring(0, start) + r.substring(dotpos + 1); + private static String qualifiedName(Options opt, String r) { + // Nothing to do: + if (opt.showQualified && (opt.showQualifiedGenerics || r.indexOf('<') < 0)) + return r; + StringBuilder buf = new StringBuilder(r.length()); + int last = 0, depth = 0; + boolean strip = !opt.showQualified; + for (int i = 0; i < r.length();) { + char c = r.charAt(i++); + // The last condition prevents losing the dot in A.B + if ((c == '.' || c == '$') && strip && last + 1 < i) + last = i; // skip + if (Character.isJavaIdentifierPart(c)) + continue; + // Handle nesting of generics + if (c == '<') { + ++depth; + strip = !opt.showQualifiedGenerics; + } else if (c == '>' && --depth == 0) + strip = !opt.showQualified; + if (last < i) { + buf.append(r, last, i); + last = i; } } - return r; + if (last < r.length()) + buf.append(r, last, r.length()); + return buf.toString(); } /** @@ -263,9 +273,9 @@ class ClassGraph { } /** Print a a basic type t */ - private String type(Options opt, Type t) { + private String type(Options opt, Type t, boolean generics) { String type; - if (opt.showQualified) + if (generics ? opt.showQualifiedGenerics : opt.showQualified) type = t.qualifiedTypeName(); else type = t.typeName(); @@ -281,7 +291,7 @@ class ClassGraph { Type args[] = t.typeArguments(); tp += "<"; for (int i = 0; i < args.length; i++) { - tp += type(opt, args[i]); + tp += type(opt, args[i], true); if (i != args.length - 1) tp += ", "; } @@ -291,11 +301,10 @@ class ClassGraph { /** Annotate an field/argument with its type t */ private String typeAnnotation(Options opt, Type t) { - String ta = ""; if (t.typeName().equals("void")) - return ta; - ta += " : "; - ta += type(opt, t); + return ""; + String ta = " : "; + ta += type(opt, t, false); ta += t.dimension(); return ta; } @@ -506,16 +515,12 @@ class ClassGraph { Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS; String qualifiedName = qualifiedName(opt, r); int startTemplate = qualifiedName.indexOf('<'); - int idx; - if(startTemplate < 0) - idx = qualifiedName.lastIndexOf('.'); - else - idx = qualifiedName.lastIndexOf('.', startTemplate); + int idx = qualifiedName.lastIndexOf('.', startTemplate < 0 ? qualifiedName.length() - 1 : startTemplate); if (opt.showComment) tableLine(Align.LEFT, htmlNewline(escape(c.commentText())), opt, Font.CLASS); else if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { String packageName = qualifiedName.substring(0, idx); - String cn = className.substring(idx + 1); + String cn = qualifiedName.substring(idx + 1); tableLine(Align.CENTER, escape(cn), opt, font); tableLine(Align.CENTER, packageName, opt, Font.PACKAGE); } else { @@ -781,14 +786,16 @@ class ClassGraph { w.print("\t" + info.name + "[label="); externalTableStart(opt, className, classToUrl(className)); innerTableStart(); - int idx = className.lastIndexOf("."); - if(opt.postfixPackage && idx > 0 && idx < (className.length() - 1)) { - String packageName = className.substring(0, idx); - String cn = className.substring(idx + 1); + String qualifiedName = qualifiedName(opt, className); + int startTemplate = qualifiedName.indexOf('<'); + int idx = qualifiedName.lastIndexOf('.', startTemplate < 0 ? qualifiedName.length() - 1 : startTemplate); + if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { + String packageName = qualifiedName.substring(0, idx); + String cn = qualifiedName.substring(idx + 1); tableLine(Align.CENTER, escape(cn), opt, Font.CLASS); tableLine(Align.CENTER, packageName, opt, Font.PACKAGE); } else { - tableLine(Align.CENTER, escape(className), opt, Font.CLASS); + tableLine(Align.CENTER, escape(qualifiedName), opt, Font.CLASS); } innerTableEnd(); externalTableEnd(); diff --git a/src/main/java/org/umlgraph/doclet/Options.java b/src/main/java/org/umlgraph/doclet/Options.java index c9a3dea..4efa0e7 100644 --- a/src/main/java/org/umlgraph/doclet/Options.java +++ b/src/main/java/org/umlgraph/doclet/Options.java @@ -71,6 +71,7 @@ public class Options implements Cloneable, OptionProvider { List hidePatterns; List includePatterns; boolean showQualified; + boolean showQualifiedGenerics; boolean showAttributes; boolean showEnumerations; boolean showEnumConstants; @@ -141,6 +142,7 @@ public class Options implements Cloneable, OptionProvider { Options() { showQualified = false; + showQualifiedGenerics = false; showAttributes = false; showEnumConstants = false; showOperations = false; @@ -303,6 +305,10 @@ public class Options implements Cloneable, OptionProvider { showQualified = true; } else if (opt[0].equals("-!qualify")) { showQualified = false; + } else if(opt[0].equals("-qualifyGenerics")) { + showQualifiedGenerics = true; + } else if (opt[0].equals("-!qualifyGenerics")) { + showQualifiedGenerics = false; } else if(opt[0].equals("-horizontal")) { horizontal = true; } else if (opt[0].equals("-!horizontal")) {