# groovydoc, the Groovy & Java documentation generator

version 6.0.0-beta-2

GroovyDoc generates API documentation from your source code. It plays the role the Javadoc tool plays in the Java ecosystem, but accepts both `.groovy` and `.java` sources and adds conveniences suited to Groovy.

The documentation generator is driven from the command line, from Apache Ant, or from build-tool wrappers such as the GMavenPlus Maven plugin. The sections below cover the everyday authoring and invocation patterns; Advanced topics collects the lesser-used features.

## 1. Writing doc comments

GroovyDoc recognises three forms of doc comment, all of which can coexist in the same source file:

- Traditional Javadoc `/*` …​ `/` block comments.

- JEP 467-style Markdown comments using runs of `///` line prefixes.

- Runtime-retained Javadoc `/*@` …​ `/` block comments, whose content is reflectable at runtime via the `@Groovydoc` annotation (see Runtime Groovydoc).

### 1.1. Comment forms

#### 1.1.1. Traditional Javadoc

    /**
     * Summary sentence. More description.
     *
     * @param name the subject to greet
     * @return the greeting
     */
    String greet(String name) { "Hello, $name" }

Leading `*` prefixes on each line are stripped. The first sentence (up to the first period followed by whitespace) is used as the short summary on index/package pages.

#### 1.1.2. JEP 467 Markdown (`///`)

Each line of the run starts with `///`. Inside the comment, CommonMark Markdown is supported — headings, bullets, emphasis, links, and fenced code blocks all render as you would expect:

    /// # Greet
    ///
    /// Returns a friendly greeting. Supports the usual inline tags:
    /// {@link String} and {@code greet} still work.
    ///
    /// ```groovy
    /// assert greeter.greet('world') == 'Hello, world'
    /// ```
    ///
    /// @param name the subject to greet
    /// @return the greeting
    String greet(String name) { "Hello, $name" }

Markdown is rendered through CommonMark. Headings are shifted down by two levels (so `#` becomes `<h3>`) to fit under the page’s existing title and section banners. Inline Javadoc tags like `{@link …​}` are preserved inside Markdown bodies. `{@link …​}` tokens appearing inside fenced code blocks are left literal — the fence is treated as code, not documentation.

For the full Markdown syntax and semantics, see JEP 467 and CommonMark.

#### 1.1.3. Runtime Groovydoc (`/**@`)

If the comment opens with `/@` instead of `/`, Groovy’s parser can retain the raw comment text as a `groovy.lang.@Groovydoc` annotation on the enclosing class/method/field. Enable the feature through the compiler option `runtimeGroovydoc`; see Runtime Groovydoc.

### 1.2. Block tags

Block tags appear at the end of the comment, one per paragraph, leading with `@`. Common tags:

Tag | Purpose
--- | ---
`@param <name> <description>` | Describes a parameter. Use `@param <T>` for a type parameter.
`@return <description>` | Describes the return value.
`@throws <exception> <description>`, `@exception <exception> <description>` | Describes an exception the method might throw.
`@since <version>` | Indicates when the feature was added.
`@author <name>` | Author of the element. Rendered only when `-author` is enabled.
`@version <text>` | Version information.
`@deprecated <explanation>` | Marks the element as deprecated; recommend a replacement.
`@see <reference>` | Adds a "See Also" entry. The reference is a class or member.
`@apiNote <text>` | Guidance intended for callers of the API.
`@implSpec <text>` | Contract that overriders must preserve.
`@implNote <text>` | Non-contract implementation detail.

Multiple `@param`, `@throws`, and `@see` entries are collated under a single heading in the rendered output.

### 1.3. Inline tags

Inline tags appear within a comment body and are expanded in place.

Tag | Purpose
--- | ---
`{@link <reference>}` | Cross-reference to a class or member. Produces a hyperlink.
`{@code <text>}` | Renders the text in a monospaced code style. HTML metacharacters are escaped. The body is brace-balanced with a linear scan (GROOVY-12095), so nested braces — Groovy closures, map/type literals, etc. — are kept intact, including inside `<pre>{@code …​}</pre>` examples. Braces inside ordinary quoted string/character literals (e.g. `System.out.println(" } ")`), multi-line text blocks (`"""…​"""` / `'''…​'''`), `/* …​ */` block comments, and `// …​` line comments (e.g. `// }`) are ignored while matching.
`{@literal <text>}` | Renders the text verbatim without code styling. Same brace-balanced body rules as `{@code}`.
`{@value #FIELD}`, `{@value Class#FIELD}` | Inlines the value of a compile-time-constant field. Same-class references and cross-class references both work. On a constant field’s own comment, bare `{@value}` inlines that field’s own value.
`{@inheritDoc}` | Inherits the parent class’s/interface’s corresponding doc.
`{@snippet …​}` | Embeds a code snippet. See {@snippet} under advanced topics.
`{@docRoot}` | Path to the root of the generated documentation. Useful when writing a relative link that must work from pages at any depth.

## 2. Running groovydoc

### 2.1. The `groovydoc` command line tool

The `groovydoc` command line invocation:

    groovydoc [options] [packagenames] [sourcefiles]

Most commonly-used options:

Short version | Long version | Description
--- | --- | ---
-d | --destdir <dir> | Destination directory for output files
-sourcepath <pathlist> |  | Directories to find source files (platform path separator)
-classpath, -cp | --classpath | Where to find class files (must be first argument)
-public |  | Show only public classes and members
-protected |  | Show protected/public classes and members (default)
-package |  | Show package/protected/public classes and members
-private |  | Show all classes and members
-charset <charset> |  | Charset for cross-platform viewing of generated HTML
-fileEncoding <charset> |  | Charset for generated documentation files
-doctitle <html> |  | Title for the overview page
-windowtitle <text> |  | Browser window title
-header <html> |  | Include header text on each page
-footer <html> |  | Include footer text on each page
-overview <file> |  | Read overview documentation from HTML file
-exclude <pkglist> |  | Exclude listed packages (colon-separated)
-noscripts |  | Don’t process Groovy Scripts
-author |  | Include `@author` paragraphs
-stylesheetfile <path> |  | Replace the default stylesheet with a supplied one
-addStylesheet <path> |  | Add a stylesheet alongside the default (can be given multiple times with comma-separated values)
-theme <mode> |  | Theme: `auto` (default, follow OS), `light`, or `dark`
-syntaxHighlighter <name> |  | Client-side syntax highlighter: `prism` (bundled) or `none` (default)
-preLanguage <lang> |  | Default Prism language id for unattributed `<pre>` blocks in doc comments. When set, a post-render pass wraps their bodies so Prism highlights them (see Highlighting plain `<pre>` blocks).
-showInternal |  | Include members annotated with `groovy.transform.@Internal` (hidden by default)
-noindex |  | Skip generating the alphabetical index page
-nodeprecatedlist |  | Skip generating the deprecated list
-nohelp |  | Skip generating the help page
-notimestamp |  | Don’t include generation timestamp in output
-noversionstamp |  | Don’t include Groovy version in output
-nomainforscripts |  | Don’t include the implicit `public static void main` method for scripts
-help, -h | --help | Display help message
-verbose, -quiet, --debug |  | Adjust logging verbosity
| --version | Display the version
-javaVersion <version> |  | Language version for parsed Java files (e.g. `JAVA_17`)

### 2.2. The `groovydoc` Ant task

The Ant task exposes the same feature set. You will need the task defined before invoking it:

    <taskdef name         = "groovydoc"
             classname    = "org.codehaus.groovy.ant.Groovydoc"
             classpathref = "my.classpath"/>

where my.classpath references the Groovy distribution jars (`groovy-VERSION.jar`, `groovy-ant-VERSION.jar`, `groovy-groovydoc-VERSION.jar`, plus any modules and transitive dependencies you use).

#### 2.2.1. `<groovydoc>` attributes

Attribute | Description | Required
--- | --- | ---
destdir | Location to write generated documentation to. | Yes
sourcepath | Directories to scan for source files. | No
packagenames | Comma-separated list of package specs (wildcards allowed, e.g. `com.foo.**`). | No
excludePackageNames | Comma-separated (or colon-separated) list of package specs to exclude. | No
windowtitle | Browser window title. | No
doctitle | HTML shown at the top of the overview page. | No
header, footer | HTML shown at the top/bottom of every page. | No
overview | HTML file read as the overview page. | No
charset | Charset for cross-platform viewing of generated HTML. | No
fileEncoding | Charset used when writing the generated files. | No
author | Include `@author` paragraphs. Defaults to `true`. | No
processScripts | Process Groovy scripts. Defaults to `true`; set to `false` to mirror the CLI `-noscripts` flag. | No
includeMainForScripts | Include the synthetic `public static void main` method when documenting scripts. Defaults to `true`; set to `false` to mirror the CLI `-nomainforscripts` flag. | No
stylesheetFile | Replace the default stylesheet with a supplied one. | No
private | Show all classes and members (including private ones). | No
public, protected, package | Set individually to control the visibility scope; equivalent to the CLI `-public`, `-protected`, `-package` flags. | No
access | Alternative to the boolean scope attributes above. Accepts `public`, `protected`, `package`, or `private`. | No
javaVersion | Language version for Java source files. | No
extensions | Colon-separated source extensions (default `.java:.groovy:.gv:.gvy:.gsh`). | No
use | Legacy Javadoc option accepted for parity. Has no effect on groovydoc output. | No
showInternal | Include members annotated with `groovy.transform.@Internal`. | No
noIndex, noDeprecatedList, noHelp | Suppress the matching auxiliary page. | No
syntaxHighlighter | `prism` or `none` (default). | No
theme | Theme lock: `auto` (default), `light`, or `dark`. | No
preLanguage | Default Prism language for unattributed `<pre>` blocks in doc comments. See Highlighting plain `<pre>` blocks. | No
noTimestamp, noVersionStamp | Omit the matching stamp from output. | No

#### 2.2.2. `<groovydoc>` nested elements

##### `<link>`

Create cross-references to external Javadoc/groovydoc output. See Linking to external APIs.

Attribute | Description | Required
--- | --- | ---
packages | Comma-separated list of package prefixes. | Yes
href | Base URL of the external site. | Yes
module | JPMS module name; inserted as a path segment for modular Javadoc layouts. | No

##### `<addStylesheet>`

Add an extra stylesheet alongside the default. Repeat the element to add multiple stylesheets.

Attribute | Description | Required
--- | --- | ---
file | Path to the stylesheet file. | Yes

#### 2.2.3. Ant task example

    <taskdef name           = "groovydoc"
             classname      = "org.codehaus.groovy.ant.Groovydoc"
             classpathref   = "path_to_groovy_all"/>

    <groovydoc destdir      = "${docsDirectory}/gapi"
               sourcepath   = "${mainSourceDirectory}"
               packagenames = "**.*"
               use          = "true"
               windowtitle  = "${title}"
               doctitle     = "${title}"
               header       = "${title}"
               footer       = "${docFooter}"
               overview     = "src/main/overview.html"
               private      = "false">
            <link packages="java.,org.xml.,javax.,org.xml." href="https://docs.oracle.com/javase/8/docs/api/"/>
            <link packages="org.apache.tools.ant."          href="https://docs.groovy-lang.org/docs/ant/api/"/>
            <link packages="org.junit.,junit.framework."    href="https://junit.org/junit4/javadoc/latest/"/>
            <link packages="groovy.,org.codehaus.groovy."   href="https://docs.groovy-lang.org/latest/html/api/"/>
    </groovydoc>

Running the task from Groovy via `AntBuilder` works the same way.

## 3. Linking to external APIs

`<link>` (Ant) and `-link` (CLI) let cross-references resolve to an external Javadoc/groovydoc site. Packages are matched by the `packages` attribute as a comma-separated list of prefixes; when a documented reference matches one of the prefixes the link goes to the configured `href` base.

The `module` attribute on `<link>` supports modular Javadoc layouts, where an external site places each JPMS module’s docs under a module-named subdirectory. With `module="java.base"` and `href="https://docs.oracle.com/en/java/javase/17/docs/api/"`, a link to `java.lang.Object` resolves to `https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html`.

## 4. Customising the output

### 4.1. Stylesheets

Two mechanisms cover most customisation needs:

- `-stylesheetfile <path>` (CLI) / `stylesheetFile="…​"` (Ant) — replaces the default stylesheet. The supplied file is copied verbatim over `stylesheet.css` in the output. If the file has no dark-mode support of its own, the generated docs will be light-only regardless of the theme settings below.

- `-addStylesheet <path>` (CLI) / `<addStylesheet file="…​"/>` (Ant) — adds an extra stylesheet alongside the default. The default is still loaded and supplies the baseline look; the added stylesheet layers on top. This is the safer choice for theme tweaks.

Author stylesheets can opt into the baseline palette by referencing the default stylesheet’s CSS custom properties (`--fg`, `--bg`, `--link`, `--bg-panel`, `--border`, `--caption-bg`, and related semantic tokens). Doing so makes the added stylesheet automatically dark-mode aware.

### 4.2. Theme

`-theme <mode>` / `theme="…​"` controls the palette strategy:

- `auto` (default) — the generated stylesheet emits a `prefers-color-scheme` media query. Each reader’s browser picks the light or dark palette that matches their OS preference. Syntax highlighting (if enabled) switches Prism themes in sync.

- `light` — locks the output to the light palette regardless of OS preference.

- `dark` — locks the output to the dark palette regardless of OS preference.

`auto` is the right choice for public-facing docs that should adapt to the reader. `light` and `dark` are useful for branded sites where a consistent look matters more than honouring OS preference.

### 4.3. Syntax highlighting

`-syntaxHighlighter prism` / `syntaxHighlighter="prism"` enables client-side syntax highlighting for `{@snippet}` blocks and Markdown fenced code blocks. Prism.js is bundled and covers at minimum Groovy, Java, XML, JSON, YAML, TOML, SQL, CSV, Markdown, JavaScript, and regex. The light/dark theme selection tracks the theme setting automatically. The default is `none` (no highlighting); code blocks are rendered as plain preformatted text.

### 4.4. Highlighting plain `<pre>` blocks

Doc comments written before the `{@snippet}` era often use bare `<pre>…​</pre>` wrappers for code samples. Prism only walks `<code>` descendants of language-classed elements, so a bare `<pre>` with prose inside is skipped even when `-syntaxHighlighter=prism` is on. The `-preLanguage <lang>` option (CLI) or `preLanguage="lang"` attribute (Ant task) closes that gap without touching source files:

    groovydoc -syntaxHighlighter prism -preLanguage groovy ...

When set, a post-render pass rewrites each unattributed `<pre>body</pre>` to `<pre class="language-xxx"><code>body</code></pre>`, using the configured language id. A `<pre class="language-xxx">` that lacks an inner `<code>` is also completed with a `<code>` wrapper so hand-authored language-classed blocks highlight whether or not the author remembered the nested `<code>`. `<pre>` tags with any existing attribute (authored `class="language-sql"`, `id="…​"`, or similar) are left untouched.

The option is off by default; unset, no rewriting occurs.

### 4.5. Disable optional pages

GroovyDoc generates auxiliary pages by default:

- `index-all.html` — alphabetical index of every class and member

- `deprecated-list.html` — everything marked `@deprecated`

- `help-doc.html` — explanation of the page layout

Any of these can be suppressed with `-noindex`, `-nodeprecatedlist`, `-nohelp` (CLI) or the corresponding `noIndex`, `noDeprecatedList`, `noHelp` Ant attributes. When suppressed, the page is not generated and navigation bars on other pages omit the corresponding link.

## 5. GMavenPlus Maven plugin

GMavenPlus is a Maven plugin with goals that drive groovydoc. Consult the plugin documentation for the current list of options it exposes.

## 6. Advanced topics

### 6.1. `{@snippet}` code snippets

`{@snippet}` embeds a code sample that renders as a preformatted block and, when syntax highlighting is enabled, is coloured according to its declared language. Three forms are supported:

#### 6.1.1. Inline body

    /**
     * {@snippet lang="groovy" :
     * def greet(name) { "Hello, $name" }
     * greet('world')
     * }
     */

The language is optional; when set, it becomes the Prism language class used for syntax highlighting. Any text from the opening brace to the matching closing brace is the snippet body.

#### 6.1.2. Brace balancing in the inline form

Body parsing is a linear brace-depth scan: depth starts at 1 on the opening `{` of the tag, increments on each structural `{`, decrements on each structural `}`, and the matching close is reached when depth returns to zero. While scanning, ordinary quoted string/character literals (backslash escapes included), multi-line text blocks (`"""…​"""` / `'''…​'''`), `/* …​ /` block comments, and `// …​` line comments (to end of line) are skipped so braces inside them do not affect depth. Nested braces in real code — closures, `catalog.each { book → …​ }`, GString `"value=${x}"`, and unbalanced braces *inside quotes, text blocks, or comments such as `System.out.println(" } ")`, `"""\n}\n"""`, or `// }` — are therefore handled correctly and do not terminate the tag early.

    /**
     * {@snippet lang="groovy" :
     * System.out.println(" } ")   // } inside the string is fine
     * // } inside a line comment is fine too
     * def block = """
     *   multi-line with }
     * """
     * if (ok) { work() }
     * }
     */

Because `//` comments run to end of line, put the tag-closing `}` on its own line (or after real code), not after a trailing `//` on the same line — otherwise the closer is swallowed by the comment. Braces that are not inside a skipped span and are not balanced will still confuse the parser; workarounds:

- Rewrite the example so structural braces balance, or keep unbalanced braces inside quotes, text blocks, or comments (already ignored).

- Move the sample into a file and use the external form (`{@snippet file="Example.groovy"}`), which reads the file verbatim without brace-balanced parsing.

- Write a problematic `}` as the HTML entity `}`, which is not a brace character during body extraction but renders as `}` in the output.

#### 6.1.3. External file reference

Place the source of the snippet in a `snippet-files/` subdirectory of the current package, then reference it:

    /** {@snippet file="GreetExample.groovy"} */

The `snippet-files/` directory is discovered via the `-sourcepath`. The file is copied to the output site verbatim so that the snippet remains browsable in the rendered docs.

A `region="name"` attribute selects a slice of the file bounded by `// @start region="name"` and `// @end region="name"` marker comments.

Two author-facing conveniences apply to the external form:

- Language inference from file extension — when no explicit `lang="…​"` attribute is given, the Prism language class is derived from the referenced file’s extension. The recognised extensions are `.groovy` / `.gvy` / `.gy` / `.gsh` (groovy), `.java`, `.xml` / `.html` / `.htm` (xml-doc), `.json`, `.yaml` / `.yml`, `.toml`, `.sql`, `.csv`, `.md` / `.markdown`, `.properties`, and `.js` (javascript). Explicit `lang=` still wins when both are present.

- License-header auto-strip — external snippet files typically carry a license or copyright notice as their first block comment, which isn’t useful in the rendered output. If the file begins with a leading `/* …​ */` block comment whose text contains either "Licensed" or "Copyright", the block is stripped before rendering (covers Apache, MIT, BSD, GPL and most proprietary notices). Files whose first content isn’t a license-looking block comment are left verbatim. To preserve a matching header (or suppress the strip for a file that happens to match), add `keepHeader=true`:

      /** {@snippet file="GreetExample.groovy" keepHeader=true} */

#### 6.1.4. Markup comments inside a snippet body

Markup comments let snippet authors highlight, replace, or link portions of the code without changing the source itself:

Directive | Effect
--- | ---
`// @highlight [substring="text"|regex="pattern"] [type="bold|italic|highlighted"]` | Wrap matches in `<b>`/`<i>`/`<mark>`. Type defaults to `bold`.
`// @replace [substring="text"|regex="pattern"] replacement="text"` | Replace matching text in the rendered output.
`// @link [substring="text"|regex="pattern"] target="Class[#member]"` | Turn matches into anchors pointing at the referenced element.
`// @start region="name"`, `// @end [region="name"]` | Define a named region for the external-file form, or as a scoping bound for any of the above directives.

A directive written on its own line applies to the next code line. A directive written at the end of a code line (after the code) applies to that line’s code portion. Adding a `region="name"` attribute to a directive activates it until the matching `// @end`. Directive comment lines are stripped from the rendered output.

For the complete semantics see JEP 413.

### 6.2. Class hierarchy tree pages

GroovyDoc generates a global `overview-tree.html` and per-package `package-tree.html` showing class and interface hierarchies. Classes are rooted at `java.lang.Object`; interfaces and traits form a separate tree. External ancestors (types the tool can’t see) render as plain text joining documented classes up the chain.

### 6.3. Runtime Groovydoc (`/**@`)

A doc comment whose opening marker is `/@` instead of `/` can be retained as runtime metadata. Enable it by setting the compiler option:

    compilerConfiguration.setOptimizationOptions(
        [(CompilerConfiguration.RUNTIME_GROOVYDOC): true]
    )

When enabled, the parser attaches the raw comment text (still in source form — including `/*@`, per-line ``, and `*/`) to the declaration as a `groovy.lang.@Groovydoc` annotation. Readers access the text reflectively:

    assert SomeClass.class.groovydoc.content.contains('class summary')

`/@` comments do not need to be marked specially to participate in normal groovydoc HTML generation; they render identically to `/`.

### 6.4. `doc-files/` and `snippet-files/`

Each package may contain a `doc-files/` subdirectory whose content is copied verbatim into the rendered output under the same package path. Useful for bundling images, diagrams, and supplementary HTML alongside the generated pages.

The sibling convention `snippet-files/` is used by `{@snippet file=…​`. Both conventions are sourced from `-sourcepath` directories and preserve nested subdirectories.

### 6.5. Java source version

`-javaVersion` (CLI) / `javaVersion` (Ant attribute) declares the language level at which `.java` source files are parsed. The accepted values are the names of the `ParserConfiguration.LanguageLevel` enum — for example `JAVA_8`, `JAVA_17`, `JAVA_21`.

### 6.6. Custom templates

The default template set can be replaced by extending `Groovydoc` in a small Java class:

    package org.codehaus.groovy.tools.groovydoc;

    import org.codehaus.groovy.ant.Groovydoc;

    public class CustomGroovyDoc extends Groovydoc {

        @Override
        protected String[] getClassTemplates() {
            return new String[]{"path/to/custom/classDocName.html"};
        }
    }

The following methods can be overridden:

- `getClassTemplates` — class-level templates

- `getPackageTemplates` — package-level templates

- `getDocTemplates` — top-level (overview, index, tree, etc.) templates

The list of default templates is in `org.codehaus.groovy.tools.groovydoc.gstringTemplates.GroovyDocTemplateInfo`.

Having extended the task, you then register it as an Ant task under the same name:

    <taskdef name         = "groovydoc"
             classname    = "org.codehaus.groovy.tools.groovydoc.CustomGroovyDoc"
             classpathref = "path_to_groovy_all"/>

Template customisation is provided as is — the template APIs are subject to change between releases.