8178043: Support grouping modules in unified javadoc
authorbpatel
Fri, 12 May 2017 18:05:40 -0700 (2017-05-13)
changeset 45157 f5f796453339
parent 45156 001f73134346
child 45158 898cbe31fbda
child 45216 68023c0c9861
8178043: Support grouping modules in unified javadoc Reviewed-by: jjg, ksrini
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractModuleIndexWriter.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexFrameWriter.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModulePackageIndexFrameWriter.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java
langtools/test/jdk/javadoc/doclet/testModules/TestModules.java
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractModuleIndexWriter.java	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractModuleIndexWriter.java	Fri May 12 18:05:40 2017 -0700
@@ -25,6 +25,7 @@
 
 package jdk.javadoc.internal.doclets.formats.html;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
@@ -101,7 +102,7 @@
      * @param tableSummary summary for the table
      * @param body the document tree to which the modules list will be added
      */
-    protected abstract void addModulesList(Map<ModuleElement, Set<PackageElement>> modules, String text,
+    protected abstract void addModulesList(Collection<ModuleElement> modules, String text,
             String tableSummary, Content body);
 
     /**
@@ -173,7 +174,7 @@
      * @param body the document tree to which the index will be added
      */
     protected void addIndex(Content body) {
-        addIndexContents(modules, "doclet.Module_Summary",
+        addIndexContents(configuration.modules, "doclet.Module_Summary",
                 configuration.getText("doclet.Member_Table_Summary",
                 configuration.getText("doclet.Module_Summary"),
                 configuration.getText("doclet.modules")), body);
@@ -201,7 +202,7 @@
      * @param tableSummary summary for the table
      * @param body the document tree to which the index contents will be added
      */
-    protected void addIndexContents(Map<ModuleElement, Set<PackageElement>> modules, String text,
+    protected void addIndexContents(Collection<ModuleElement> modules, String text,
             String tableSummary, Content body) {
         HtmlTree htmlTree = (configuration.allowTag(HtmlTag.NAV))
                 ? HtmlTree.NAV()
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexFrameWriter.java	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexFrameWriter.java	Fri May 12 18:05:40 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 
 package jdk.javadoc.internal.doclets.formats.html;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
@@ -81,7 +82,7 @@
     /**
      * {@inheritDoc}
      */
-    protected void addModulesList(Map<ModuleElement, Set<PackageElement>> modules, String text,
+    protected void addModulesList(Collection<ModuleElement> modules, String text,
             String tableSummary, Content body) {
         Content heading = HtmlTree.HEADING(HtmlConstants.MODULE_HEADING, true,
                 contents.modulesLabel);
@@ -90,7 +91,7 @@
                 : HtmlTree.DIV(HtmlStyle.indexContainer, heading);
         HtmlTree ul = new HtmlTree(HtmlTag.UL);
         ul.setTitle(contents.modulesLabel);
-        for (ModuleElement mdle: modules.keySet()) {
+        for (ModuleElement mdle: modules) {
             ul.addContent(getModuleLink(mdle));
         }
         htmlTree.addContent(ul);
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java	Fri May 12 18:05:40 2017 -0700
@@ -30,7 +30,7 @@
 import javax.lang.model.element.ModuleElement;
 import javax.lang.model.element.PackageElement;
 
-import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
+import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
@@ -56,11 +56,16 @@
 public class ModuleIndexWriter extends AbstractModuleIndexWriter {
 
     /**
-     * Set representing the modules.
+     * Map representing the group of modules as specified on the command line.
      *
      * @see Group
      */
-    private final SortedSet<ModuleElement> modules;
+    private final Map<String, SortedSet<ModuleElement>> groupModuleMap;
+
+    /**
+     * List to store the order groups as specified on the command line.
+     */
+    private final List<String> groupList;
 
     /**
      * HTML tree for main tag.
@@ -74,7 +79,8 @@
      */
     public ModuleIndexWriter(ConfigurationImpl configuration, DocPath filename) {
         super(configuration, filename);
-        modules = configuration.modules;
+        groupModuleMap = configuration.group.groupModules(configuration.modules);
+        groupList = configuration.group.getGroupList();
     }
 
     /**
@@ -96,11 +102,13 @@
      */
     @Override
     protected void addIndex(Content body) {
-        if (modules != null && !modules.isEmpty()) {
-            addIndexContents(configuration.getText("doclet.Modules"),
-                    configuration.getText("doclet.Member_Table_Summary",
-                            configuration.getText("doclet.Module_Summary"),
-                            configuration.getText("doclet.modules")), body);
+        for (String groupname : groupList) {
+            SortedSet<ModuleElement> list = groupModuleMap.get(groupname);
+            if (list != null && !list.isEmpty()) {
+                addIndexContents(list,
+                        groupname, configuration.getText("doclet.Member_Table_Summary",
+                                groupname, configuration.getText("doclet.modules")), body);
+            }
         }
     }
 
@@ -111,7 +119,7 @@
      * @param tableSummary summary for the table
      * @param body the document tree to which the index contents will be added
      */
-    protected void addIndexContents(String title, String tableSummary, Content body) {
+    protected void addIndexContents(Collection<ModuleElement> modules, String title, String tableSummary, Content body) {
         HtmlTree htmltree = (configuration.allowTag(HtmlTag.NAV))
                 ? HtmlTree.NAV()
                 : new HtmlTree(HtmlTag.DIV);
@@ -123,7 +131,7 @@
         }
         htmltree.addContent(ul);
         body.addContent(htmltree);
-        addModulesList(title, tableSummary, body);
+        addModulesList(modules, title, tableSummary, body);
     }
 
     /**
@@ -133,15 +141,17 @@
      * @param tableSummary the summary of the table tag
      * @param body the content tree to which the module list will be added
      */
-    protected void addModulesList(String text, String tableSummary, Content body) {
+    protected void addModulesList(Collection<ModuleElement> modules, String text, String tableSummary, Content body) {
         Content table = (configuration.isOutputHtml5())
                 ? HtmlTree.TABLE(HtmlStyle.overviewSummary, getTableCaption(new RawHtml(text)))
                 : HtmlTree.TABLE(HtmlStyle.overviewSummary, tableSummary, getTableCaption(new RawHtml(text)));
         table.addContent(getSummaryTableHeader(moduleTableHeader, "col"));
         Content tbody = new HtmlTree(HtmlTag.TBODY);
-        addModulesList(tbody);
+        addModulesList(modules, tbody);
         table.addContent(tbody);
-        Content div = HtmlTree.DIV(HtmlStyle.contentContainer, table);
+        Content anchor = getMarkerAnchor(text);
+        Content div = HtmlTree.DIV(HtmlStyle.contentContainer, anchor);
+        div.addContent(table);
         if (configuration.allowTag(HtmlTag.MAIN)) {
             htmlTree.addContent(div);
         } else {
@@ -154,7 +164,7 @@
      *
      * @param tbody the documentation tree to which the list will be added
      */
-    protected void addModulesList(Content tbody) {
+    protected void addModulesList(Collection<ModuleElement> modules, Content tbody) {
         boolean altColor = true;
         for (ModuleElement mdle : modules) {
             if (!mdle.isUnnamed()) {
@@ -260,9 +270,4 @@
     protected void addModulePackagesList(Map<ModuleElement, Set<PackageElement>> modules, String text,
             String tableSummary, Content body, ModuleElement mdle) {
     }
-
-    @Override
-    protected void addModulesList(Map<ModuleElement, Set<PackageElement>> modules, String text,
-            String tableSummary, Content body) {
-    }
 }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModulePackageIndexFrameWriter.java	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModulePackageIndexFrameWriter.java	Fri May 12 18:05:40 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package jdk.javadoc.internal.doclets.formats.html;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -175,7 +176,7 @@
     protected void addOverviewHeader(Content body) {
     }
 
-    protected void addModulesList(Map<ModuleElement, Set<PackageElement>> modules, String text,
+    protected void addModulesList(Collection<ModuleElement> modules, String text,
             String tableSummary, Content body) {
     }
 
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java	Fri May 12 18:05:40 2017 -0700
@@ -29,11 +29,12 @@
 
 import javax.lang.model.element.PackageElement;
 
-import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
+import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
 import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
+import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
@@ -112,8 +113,8 @@
             SortedSet<PackageElement> list = groupPackageMap.get(groupname);
             if (list != null && !list.isEmpty()) {
                 addIndexContents(list,
-                                 groupname, configuration.getText("doclet.Member_Table_Summary",
-                                                                  groupname, configuration.getText("doclet.packages")), body);
+                        groupname, configuration.getText("doclet.Member_Table_Summary",
+                                groupname, configuration.getText("doclet.packages")), body);
             }
         }
     }
@@ -131,7 +132,9 @@
         Content tbody = new HtmlTree(HtmlTag.TBODY);
         addPackagesList(packages, tbody);
         table.addContent(tbody);
-        Content div = HtmlTree.DIV(HtmlStyle.contentContainer, table);
+        Content anchor = getMarkerAnchor(text);
+        Content div = HtmlTree.DIV(HtmlStyle.contentContainer, anchor);
+        div.addContent(table);
         if (configuration.allowTag(HtmlTag.MAIN)) {
             htmlTree.addContent(div);
         } else {
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Fri May 12 18:05:40 2017 -0700
@@ -192,9 +192,9 @@
 doclet.Window_ClassUse_Header=Uses of {0} {1}
 doclet.ClassUse_Title=Uses of {0}
 doclet.navClassUse=Use
-doclet.Error_in_packagelist=Error in using -group option: {0} {1}
-doclet.Groupname_already_used=In -group option, groupname already used: {0}
-doclet.Same_package_name_used=Package name format used twice: {0}
+doclet.Error_in_grouplist=Bad -group option: {0} {1}
+doclet.Groupname_already_used=In -group option, group name already used: {0}
+doclet.Same_element_name_used=Element name or pattern used twice: {0}
 
 # option specifiers
 doclet.usage.d.parameters=\
@@ -274,9 +274,9 @@
     Exclude any doc-files subdirectories with given name
 
 doclet.usage.group.parameters=\
-    <name> <p1>:<p2>..
+    <name> <g1>:<g2>...
 doclet.usage.group.description=\
-    Group specified packages together in overview page
+    Group specified elements together in overview page
 
 doclet.usage.nocomment.description=\
     Suppress description and tags, generate only declarations
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java	Fri May 12 18:05:40 2017 -0700
@@ -699,7 +699,11 @@
         typeElementCatalog = new TypeElementCatalog(includedTypeElements, this);
         initTagletManager(customTagStrs);
         groups.stream().forEach((grp) -> {
-            group.checkPackageGroups(grp.value1, grp.value2);
+            if (showModules) {
+                group.checkModuleGroups(grp.value1, grp.value2);
+            } else {
+                group.checkPackageGroups(grp.value1, grp.value2);
+            }
         });
     }
 
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Fri May 12 18:05:40 2017 -0700
@@ -49,6 +49,7 @@
 doclet.Packages=Packages
 doclet.Modules=Modules
 doclet.Other_Packages=Other Packages
+doclet.Other_Modules=Other Modules
 doclet.Notice_taglet_registered=Registered Taglet {0} ...
 doclet.Notice_taglet_unseen=Note: Custom tags that were not seen: {0}
 doclet.Notice_taglet_overriden=Note: Custom tags that override standard tags: {0}
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java	Fri May 12 18:05:40 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@
 
 import java.util.*;
 
-import javax.lang.model.element.Element;
+import javax.lang.model.element.ModuleElement;
 import javax.lang.model.element.PackageElement;
 
 import jdk.javadoc.internal.doclets.toolkit.Configuration;
@@ -35,7 +35,7 @@
 
 
 /**
- * Process and manage grouping of packages, as specified by "-group" option on
+ * Process and manage grouping of elements, as specified by "-group" option on
  * the command line.
  * <p>
  * For example, if user has used -group option as
@@ -79,10 +79,10 @@
     private List<String> groupList = new ArrayList<>();
 
     /**
-     * Map of non-regular expressions(possible package names) with the
+     * Map of non-regular expressions(possible package or module names) with the
      * corresponding group name.
      */
-    private Map<String,String> pkgNameGroupMap = new HashMap<>();
+    private Map<String,String> elementNameGroupMap = new HashMap<>();
 
     /**
      * The global configuration information for this run.
@@ -107,11 +107,57 @@
     }
 
     /**
+     * Depending upon the format of the module name provided in the "-group"
+     * option, generate two separate maps. There will be a map for mapping
+     * regular expression(only meta character allowed is '*' and that is at the
+     * end of the regular expression) on to the group name. And another map
+     * for mapping (possible) module names(if the name format doesn't contain
+     * meta character '*', then it is assumed to be a module name) on to the
+     * group name. This will also sort all the regular expressions found in the
+     * reverse order of their lengths, i.e. longest regular expression will be
+     * first in the sorted list.
+     *
+     * @param groupname       The name of the group from -group option.
+     * @param moduleNameFormList List of the module name formats.
+     */
+    public boolean checkModuleGroups(String groupname, String moduleNameFormList) {
+        String[] mdlPatterns = moduleNameFormList.split(":");
+        if (groupList.contains(groupname)) {
+            initMessages();
+            messages.warning("doclet.Groupname_already_used", groupname);
+            return false;
+        }
+        groupList.add(groupname);
+        for (String mdlPattern : mdlPatterns) {
+            if (mdlPattern.length() == 0) {
+                initMessages();
+                messages.warning("doclet.Error_in_grouplist", groupname, moduleNameFormList);
+                return false;
+            }
+            if (mdlPattern.endsWith("*")) {
+                mdlPattern = mdlPattern.substring(0, mdlPattern.length() - 1);
+                if (foundGroupFormat(regExpGroupMap, mdlPattern)) {
+                    return false;
+                }
+                regExpGroupMap.put(mdlPattern, groupname);
+                sortedRegExpList.add(mdlPattern);
+            } else {
+                if (foundGroupFormat(elementNameGroupMap, mdlPattern)) {
+                    return false;
+                }
+                elementNameGroupMap.put(mdlPattern, groupname);
+            }
+        }
+        Collections.sort(sortedRegExpList, new MapKeyComparator());
+        return true;
+    }
+
+    /**
      * Depending upon the format of the package name provided in the "-group"
      * option, generate two separate maps. There will be a map for mapping
      * regular expression(only meta character allowed is '*' and that is at the
      * end of the regular expression) on to the group name. And another map
-     * for mapping (possible) package names(if the name format doesen't contain
+     * for mapping (possible) package names(if the name format doesn't contain
      * meta character '*', then it is assumed to be a package name) on to the
      * group name. This will also sort all the regular expressions found in the
      * reverse order of their lengths, i.e. longest regular expression will be
@@ -121,32 +167,31 @@
      * @param pkgNameFormList List of the package name formats.
      */
     public boolean checkPackageGroups(String groupname, String pkgNameFormList) {
-        StringTokenizer strtok = new StringTokenizer(pkgNameFormList, ":");
+        String[] pkgPatterns = pkgNameFormList.split(":");
         if (groupList.contains(groupname)) {
             initMessages();
             messages.warning("doclet.Groupname_already_used", groupname);
             return false;
         }
         groupList.add(groupname);
-        while (strtok.hasMoreTokens()) {
-            String id = strtok.nextToken();
-            if (id.length() == 0) {
+        for (String pkgPattern : pkgPatterns) {
+            if (pkgPattern.length() == 0) {
                 initMessages();
-                messages.warning("doclet.Error_in_packagelist", groupname, pkgNameFormList);
+                messages.warning("doclet.Error_in_grouplist", groupname, pkgNameFormList);
                 return false;
             }
-            if (id.endsWith("*")) {
-                id = id.substring(0, id.length() - 1);
-                if (foundGroupFormat(regExpGroupMap, id)) {
+            if (pkgPattern.endsWith("*")) {
+                pkgPattern = pkgPattern.substring(0, pkgPattern.length() - 1);
+                if (foundGroupFormat(regExpGroupMap, pkgPattern)) {
                     return false;
                 }
-                regExpGroupMap.put(id, groupname);
-                sortedRegExpList.add(id);
+                regExpGroupMap.put(pkgPattern, groupname);
+                sortedRegExpList.add(pkgPattern);
             } else {
-                if (foundGroupFormat(pkgNameGroupMap, id)) {
+                if (foundGroupFormat(elementNameGroupMap, pkgPattern)) {
                     return false;
                 }
-                pkgNameGroupMap.put(id, groupname);
+                elementNameGroupMap.put(pkgPattern, groupname);
             }
         }
         Collections.sort(sortedRegExpList, new MapKeyComparator());
@@ -162,39 +207,82 @@
     }
 
     /**
-     * Search if the given map has given the package format.
+     * Search if the given map has the given element format.
      *
      * @param map Map to be searched.
-     * @param pkgFormat The pacakge format to search.
+     * @param elementFormat The format to search.
      *
-     * @return true if package name format found in the map, else false.
+     * @return true if element name format found in the map, else false.
      */
-    boolean foundGroupFormat(Map<String,?> map, String pkgFormat) {
-        if (map.containsKey(pkgFormat)) {
+    boolean foundGroupFormat(Map<String,?> map, String elementFormat) {
+        if (map.containsKey(elementFormat)) {
             initMessages();
-            messages.error("doclet.Same_package_name_used", pkgFormat);
+            messages.error("doclet.Same_element_name_used", elementFormat);
             return true;
         }
         return false;
     }
 
     /**
+     * Group the modules according the grouping information provided on the
+     * command line. Given a list of modules, search each module name in
+     * regular expression map as well as module name map to get the
+     * corresponding group name. Create another map with mapping of group name
+     * to the module list, which will fall under the specified group. If any
+     * module doesn't belong to any specified group on the command line, then
+     * a new group named "Other Modules" will be created for it. If there are
+     * no groups found, in other words if "-group" option is not at all used,
+     * then all the modules will be grouped under group "Modules".
+     *
+     * @param modules Specified modules.
+     * @return map of group names and set of module elements.
+     */
+    public Map<String, SortedSet<ModuleElement>> groupModules(Set<ModuleElement> modules) {
+        Map<String, SortedSet<ModuleElement>> groupModuleMap = new HashMap<>();
+        String defaultGroupName =
+            (elementNameGroupMap.isEmpty() && regExpGroupMap.isEmpty())?
+                configuration.getResources().getText("doclet.Modules") :
+                configuration.getResources().getText("doclet.Other_Modules");
+        // if the user has not used the default group name, add it
+        if (!groupList.contains(defaultGroupName)) {
+            groupList.add(defaultGroupName);
+        }
+        for (ModuleElement mdl : modules) {
+            String moduleName = mdl.isUnnamed() ? null : mdl.getQualifiedName().toString();
+            String groupName = mdl.isUnnamed() ? null : elementNameGroupMap.get(moduleName);
+            // if this module is not explicitly assigned to a group,
+            // try matching it to group specified by regular expression
+            if (groupName == null) {
+                groupName = regExpGroupName(moduleName);
+            }
+            // if it is in neither group map, put it in the default
+            // group
+            if (groupName == null) {
+                groupName = defaultGroupName;
+            }
+            getModuleList(groupModuleMap, groupName).add(mdl);
+        }
+        return groupModuleMap;
+    }
+
+    /**
      * Group the packages according the grouping information provided on the
      * command line. Given a list of packages, search each package name in
      * regular expression map as well as package name map to get the
      * corresponding group name. Create another map with mapping of group name
      * to the package list, which will fall under the specified group. If any
-     * package doesen't belong to any specified group on the comamnd line, then
+     * package doesn't belong to any specified group on the command line, then
      * a new group named "Other Packages" will be created for it. If there are
      * no groups found, in other words if "-group" option is not at all used,
      * then all the packages will be grouped under group "Packages".
      *
      * @param packages Packages specified on the command line.
+     * @return map of group names and set of package elements
      */
     public Map<String, SortedSet<PackageElement>> groupPackages(Set<PackageElement> packages) {
         Map<String, SortedSet<PackageElement>> groupPackageMap = new HashMap<>();
         String defaultGroupName =
-            (pkgNameGroupMap.isEmpty() && regExpGroupMap.isEmpty())?
+            (elementNameGroupMap.isEmpty() && regExpGroupMap.isEmpty())?
                 configuration.getResources().getText("doclet.Packages") :
                 configuration.getResources().getText("doclet.Other_Packages");
         // if the user has not used the default group name, add it
@@ -203,7 +291,7 @@
         }
         for (PackageElement pkg : packages) {
             String pkgName = pkg.isUnnamed() ? null : configuration.utils.getPackageName(pkg);
-            String groupName = pkg.isUnnamed() ? null : pkgNameGroupMap.get(pkgName);
+            String groupName = pkg.isUnnamed() ? null : elementNameGroupMap.get(pkgName);
             // if this package is not explicitly assigned to a group,
             // try matching it to group specified by regular expression
             if (groupName == null) {
@@ -220,15 +308,15 @@
     }
 
     /**
-     * Search for package name in the sorted regular expression
+     * Search for element name in the sorted regular expression
      * list, if found return the group name.  If not, return null.
      *
-     * @param pkgName Name of package to be found in the regular
+     * @param elementName Name of element to be found in the regular
      * expression list.
      */
-    String regExpGroupName(String pkgName) {
+    String regExpGroupName(String elementName) {
         for (String regexp : sortedRegExpList) {
-            if (pkgName.startsWith(regexp)) {
+            if (elementName.startsWith(regexp)) {
                 return regExpGroupMap.get(regexp);
             }
         }
@@ -239,7 +327,7 @@
      * For the given group name, return the package list, on which it is mapped.
      * Create a new list, if not found.
      *
-     * @param map Map to be searched for gorup name.
+     * @param map Map to be searched for group name.
      * @param groupname Group name to search.
      */
     SortedSet<PackageElement> getPkgList(Map<String, SortedSet<PackageElement>> map,
@@ -248,6 +336,18 @@
     }
 
     /**
+     * For the given group name, return the module list, on which it is mapped.
+     * Create a new list, if not found.
+     *
+     * @param map Map to be searched for group name.
+     * @param groupname Group name to search.
+     */
+    SortedSet<ModuleElement> getModuleList(Map<String, SortedSet<ModuleElement>> map,
+            String groupname) {
+        return map.computeIfAbsent(groupname, g -> new TreeSet<>(configuration.utils.makeModuleComparator()));
+    }
+
+    /**
      * Return the list of groups, in the same order as specified
      * on the command line.
      */
--- a/langtools/test/jdk/javadoc/doclet/testModules/TestModules.java	Fri May 12 06:42:37 2017 +0200
+++ b/langtools/test/jdk/javadoc/doclet/testModules/TestModules.java	Fri May 12 18:05:40 2017 -0700
@@ -25,6 +25,7 @@
  * @test
  * @bug 8154119 8154262 8156077 8157987 8154261 8154817 8135291 8155995 8162363
  *      8168766 8168688 8162674 8160196 8175799 8174974 8176778 8177562 8175218 8175823 8166306
+ *      8178043
  * @summary Test modules support in javadoc.
  * @author bpatel
  * @library ../lib
@@ -326,6 +327,54 @@
         checkAllModulesLink(false);
     }
 
+    /**
+     * Test -group option for modules. The overview-summary.html page should group the modules accordingly.
+     */
+    @Test
+    void testGroupOption() {
+        javadoc("-d", "out-group", "--show-module-contents=all",
+                "-tag", "regular:a:Regular Tag:",
+                "-tag", "moduletag:s:Module Tag:",
+                "--module-source-path", testSrc,
+                "-group", "Module Group A", "moduleA*",
+                "-group", "Module Group B & C", "moduleB*:moduleC*",
+                "-group", "Java SE Modules", "java*",
+                "--module", "moduleA,moduleB,moduleC,moduletags",
+                "moduleA/concealedpkgmdlA", "testpkgmdlA", "testpkg2mdlB", "testpkgmdlB", "testpkgmdlC",
+                "testpkgmdltags");
+        checkExit(Exit.OK);
+        checkGroupOption();
+    }
+
+    /**
+     * Test -group option for unnamed modules. The overview-summary.html page should group the packages accordingly.
+     */
+    @Test
+    void testUnnamedModuleGroupOption() {
+        javadoc("-d", "out-groupnomodule", "-use",
+                "-overview", testSrc("overview.html"),
+                "-sourcepath", testSrc,
+                "-group", "Package Group 0", "testpkgnomodule",
+                "-group", "Package Group 1", "testpkgnomodule1",
+                "testpkgnomodule", "testpkgnomodule1");
+        checkExit(Exit.OK);
+        checkUnnamedModuleGroupOption();
+    }
+
+    /**
+     * Test -group option for a single module.
+     */
+    @Test
+    void testGroupOptionSingleModule() {
+        javadoc("-d", "out-groupsinglemodule", "-use",
+                "--module-source-path", testSrc,
+                "-group", "Module Group B", "moduleB*",
+                "--module", "moduleB",
+                "testpkg2mdlB", "testpkgmdlB");
+        checkExit(Exit.OK);
+        //checkOverviewSummaryPackages();
+    }
+
     void checkDescription(boolean found) {
         checkOutput("moduleA-summary.html", found,
                 "<!-- ============ MODULE DESCRIPTION =========== -->\n"
@@ -346,8 +395,10 @@
                 + "<div class=\"contentContainer\">\n"
                 + "<div class=\"block\">The overview summary page header.</div>\n"
                 + "</div>\n"
-                + "<div class=\"contentContainer\">\n"
-                + "<table class=\"overviewSummary\" summary=\"Module Summary table, listing modules, and an explanation\">\n"
+                + "<div class=\"contentContainer\"><a name=\"Modules\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<table class=\"overviewSummary\" summary=\"Modules table, listing modules, and an explanation\">\n"
                 + "<caption><span>Modules</span><span class=\"tabEnd\">&nbsp;</span></caption>");
         checkOutput("overview-summary.html", false,
                 "</table>\n"
@@ -355,8 +406,10 @@
                 + "<div class=\"contentContainer\">\n"
                 + "<div class=\"block\">The overview summary page header.</div>\n"
                 + "</div>\n"
-                + "<div class=\"contentContainer\">\n"
-                + "<table class=\"overviewSummary\" summary=\"Module Summary table, listing modules, and an explanation\">\n"
+                + "<div class=\"contentContainer\"><a name=\"Modules\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<table class=\"overviewSummary\" summary=\"Modules table, listing modules, and an explanation\">\n"
                 + "<caption><span>Modules</span><span class=\"tabEnd\">&nbsp;</span></caption>");
     }
 
@@ -405,7 +458,9 @@
                 + "<div class=\"contentContainer\">\n"
                 + "<div class=\"block\">The overview summary page header.</div>\n"
                 + "</div>\n"
-                + "<div class=\"contentContainer\">\n"
+                + "<div class=\"contentContainer\"><a id=\"Modules\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
                 + "<table class=\"overviewSummary\">\n"
                 + "<caption><span>Modules</span><span class=\"tabEnd\">&nbsp;</span></caption>");
         checkOutput("overview-summary.html", false,
@@ -416,7 +471,9 @@
                 + "<div class=\"contentContainer\">\n"
                 + "<div class=\"block\">The overview summary page header.</div>\n"
                 + "</div>\n"
-                + "<div class=\"contentContainer\">\n"
+                + "<div class=\"contentContainer\"><a id=\"Modules\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
                 + "<table class=\"overviewSummary\">\n"
                 + "<caption><span>Modules</span><span class=\"tabEnd\">&nbsp;</span></caption>");
     }
@@ -495,7 +552,7 @@
 
     void checkOverviewSummaryModules() {
         checkOutput("overview-summary.html", true,
-                "<table class=\"overviewSummary\" summary=\"Module Summary table, listing modules, and an explanation\">\n"
+                "<table class=\"overviewSummary\" summary=\"Modules table, listing modules, and an explanation\">\n"
                 + "<caption><span>Modules</span><span class=\"tabEnd\">&nbsp;</span></caption>\n"
                 + "<tr>\n"
                 + "<th class=\"colFirst\" scope=\"col\">Module</th>\n"
@@ -512,7 +569,7 @@
 
     void checkOverviewSummaryPackages() {
         checkOutput("overview-summary.html", false,
-                "<table class=\"overviewSummary\" summary=\"Module Summary table, listing modules, and an explanation\">\n"
+                "<table class=\"overviewSummary\" summary=\"Modules table, listing modules, and an explanation\">\n"
                 + "<caption><span>Modules</span><span class=\"tabEnd\">&nbsp;</span></caption>\n"
                 + "<tr>\n"
                 + "<th class=\"colFirst\" scope=\"col\">Module</th>\n"
@@ -523,7 +580,9 @@
                 + "<div class=\"contentContainer\">\n"
                 + "<div class=\"block\">The overview summary page header.</div>\n"
                 + "</div>\n"
-                + "<div class=\"contentContainer\">\n"
+                + "<div class=\"contentContainer\"><a name=\"Packages\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
                 + "<table class=\"overviewSummary\" summary=\"Packages table, listing packages, and an explanation\">\n"
                 + "<caption><span>Packages</span><span class=\"tabEnd\">&nbsp;</span></caption>");
         checkOutput("overview-summary.html", true,
@@ -537,7 +596,9 @@
                 + "<div class=\"contentContainer\">\n"
                 + "<div class=\"block\">The overview summary page header.</div>\n"
                 + "</div>\n"
-                + "<div class=\"contentContainer\">\n"
+                + "<div class=\"contentContainer\"><a name=\"Packages\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
                 + "<table class=\"overviewSummary\" summary=\"Packages table, listing packages, and an explanation\">\n"
                 + "<caption><span>Packages</span><span class=\"tabEnd\">&nbsp;</span></caption>");
     }
@@ -574,7 +635,9 @@
                 + "<div class=\"contentContainer\">\n"
                 + "<div class=\"block\">The overview summary page header.</div>\n"
                 + "</div>\n"
-                + "<div class=\"contentContainer\">\n"
+                + "<div class=\"contentContainer\"><a id=\"Packages\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
                 + "<table class=\"overviewSummary\">\n"
                 + "<caption><span>Packages</span><span class=\"tabEnd\">&nbsp;</span></caption>");
         checkOutput("overview-summary.html", true,
@@ -591,7 +654,9 @@
                 + "<div class=\"contentContainer\">\n"
                 + "<div class=\"block\">The overview summary page header.</div>\n"
                 + "</div>\n"
-                + "<div class=\"contentContainer\">\n"
+                + "<div class=\"contentContainer\"><a id=\"Packages\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
                 + "<table class=\"overviewSummary\">\n"
                 + "<caption><span>Packages</span><span class=\"tabEnd\">&nbsp;</span></caption>");
     }
@@ -974,4 +1039,54 @@
                 + "</a>",
                 "<caption><span>Concealed</span><span class=\"tabEnd\">&nbsp;</span></caption>");
     }
+
+    void checkGroupOption() {
+        checkOutput("overview-summary.html", true,
+                "<div class=\"contentContainer\"><a name=\"ModuleGroupA\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<table class=\"overviewSummary\" summary=\"Module Group A table, listing modules, and an explanation\">\n"
+                + "<caption><span>Module Group A</span><span class=\"tabEnd\">&nbsp;</span></caption>",
+                "<div class=\"contentContainer\"><a name=\"ModuleGroupB&amp;C\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<table class=\"overviewSummary\" summary=\"Module Group B &amp; C table, listing modules, and an explanation\">\n"
+                + "<caption><span>Module Group B & C</span><span class=\"tabEnd\">&nbsp;</span></caption>",
+                "<div class=\"contentContainer\"><a name=\"OtherModules\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<table class=\"overviewSummary\" summary=\"Other Modules table, listing modules, and an explanation\">\n"
+                + "<caption><span>Other Modules</span><span class=\"tabEnd\">&nbsp;</span></caption>");
+        checkOutput("overview-summary.html", false,
+                "<table class=\"overviewSummary\" summary=\"Modules table, listing modules, and an explanation\">\n"
+                + "<caption><span>Modules</span><span class=\"tabEnd\">&nbsp;</span></caption>",
+                "Java SE Modules");
+    }
+
+    void checkUnnamedModuleGroupOption() {
+        checkOutput("overview-summary.html", true,
+                "<div class=\"contentContainer\"><a name=\"PackageGroup0\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<table class=\"overviewSummary\" summary=\"Package Group 0 table, listing packages, and an explanation\">\n"
+                + "<caption><span>Package Group 0</span><span class=\"tabEnd\">&nbsp;</span></caption>\n"
+                + "<tr>",
+                "<div class=\"contentContainer\"><a name=\"PackageGroup1\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<table class=\"overviewSummary\" summary=\"Package Group 1 table, listing packages, and an explanation\">\n"
+                + "<caption><span>Package Group 1</span><span class=\"tabEnd\">&nbsp;</span></caption>");
+    }
+
+    void checkGroupOptionSingleModule() {
+        checkOutput("overview-summary.html", true,
+                "<div class=\"contentContainer\"><a name=\"ModuleGroupB\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<table class=\"overviewSummary\" summary=\"Module Group B table, listing modules, and an explanation\">\n"
+                + "<caption><span>Module Group B</span><span class=\"tabEnd\">&nbsp;</span></caption>");
+        checkOutput("overview-summary.html", false,
+                "<table class=\"overviewSummary\" summary=\"Modules table, listing modules, and an explanation\">\n"
+                + "<caption><span>Modules</span><span class=\"tabEnd\">&nbsp;</span></caption>");
+    }
 }