This is an automated email from the ASF dual-hosted git repository.

jamesfredley pushed a commit to branch fix/groovydoc-java-version
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit 3467bad8dbaa0da1e973e6a4cdb1bc1f07f1fc43
Author: James Fredley <[email protected]>
AuthorDate: Thu Feb 19 20:00:48 2026 -0500

    Adopt AntBuilder groovydoc with javaVersion support
    
    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 <[email protected]>
---
 gradle/docs-config.gradle                |  9 +++
 gradle/docs-dependencies.gradle          | 97 ++++++++++++++++++++++++++++----
 grails-data-docs/stage/build.gradle      | 10 ++--
 grails-data-hibernate5/docs/build.gradle | 62 ++++++++++++++++++++
 grails-data-mongodb/docs/build.gradle    | 61 ++++++++++++++++++++
 grails-doc/build.gradle                  |  4 +-
 grails-forge/gradle/doc-config.gradle    | 82 +++++++++++++++++++++++----
 grails-gradle/gradle/docs-config.gradle  | 54 ++++++++++++++++++
 8 files changed, 351 insertions(+), 28 deletions(-)

diff --git a/gradle/docs-config.gradle b/gradle/docs-config.gradle
index 5b5c7d1794..76a14b619b 100644
--- a/gradle/docs-config.gradle
+++ b/gradle/docs-config.gradle
@@ -21,4 +21,13 @@ apply from: 
rootProject.layout.projectDirectory.file('gradle/docs-dependencies.g
 
 ext {
     includeInApiDocs = true
+}
+
+// Set source directories for AntBuilder groovydoc execution (per-module tasks)
+tasks.withType(Groovydoc).configureEach { Groovydoc gdoc ->
+    SourceSetContainer sourceSets = 
project.extensions.getByType(SourceSetContainer)
+    SourceSet mainSS = sourceSets.findByName('main')
+    if (mainSS) {
+        gdoc.ext.groovydocSourceDirs = (mainSS.groovy.srcDirs + 
mainSS.java.srcDirs).findAll { it.exists() }
+    }
 }
\ No newline at end of file
diff --git a/gradle/docs-dependencies.gradle b/gradle/docs-dependencies.gradle
index df4244f39c..23b75693b9 100644
--- a/gradle/docs-dependencies.gradle
+++ b/gradle/docs-dependencies.gradle
@@ -50,6 +50,21 @@ String resolveProjectVersion(String artifact) {
     }
 }
 
+// Resolve a Groovydoc task property that may be either a Gradle Property<T> 
or a plain value.
+// Gradle 8.x Groovydoc uses a mix of both types depending on the property.
+Object resolveGroovydocProperty(Object value) {
+    if (value instanceof org.gradle.api.provider.Provider) {
+        return value.getOrNull()
+    }
+    return value
+}
+
+// Compute the javaVersion string for groovydoc's JavaParser language level.
+// Requires Groovy 4.0.27+ (GROOVY-11668). Gradle's built-in Groovydoc task 
does not
+// expose this parameter (https://github.com/gradle/gradle/issues/33659), so 
we replace
+// the task execution with AntBuilder to pass it directly to the Groovy Ant 
task.
+String groovydocJavaVersion = "JAVA_${project.findProperty('javaVersion') ?: 
'17'}"
+
 tasks.withType(Groovydoc).configureEach { Groovydoc gdoc ->
     gdoc.exclude('META-INF/**', '*yml', '*properties', '*xml', 
'**/Application.groovy', '**/Bootstrap.groovy', '**/resources.groovy')
     gdoc.groovyClasspath = configurations.documentation
@@ -79,25 +94,83 @@ tasks.withType(Groovydoc).configureEach { Groovydoc gdoc ->
 </script>
 <!-- End Matomo Code -->'''
 
-    doFirst {
-        def gebVersion = resolveProjectVersion('geb-spock')
-        if(gebVersion) {
-            
gdoc.link("https://groovy.apache.org/geb/manual/${gebVersion}/api/";, 'geb.')
+    // Replace Gradle's built-in Groovydoc execution with AntBuilder to 
support javaVersion.
+    // See: https://github.com/apache/grails-core/issues/15385
+    gdoc.actions.clear()
+    gdoc.doLast {
+        def destDir = gdoc.destinationDir
+        destDir.mkdirs()
+
+        // Source directories: set by modules via ext.groovydocSourceDirs, or 
derived from source sets
+        List<File> sourceDirs
+        if (gdoc.ext.has('groovydocSourceDirs') && 
gdoc.ext.groovydocSourceDirs) {
+            sourceDirs = (gdoc.ext.groovydocSourceDirs as List<File>).findAll 
{ it.exists() }
+        } else {
+            sourceDirs = []
+            def sourceSetsExt = 
project.extensions.findByType(SourceSetContainer)
+            if (sourceSetsExt) {
+                def mainSS = sourceSetsExt.findByName('main')
+                if (mainSS) {
+                    sourceDirs.addAll(mainSS.groovy.srcDirs.findAll { 
it.exists() })
+                    sourceDirs.addAll(mainSS.java.srcDirs.findAll { 
it.exists() })
+                }
+            }
         }
+        sourceDirs = sourceDirs.unique()
 
-        def testContainersVersion = resolveProjectVersion('testcontainers')
-        if(testContainersVersion) {
-            
gdoc.link("https://javadoc.io/doc/org.testcontainers/testcontainers/${testContainersVersion}/";,
 'org.testcontainers.')
+        if (sourceDirs.isEmpty()) {
+            logger.lifecycle("Skipping groovydoc for ${gdoc.name}: no source 
directories found")
+            return
         }
 
+        ant.taskdef(
+                name: 'groovydoc',
+                classname: 'org.codehaus.groovy.ant.Groovydoc',
+                classpath: configurations.documentation.asPath
+        )
+
+        // Resolve dynamic links from project dependencies
+        List<Map<String, String>> groovydocLinks = []
+        def gebVersion = resolveProjectVersion('geb-spock')
+        if (gebVersion) {
+            groovydocLinks << [packages: 'geb.', href: 
"https://groovy.apache.org/geb/manual/${gebVersion}/api/";]
+        }
+        def testContainersVersion = resolveProjectVersion('testcontainers')
+        if (testContainersVersion) {
+            groovydocLinks << [packages: 'org.testcontainers.', href: 
"https://javadoc.io/doc/org.testcontainers/testcontainers/${testContainersVersion}/";]
+        }
         def springVersion = resolveProjectVersion('spring-core')
-        if(springVersion) {
-            
gdoc.link("https://docs.spring.io/spring-framework/docs/${springVersion}/javadoc-api/";,
 'org.springframework.core.')
+        if (springVersion) {
+            groovydocLinks << [packages: 'org.springframework.core.', href: 
"https://docs.spring.io/spring-framework/docs/${springVersion}/javadoc-api/";]
         }
-
         def springBootVersion = resolveProjectVersion('spring-boot')
-        if(springBootVersion) {
-            
gdoc.link("https://docs.spring.io/spring-boot/docs/${springBootVersion}/api/";, 
'org.springframework.boot.')
+        if (springBootVersion) {
+            groovydocLinks << [packages: 'org.springframework.boot.', href: 
"https://docs.spring.io/spring-boot/docs/${springBootVersion}/api/";]
+        }
+        if (gdoc.ext.has('groovydocLinks')) {
+            groovydocLinks.addAll(gdoc.ext.groovydocLinks as List<Map<String, 
String>>)
+        }
+
+        def sourcepath = sourceDirs.collect { it.absolutePath 
}.join(File.pathSeparator)
+
+        ant.groovydoc(
+                destdir: destDir.absolutePath,
+                sourcepath: sourcepath,
+                packagenames: '**.*',
+                windowtitle: gdoc.windowTitle ?: '',
+                doctitle: gdoc.docTitle ?: '',
+                footer: gdoc.footer ?: '',
+                access: 
resolveGroovydocProperty(gdoc.access)?.name()?.toLowerCase() ?: 'protected',
+                author: resolveGroovydocProperty(gdoc.includeAuthor) as String,
+                noTimestamp: resolveGroovydocProperty(gdoc.noTimestamp) as 
String,
+                noVersionStamp: resolveGroovydocProperty(gdoc.noVersionStamp) 
as String,
+                processScripts: resolveGroovydocProperty(gdoc.processScripts) 
as String,
+                includeMainForScripts: 
resolveGroovydocProperty(gdoc.includeMainForScripts) as String,
+                javaVersion: groovydocJavaVersion
+        ) {
+            for (Map<String, String> l in groovydocLinks) {
+                link(packages: l.packages, href: l.href)
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/grails-data-docs/stage/build.gradle 
b/grails-data-docs/stage/build.gradle
index b5d71cc03a..4d13bb6b01 100644
--- a/grails-data-docs/stage/build.gradle
+++ b/grails-data-docs/stage/build.gradle
@@ -77,14 +77,16 @@ combinedGroovydoc.configure { Groovydoc task ->
             }
             .flatten()
 
-    task.source(sources.collect{ SourceSet it -> [it.allSource.srcDirs, 
it.allSource.srcDirs] }.flatten().findAll { File srcDir ->
-        if(!(srcDir.name in ['java', 'groovy'])) {
+    def allSourceDirs = sources.collect { SourceSet it -> 
[it.allSource.srcDirs, it.allSource.srcDirs] }.flatten().findAll { File srcDir 
->
+        if (!(srcDir.name in ['java', 'groovy'])) {
             return false
         }
 
         srcDir.exists()
-    }.unique())
-    task.classpath = files(sources.collect{ SourceSet it -> 
it.compileClasspath.filter(File.&isDirectory) }.flatten().unique())
+    }.unique()
+    task.source(allSourceDirs)
+    task.ext.groovydocSourceDirs = allSourceDirs
+    task.classpath = files(sources.collect { SourceSet it -> 
it.compileClasspath.filter(File.&isDirectory) }.flatten().unique())
     task.destinationDir = 
project.layout.buildDirectory.dir('data-api/api').get().asFile
 
     
task.inputs.files(task.source).withPropertyName("groovyDocSrc").withPathSensitivity(PathSensitivity.RELATIVE)
diff --git a/grails-data-hibernate5/docs/build.gradle 
b/grails-data-hibernate5/docs/build.gradle
index aed5772187..565da447cb 100644
--- a/grails-data-hibernate5/docs/build.gradle
+++ b/grails-data-hibernate5/docs/build.gradle
@@ -44,7 +44,11 @@ dependencies {
     documentation 'com.github.javaparser:javaparser-core'
     documentation "info.picocli:picocli:$picocliVersion"
     documentation 'org.apache.groovy:groovy-dateutil'
+    documentation 'org.apache.groovy:groovy-ant'
+    documentation 'org.apache.groovy:groovy-groovydoc'
+    documentation 'org.apache.groovy:groovy-templates'
     documentation 'org.fusesource.jansi:jansi'
+    documentation 'jline:jline'
     documentation project(':grails-bootstrap')
     documentation project(':grails-core')
     documentation project(':grails-spring')
@@ -90,6 +94,18 @@ tasks.named('asciidoctor', AsciidoctorTask) { 
AsciidoctorTask it ->
     ]
 }
 
+// Resolve a Groovydoc task property that may be either a Gradle Property<T> 
or a plain value.
+Object resolveGroovydocProperty(Object value) {
+    if (value instanceof org.gradle.api.provider.Provider) {
+        return value.getOrNull()
+    }
+    return value
+}
+
+// Compute the javaVersion string for groovydoc's JavaParser language level.
+// Requires Groovy 4.0.27+ (GROOVY-11668).
+String groovydocJavaVersion = "JAVA_${project.findProperty('javaVersion') ?: 
'17'}"
+
 tasks.withType(Groovydoc).configureEach {
     it.dependsOn(rootProject.subprojects
             .findAll { it.findProperty('gormApiDocs') }
@@ -131,6 +147,52 @@ tasks.withType(Groovydoc).configureEach {
     it.classpath = configurations.documentation
     it.groovyClasspath += configurations.documentation
     it.noVersionStamp = false
+
+    // Collect source directories for AntBuilder groovydoc
+    List<File> groovydocSrcDirs = coreProjects.collect {
+        rootProject.layout.projectDirectory.dir("$it/src/main/groovy").asFile
+    }
+    rootProject.subprojects
+            .findAll { sp -> sp.findProperty('gormApiDocs') }
+            .each { sp -> groovydocSrcDirs << new File(sp.projectDir, 
'src/main/groovy') }
+    it.ext.groovydocSourceDirs = groovydocSrcDirs
+
+    // Replace Gradle's built-in Groovydoc execution with AntBuilder to 
support javaVersion.
+    // See: https://github.com/apache/grails-core/issues/15385
+    it.actions.clear()
+    it.doLast { Groovydoc gdoc ->
+        def destDir = gdoc.destinationDir
+        destDir.mkdirs()
+
+        List<File> sourceDirs = (gdoc.ext.groovydocSourceDirs as 
List<File>).findAll { File f -> f.exists() }.unique()
+        if (sourceDirs.isEmpty()) {
+            logger.lifecycle("Skipping groovydoc for ${gdoc.name}: no source 
directories found")
+            return
+        }
+
+        ant.taskdef(
+                name: 'groovydoc',
+                classname: 'org.codehaus.groovy.ant.Groovydoc',
+                classpath: configurations.documentation.asPath
+        )
+
+        def sourcepath = sourceDirs.collect { File f -> f.absolutePath 
}.join(File.pathSeparator)
+
+        ant.groovydoc(
+                destdir: destDir.absolutePath,
+                sourcepath: sourcepath,
+                packagenames: '**.*',
+                doctitle: gdoc.docTitle ?: '',
+                footer: gdoc.footer ?: '',
+                access: 
resolveGroovydocProperty(gdoc.access)?.name()?.toLowerCase() ?: 'protected',
+                author: resolveGroovydocProperty(gdoc.includeAuthor) as String,
+                noTimestamp: 'true',
+                noVersionStamp: resolveGroovydocProperty(gdoc.noVersionStamp) 
as String,
+                processScripts: resolveGroovydocProperty(gdoc.processScripts) 
as String,
+                includeMainForScripts: 
resolveGroovydocProperty(gdoc.includeMainForScripts) as String,
+                javaVersion: groovydocJavaVersion
+        )
+    }
 }
 
 tasks.register('docs', Sync).configure { Sync docTask ->
diff --git a/grails-data-mongodb/docs/build.gradle 
b/grails-data-mongodb/docs/build.gradle
index 89cfce4530..81a0fca998 100644
--- a/grails-data-mongodb/docs/build.gradle
+++ b/grails-data-mongodb/docs/build.gradle
@@ -56,7 +56,10 @@ tasks.register('resolveMongodbVersion').configure { Task 
docTask ->
 dependencies {
     documentation platform(project(':grails-bom'))
     documentation 'org.fusesource.jansi:jansi'
+    documentation 'jline:jline'
     documentation 'org.apache.groovy:groovy'
+    documentation 'org.apache.groovy:groovy-ant'
+    documentation 'org.apache.groovy:groovy-groovydoc'
     documentation 'org.apache.groovy:groovy-templates'
     documentation 'org.apache.groovy:groovy-dateutil'
     documentation 'com.github.javaparser:javaparser-core'
@@ -100,6 +103,18 @@ tasks.named('asciidoctor', AsciidoctorTask) { 
AsciidoctorTask it ->
     ]
 }
 
+// Compute the javaVersion string for groovydoc's JavaParser language level.
+// Requires Groovy 4.0.27+ (GROOVY-11668).
+String groovydocJavaVersion = "JAVA_${project.findProperty('javaVersion') ?: 
'17'}"
+
+// Resolve a Groovydoc task property that may be either a Gradle Property<T> 
or a plain value.
+Object resolveGroovydocProperty(Object value) {
+    if (value instanceof org.gradle.api.provider.Provider) {
+        return value.getOrNull()
+    }
+    return value
+}
+
 tasks.withType(Groovydoc).configureEach { Groovydoc groovydoc ->
     groovydoc.dependsOn(rootProject.subprojects
             .findAll { it.findProperty('gormApiDocs') }
@@ -140,6 +155,52 @@ tasks.withType(Groovydoc).configureEach { Groovydoc 
groovydoc ->
     groovydoc.classpath = configurations.documentation
     groovydoc.groovyClasspath += configurations.documentation
     groovydoc.noVersionStamp = false
+
+    // Collect source directories for AntBuilder groovydoc
+    List<File> groovydocSrcDirs = coreProjects.collect {
+        layout.projectDirectory.dir("$it/src/main/groovy").asFile
+    }
+    rootProject.subprojects
+            .findAll { sp -> sp.findProperty('gormApiDocs') }
+            .each { sp -> groovydocSrcDirs << new File(sp.projectDir, 
'src/main/groovy') }
+    groovydoc.ext.groovydocSourceDirs = groovydocSrcDirs
+
+    // Replace Gradle's built-in Groovydoc execution with AntBuilder to 
support javaVersion.
+    // See: https://github.com/apache/grails-core/issues/15385
+    groovydoc.actions.clear()
+    groovydoc.doLast { Groovydoc gdoc ->
+        def destDir = gdoc.destinationDir
+        destDir.mkdirs()
+
+        List<File> sourceDirs = (gdoc.ext.groovydocSourceDirs as 
List<File>).findAll { File f -> f.exists() }.unique()
+        if (sourceDirs.isEmpty()) {
+            logger.lifecycle("Skipping groovydoc for ${gdoc.name}: no source 
directories found")
+            return
+        }
+
+        ant.taskdef(
+                name: 'groovydoc',
+                classname: 'org.codehaus.groovy.ant.Groovydoc',
+                classpath: configurations.documentation.asPath
+        )
+
+        def sourcepath = sourceDirs.collect { File f -> f.absolutePath 
}.join(File.pathSeparator)
+
+        ant.groovydoc(
+                destdir: destDir.absolutePath,
+                sourcepath: sourcepath,
+                packagenames: '**.*',
+                doctitle: gdoc.docTitle ?: '',
+                footer: gdoc.footer ?: '',
+                access: 
resolveGroovydocProperty(gdoc.access)?.name()?.toLowerCase() ?: 'protected',
+                author: resolveGroovydocProperty(gdoc.includeAuthor) as String,
+                noTimestamp: 'true',
+                noVersionStamp: resolveGroovydocProperty(gdoc.noVersionStamp) 
as String,
+                processScripts: resolveGroovydocProperty(gdoc.processScripts) 
as String,
+                includeMainForScripts: 
resolveGroovydocProperty(gdoc.includeMainForScripts) as String,
+                javaVersion: groovydocJavaVersion
+        )
+    }
 }
 
 tasks.register('docs', Sync).configure { Sync docTask ->
diff --git a/grails-doc/build.gradle b/grails-doc/build.gradle
index 1802c28395..63382c712e 100644
--- a/grails-doc/build.gradle
+++ b/grails-doc/build.gradle
@@ -127,7 +127,9 @@ combinedGroovydoc.configure { Groovydoc gdoc ->
                 sourceDirs
             }
 
-    gdoc.source(project.files((baseSourceDirs + 
includedBuildSourceDirs).unique()))
+    def allSourceDirs = (baseSourceDirs + includedBuildSourceDirs).unique()
+    gdoc.source(project.files(allSourceDirs))
+    gdoc.ext.groovydocSourceDirs = allSourceDirs
 
     gdoc.classpath = files(sources.collect { SourceSet it -> 
it.compileClasspath.filter(File.&isDirectory) }.flatten().unique())
     gdoc.destinationDir = 
project.layout.buildDirectory.dir('combined-api/api').get().asFile
diff --git a/grails-forge/gradle/doc-config.gradle 
b/grails-forge/gradle/doc-config.gradle
index d7b0eaf7fb..38b8e2a60d 100644
--- a/grails-forge/gradle/doc-config.gradle
+++ b/grails-forge/gradle/doc-config.gradle
@@ -30,13 +30,15 @@ configurations.register('documentation') {
 dependencies {
     documentation "org.codehaus.groovy:groovy-templates:$groovyVersion"
     documentation "org.codehaus.groovy:groovy-dateutil:$groovyVersion"
+    documentation "org.codehaus.groovy:groovy-ant:$groovyVersion"
+    documentation "org.codehaus.groovy:groovy-groovydoc:$groovyVersion"
 }
 
-tasks.withType(Groovydoc).configureEach {
-    classpath += project.configurations.documentation
-    windowTitle = "${project.findProperty('pomArtifactId') ?: project.name} - 
$projectVersion"
-    docTitle = "${project.findProperty('pomArtifactId') ?: project.name} - 
$projectVersion"
-    footer = '''<!-- Matomo -->
+tasks.withType(Groovydoc).configureEach { Groovydoc gdoc ->
+    gdoc.classpath += project.configurations.documentation
+    gdoc.windowTitle = "${project.findProperty('pomArtifactId') ?: 
project.name} - $projectVersion"
+    gdoc.docTitle = "${project.findProperty('pomArtifactId') ?: project.name} 
- $projectVersion"
+    gdoc.footer = '''<!-- Matomo -->
 <script>
     var _paq = window._paq = window._paq || [];
     /* tracker methods like "setCustomDimension" should be called before 
"trackPageView" */
@@ -53,10 +55,68 @@ tasks.withType(Groovydoc).configureEach {
     })();
 </script>
 <!-- End Matomo Code -->'''
-    access = GroovydocAccess.PROTECTED
-    includeAuthor = false
-    includeMainForScripts = false
-    processScripts = false
-    noTimestamp = true
-    noVersionStamp = false
+    gdoc.access = GroovydocAccess.PROTECTED
+    gdoc.includeAuthor = false
+    gdoc.includeMainForScripts = false
+    gdoc.processScripts = false
+    gdoc.noTimestamp = true
+    gdoc.noVersionStamp = false
+
+    // Resolve a Groovydoc task property that may be either a Gradle 
Property<T> or a plain value.
+    Closure resolveGroovydocProperty = { Object value ->
+        if (value instanceof org.gradle.api.provider.Provider) {
+            return value.getOrNull()
+        }
+        return value
+    }
+
+    // Replace Gradle's built-in Groovydoc execution with AntBuilder for 
consistency
+    // with the main build. The javaVersion parameter is not available in 
Groovy 3.x
+    // (requires Groovy 4.0.27+, GROOVY-11668) - it will be added when forge 
upgrades.
+    // See: https://github.com/apache/grails-core/issues/15385
+    gdoc.actions.clear()
+    gdoc.doLast {
+        def destDir = gdoc.destinationDir
+        destDir.mkdirs()
+
+        List<File> sourceDirs = []
+        def sourceSetsExt = project.extensions.findByType(SourceSetContainer)
+        if (sourceSetsExt) {
+            def mainSS = sourceSetsExt.findByName('main')
+            if (mainSS) {
+                sourceDirs.addAll(mainSS.groovy.srcDirs.findAll { it.exists() 
})
+                sourceDirs.addAll(mainSS.java.srcDirs.findAll { it.exists() })
+            }
+        }
+        sourceDirs = sourceDirs.unique()
+
+        if (sourceDirs.isEmpty()) {
+            logger.lifecycle("Skipping groovydoc for ${gdoc.name}: no source 
directories found")
+            return
+        }
+
+        ant.taskdef(
+                name: 'groovydoc',
+                classname: 'org.codehaus.groovy.ant.Groovydoc',
+                classpath: configurations.documentation.asPath
+        )
+
+        def sourcepath = sourceDirs.collect { File f -> f.absolutePath 
}.join(File.pathSeparator)
+
+        // Note: javaVersion omitted - not supported in Groovy 3.x (forge uses 
Groovy $groovyVersion)
+        ant.groovydoc(
+                destdir: destDir.absolutePath,
+                sourcepath: sourcepath,
+                packagenames: '**.*',
+                windowtitle: gdoc.windowTitle ?: '',
+                doctitle: gdoc.docTitle ?: '',
+                footer: gdoc.footer ?: '',
+                access: 
resolveGroovydocProperty(gdoc.access)?.name()?.toLowerCase() ?: 'protected',
+                author: resolveGroovydocProperty(gdoc.includeAuthor) as String,
+                noTimestamp: resolveGroovydocProperty(gdoc.noTimestamp) as 
String,
+                noVersionStamp: resolveGroovydocProperty(gdoc.noVersionStamp) 
as String,
+                processScripts: resolveGroovydocProperty(gdoc.processScripts) 
as String,
+                includeMainForScripts: 
resolveGroovydocProperty(gdoc.includeMainForScripts) as String
+        )
+    }
 }
diff --git a/grails-gradle/gradle/docs-config.gradle 
b/grails-gradle/gradle/docs-config.gradle
index be2aaf4f1c..e3459998b6 100644
--- a/grails-gradle/gradle/docs-config.gradle
+++ b/grails-gradle/gradle/docs-config.gradle
@@ -42,6 +42,18 @@ ext {
     includeInApiDocs = true
 }
 
+// Resolve a Groovydoc task property that may be either a Gradle Property<T> 
or a plain value.
+Object resolveGroovydocProperty(Object value) {
+    if (value instanceof org.gradle.api.provider.Provider) {
+        return value.getOrNull()
+    }
+    return value
+}
+
+// Compute the javaVersion string for groovydoc's JavaParser language level.
+// Requires Groovy 4.0.27+ (GROOVY-11668).
+String groovydocJavaVersion = "JAVA_${project.findProperty('javaVersion') ?: 
'17'}"
+
 TaskProvider<Groovydoc> groovydocTask = tasks.named('groovydoc', Groovydoc)
 groovydocTask.configure { Groovydoc it ->
     it.classpath = configurations.documentation
@@ -70,6 +82,48 @@ groovydocTask.configure { Groovydoc it ->
 </script>
 <!-- End Matomo Code -->'''
     it.destinationDir = project.file('build/docs/api')
+
+    // Replace Gradle's built-in Groovydoc execution with AntBuilder to 
support javaVersion.
+    // See: https://github.com/apache/grails-core/issues/15385
+    it.actions.clear()
+    it.doLast {
+        def destDir = it.destinationDir
+        destDir.mkdirs()
+
+        SourceSetContainer sourceSets = 
project.extensions.getByType(SourceSetContainer)
+        List<File> sourceDirs = ([] + sourceSets.main.groovy.srcDirs + 
sourceSets.main.java.srcDirs)
+                .findAll { File f -> f.exists() }
+                .unique()
+
+        if (sourceDirs.isEmpty()) {
+            logger.lifecycle("Skipping groovydoc for ${it.name}: no source 
directories found")
+            return
+        }
+
+        ant.taskdef(
+                name: 'groovydoc',
+                classname: 'org.codehaus.groovy.ant.Groovydoc',
+                classpath: configurations.documentation.asPath
+        )
+
+        def sourcepath = sourceDirs.collect { File f -> f.absolutePath 
}.join(File.pathSeparator)
+
+        ant.groovydoc(
+                destdir: destDir.absolutePath,
+                sourcepath: sourcepath,
+                packagenames: '**.*',
+                windowtitle: it.windowTitle ?: '',
+                doctitle: it.docTitle ?: '',
+                footer: it.footer ?: '',
+                access: 
resolveGroovydocProperty(it.access)?.name()?.toLowerCase() ?: 'protected',
+                author: resolveGroovydocProperty(it.includeAuthor) as String,
+                noTimestamp: resolveGroovydocProperty(it.noTimestamp) as 
String,
+                noVersionStamp: resolveGroovydocProperty(it.noVersionStamp) as 
String,
+                processScripts: resolveGroovydocProperty(it.processScripts) as 
String,
+                includeMainForScripts: 
resolveGroovydocProperty(it.includeMainForScripts) as String,
+                javaVersion: groovydocJavaVersion
+        )
+    }
 }
 
 tasks.named('javadoc').configure {

Reply via email to