Skip to content

Adopt AntBuilder groovydoc with javaVersion support#15420

Open
jamesfredley wants to merge 2 commits into7.0.xfrom
fix/groovydoc-java-version
Open

Adopt AntBuilder groovydoc with javaVersion support#15420
jamesfredley wants to merge 2 commits into7.0.xfrom
fix/groovydoc-java-version

Conversation

@jamesfredley
Copy link
Contributor

@jamesfredley jamesfredley commented Feb 20, 2026

Summary

Replaces Gradle built-in Groovydoc task execution with direct AntBuilder invocation of the Groovy org.codehaus.groovy.ant.Groovydoc Ant task, enabling the javaVersion parameter introduced in Groovy 4.0.27 (GROOVY-11668). The duplicated AntBuilder configuration is then centralized into a GrailsGroovydocPlugin convention plugin in build-logic/.

Problem

Gradle Groovydoc task does not expose the javaVersion property (gradle/gradle#33659 is not merged). Without it, groovydoc defaults to JAVA_11 language level when parsing Java source files, causing failures when processing Java 17+ features like sealed classes, records, and pattern matching.

Solution

1. AntBuilder groovydoc with javaVersion

For each Groovydoc task:

  1. Clear Gradle built-in @TaskAction execution
  2. Replace with a doLast that uses AntBuilder to call org.codehaus.groovy.ant.Groovydoc directly
  3. Pass javaVersion: JAVA_17 (derived from gradle.properties) to enable correct Java 17+ source parsing

2. Centralized convention plugin

Created GrailsGroovydocPlugin (org.apache.grails.buildsrc.groovydoc) in build-logic/ that:

  • Replaces Gradle's built-in Groovydoc execution with AntBuilder for javaVersion support
  • Adds the Matomo analytics footer to all generated docs
  • Resolves source directories from the main source set
  • Supports external doc links via ext.groovydocLinks
  • Handles the GroovydocAccess enum via Class.forName (not on build-logic compile classpath)
  • Handles Gradle's mixed Property<T> / plain-value API via resolveGroovydocProperty()

GrailsGroovydocExtension provides:

  • javaVersion (default: JAVA_17) - target Java version for Groovydoc output
  • javaVersionEnabled (default: true) - allows disabling for Groovy 3.x (Forge uses 3.0.25 which lacks javaVersion support)

Files changed

File Scope Notes
build-logic/plugins/build.gradle Plugin registration Registers grailsGroovydoc plugin ID
build-logic/.../GrailsGroovydocPlugin.groovy Convention plugin AntBuilder execution, Matomo footer, source resolution, links
build-logic/.../GrailsGroovydocExtension.groovy Extension javaVersion and javaVersionEnabled properties
gradle/docs-dependencies.gradle Central config (~90 modules) Plugin apply + deps + dynamic links
gradle/docs-config.gradle Per-module setup Plugin apply + includeInApiDocs
grails-gradle/gradle/docs-config.gradle grails-gradle config Plugin apply + deps + custom dest dir
grails-forge/gradle/doc-config.gradle Forge (Groovy 3.0.25) Plugin apply (javaVersionEnabled = false) + deps
grails-data-hibernate5/docs/build.gradle Hibernate5 docs Plugin apply + deps + custom source collection
grails-data-mongodb/docs/build.gradle MongoDB docs Plugin apply + deps + custom source collection
grails-doc/build.gradle Aggregate groovydoc Simplified - footer from plugin
grails-data-docs/stage/build.gradle Data mapping aggregate Simplified - footer from plugin

Technical details

  • A resolveGroovydocProperty() helper handles the mix of plain values and Property<T> wrappers in Gradle Groovydoc task API
  • Source directories are passed via ext.groovydocSourceDirs for aggregate tasks, or derived from source sets for per-module tasks
  • The documentation configuration already includes groovy-ant in the central config; hibernate5 and mongodb docs needed it added
  • Disabled groovydoc tasks (test suites) are unaffected - Gradle checks enabled before running any actions
  • The grails-data-neo4j and grails-data-graphql modules are not in the build and were not changed
  • Dynamic links (geb-spock, testcontainers, spring-core, spring-boot) use doFirst to populate ext.groovydocLinks, plugin reads them in doLast

Testing

  • Per-module groovydoc: :grails-core:groovydoc, :grails-bootstrap:groovydoc
  • grails-gradle module: :grails-gradle-plugins:groovydoc
  • Aggregate groovydoc: :grails-doc:aggregateGroovydoc (3,929 HTML files generated)
  • Data mapping aggregate: :grails-data-docs-stage:aggregateDataMappingGroovydoc
  • Code style check: ./gradlew codeStyle passes
  • Forge groovydoc (with javaVersionEnabled = false)

Closes #15385

Replace Gradle's built-in Groovydoc task execution with AntBuilder to
support the javaVersion parameter introduced in Groovy 4.0.27
(GROOVY-11668). This is needed because Gradle's Groovydoc task does not
expose javaVersion (gradle/gradle#33659 is not merged), causing Java 17+
source parsing failures.

Changes across all groovydoc configurations:
- gradle/docs-dependencies.gradle: central config for ~90 modules and
  both aggregate tasks (aggregateGroovydoc, aggregateDataMappingGroovydoc)
- gradle/docs-config.gradle: per-module source directory setup
- grails-doc/build.gradle: aggregate task source directories
- grails-data-docs/stage/build.gradle: data mapping aggregate source dirs
- grails-gradle/gradle/docs-config.gradle: independent AntBuilder setup
- grails-data-hibernate5/docs/build.gradle: added groovy-ant dependency
  and AntBuilder execution
- grails-data-mongodb/docs/build.gradle: added groovy-ant dependency
  and AntBuilder execution
- grails-forge/gradle/doc-config.gradle: AntBuilder without javaVersion
  (forge uses Groovy 3.0.25 which predates the feature)

Closes #15385

Assisted-by: Claude Code <Claude@Claude.ai>
…ion plugin

Move duplicated AntBuilder groovydoc execution, Matomo footer, documentation
configuration registration, and task defaults into a shared convention plugin
in build-logic. This eliminates ~490 lines of duplicated configuration across
8 build scripts while maintaining identical behavior.

The plugin provides:
- Documentation configuration registration with standard attributes
- Common Groovydoc task defaults (author, timestamps, scripts)
- AntBuilder-based execution with javaVersion support (Groovy 4.0.27+)
- Matomo analytics footer
- Source directory resolution from ext.groovydocSourceDirs or source sets
- External documentation link support via ext.groovydocLinks
- GrailsGroovydocExtension for per-project javaVersion control

Build scripts retain project-specific configuration: dependencies, titles,
source directories for aggregate tasks, and dynamic link resolution.

Assisted-by: Claude Code <Claude@Claude.ai>
@jamesfredley jamesfredley marked this pull request as ready for review February 20, 2026 01:50
Copilot AI review requested due to automatic review settings February 20, 2026 01:50
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR centralizes Groovydoc configuration and execution by introducing a build-logic convention plugin that runs Groovydoc via AntBuilder (to support Groovy’s javaVersion option), and updates multiple modules to use the new plugin while removing duplicated Groovydoc setup.

Changes:

  • Added org.apache.grails.buildsrc.groovydoc convention plugin (GrailsGroovydocPlugin + GrailsGroovydocExtension) to run Groovydoc through org.codehaus.groovy.ant.Groovydoc, with optional javaVersion support.
  • Updated shared/per-module docs Gradle scripts to apply the plugin and centralize common defaults (e.g., Matomo footer, shared dependency setup).
  • Updated aggregate Groovydoc tasks to pass source directories via ext.groovydocSourceDirs for the new Ant-driven execution.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
build-logic/plugins/build.gradle Registers the new org.apache.grails.buildsrc.groovydoc convention plugin.
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsGroovydocPlugin.groovy Implements AntBuilder-based Groovydoc execution and shared defaults (footer, configuration).
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsGroovydocExtension.groovy Adds extension properties to control javaVersion and the javaVersion-passing toggle.
gradle/docs-dependencies.gradle Applies the convention plugin and reworks Groovydoc link population via ext.groovydocLinks.
grails-gradle/gradle/docs-config.gradle Applies the convention plugin and removes duplicated Groovydoc task configuration.
grails-forge/gradle/doc-config.gradle Applies the convention plugin; disables javaVersion passing for Groovy 3.x and adds Ant Groovydoc deps.
grails-doc/build.gradle Simplifies aggregate Groovydoc setup and provides ext.groovydocSourceDirs for Ant execution.
grails-data-docs/stage/build.gradle Updates aggregate Groovydoc source handling and provides ext.groovydocSourceDirs.
grails-data-hibernate5/docs/build.gradle Applies the convention plugin, adds required Ant Groovydoc deps, and supplies ext.groovydocSourceDirs.
grails-data-mongodb/docs/build.gradle Applies the convention plugin, adds required Ant Groovydoc deps, and supplies ext.groovydocSourceDirs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +126 to +130
Map<String, Object> antArgs = [
destdir: destDir.absolutePath,
sourcepath: sourcepath,
packagenames: '**.*',
windowtitle: gdoc.windowTitle ?: '',
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Ant groovydoc call doesn't pass gdoc.classpath/gdoc.groovyClasspath (the documentation configuration is only used for taskdef). As a result, any Groovydoc classpath configured in build scripts is ignored during generation and can break type resolution. Pass the configured task classpath into the Ant task (e.g., classpath attribute or nested classpath).

Copilot uses AI. Check for mistakes.
Comment on lines +105 to +109
List<File> sourceDirs = resolveSourceDirectories(gdoc, project)
if (sourceDirs.isEmpty()) {
project.logger.lifecycle("Skipping groovydoc for ${gdoc.name}: no source directories found")
return
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Groovydoc source filtering from the Gradle task (e.g., gdoc.source, gdoc.includes/gdoc.excludes) isn’t honored here because the Ant task is driven only by sourcepath + packagenames. This makes existing exclusions in build scripts ineffective and can change which classes end up in the published API docs. Consider deriving the Ant inputs from gdoc.source (or translating excludes/includes into Ant filesets/excludepackagenames) so task configuration still applies.

Copilot uses AI. Check for mistakes.
Comment on lines 52 to 55
def gebVersion = resolveProjectVersion('geb-spock')
if(gebVersion) {
gdoc.link("https://groovy.apache.org/geb/manual/${gebVersion}/api/", 'geb.')
if (gebVersion) {
links << [packages: 'geb.', href: "https://groovy.apache.org/geb/manual/${gebVersion}/api/"]
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolveProjectVersion() (defined above) never returns the resolved version when it is present, so gebVersion/testContainersVersion/etc will always be null here and no external groovydoc links will be added. Ensure resolveProjectVersion() returns the resolved version value.

Copilot uses AI. Check for mistakes.
import org.gradle.api.tasks.javadoc.Groovydoc

@CompileStatic
class GrailsGroovydocPlugin implements Plugin<Project> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts about keeping this plugin generic? i.e. do not put specific grails-core configuration in it and instead configure it like we configured groovydoc before? That way if gradle merges the upstream change, we don't have to separate out all of the configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adopt newer groovydoc options

2 participants

Comments