Skip to content

Commit a8e94cf

Browse files
daniel-larrazclaude
andcommitted
Fix doclintCheck failing the build on Java 8
CI builds on Java 8, where System.getProperty("java.home") points at the JRE inside the JDK, so the task looked for javadoc at temurin-8-jdk-amd64/jre/bin/javadoc and died with "No such file or directory". Resolve the executable through the java toolchain instead, which always gives the JDK location. The task was also only meaningful on JDKs whose doclint reports missing documentation, which Java 8 and 11 do not, so it would have gone on to run a check that proves nothing. It now probes the javadoc it is about to use with a deliberately undocumented method, using the same flags as the real run, and skips with a message unless that probe is reported. Probing the flags too means an unsupported option also skips rather than failing the build. Verified: skips on JDK 11, skips on an unsupported flag, passes on JDK 25 with the documentation complete, and fails on JDK 25 with a comment removed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent a643b91 commit a8e94cf

1 file changed

Lines changed: 49 additions & 19 deletions

File tree

build.gradle

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,15 @@ tasks.withType(Javadoc).configureEach {
3636
// The javadoc task above runs doclint, but Gradle always passes -quiet, which
3737
// hides warning-level diagnostics such as "no comment", and it does not fail on
3838
// them. This task runs doclint separately and fails `check` if anything is
39-
// reported. Note that JDK 11's javadoc does not report missing comments at all,
40-
// so this only bites on newer JDKs; the documentation was verified against the
41-
// JDK 25 javadoc, which does report them.
39+
// reported.
40+
//
41+
// Only newer JDKs report missing documentation: JDK 11 reports none, JDK 25
42+
// reports it, and the documentation here was verified against JDK 25. Rather
43+
// than hard-code a version, the task probes the javadoc it is about to use and
44+
// skips when that javadoc cannot report a missing comment, so building on an
45+
// older JDK (CI uses Java 8) neither fails nor gives false assurance.
46+
def javadocTool = javaToolchains.javadocToolFor(java.toolchain)
47+
4248
def doclintCheck = tasks.register('doclintCheck') {
4349
description = 'Runs javadoc doclint over the main sources and fails on any warning.'
4450
group = 'verification'
@@ -47,6 +53,7 @@ def doclintCheck = tasks.register('doclintCheck') {
4753
def sources = sourceSets.main.allJava
4854
def classpath = sourceSets.main.compileClasspath
4955
def workDir = layout.buildDirectory.dir('tmp/doclint')
56+
def tool = javadocTool
5057

5158
inputs.files(sources)
5259
inputs.files(classpath)
@@ -57,26 +64,49 @@ def doclintCheck = tasks.register('doclintCheck') {
5764
dir.deleteDir()
5865
dir.mkdirs()
5966

60-
// The in-process javadoc ToolProvider does not honour -Xdoclint, so fork the
61-
// real javadoc executable and read its diagnostics.
62-
def argFile = new File(dir, 'sources.txt')
63-
argFile.text = sources.files.collect { it.absolutePath }.join('\n')
67+
// Resolve javadoc through the toolchain: on Java 8, java.home points at the
68+
// JRE, which has no bin/javadoc.
69+
def javadoc = tool.get().executablePath.asFile.absolutePath
70+
71+
// The in-process javadoc ToolProvider ignores -Xdoclint, so fork the real
72+
// executable and read its diagnostics.
73+
def runJavadoc = { List<String> extraArgs ->
74+
def process = new ProcessBuilder([javadoc] + extraArgs)
75+
.redirectErrorStream(true).start()
76+
def text = process.inputStream.text
77+
[output: text, exitCode: process.waitFor(),
78+
problems: text.readLines().findAll { it =~ /: (warning|error): / }]
79+
}
6480

65-
def command = ["${System.getProperty('java.home')}/bin/javadoc".toString(),
66-
'-Xdoclint:all', '-Xmaxwarns', '100000',
67-
'-classpath', classpath.asPath,
68-
'-d', new File(dir, 'out').absolutePath,
69-
'@' + argFile.absolutePath]
81+
def flags = ['-Xdoclint:all', '-Xmaxwarns', '100000']
82+
83+
// Probe: a public method with no comment, run with the same flags as the
84+
// real check. If this javadoc does not flag it -- because its doclint does
85+
// not report missing documentation, or because it rejects one of the flags
86+
// -- the real run would prove nothing, so skip rather than give false
87+
// assurance or fail for an environmental reason.
88+
def probeDir = new File(dir, 'probe')
89+
probeDir.mkdirs()
90+
def probeSource = new File(probeDir, 'DoclintProbe.java')
91+
probeSource.text = 'public class DoclintProbe { public void undocumented() {} }\n'
92+
def probe = runJavadoc(flags + ['-d', new File(probeDir, 'out').absolutePath,
93+
probeSource.absolutePath])
94+
if (probe.problems.isEmpty()) {
95+
logger.lifecycle('doclintCheck: skipped, ' + javadoc +
96+
' does not report missing documentation (needs a newer JDK).')
97+
return
98+
}
7099

71-
def process = new ProcessBuilder(command).redirectErrorStream(true).start()
72-
def output = process.inputStream.text
73-
def exitCode = process.waitFor()
100+
def argFile = new File(dir, 'sources.txt')
101+
argFile.text = sources.files.collect { it.absolutePath }.join('\n')
74102

75-
def problems = output.readLines().findAll { it =~ /: (warning|error): / }
76-
if (exitCode != 0 || !problems.isEmpty()) {
77-
problems.each { logger.error(it) }
103+
def result = runJavadoc(flags + ['-classpath', classpath.asPath,
104+
'-d', new File(dir, 'out').absolutePath,
105+
'@' + argFile.absolutePath])
106+
if (result.exitCode != 0 || !result.problems.isEmpty()) {
107+
result.problems.each { logger.error(it) }
78108
throw new GradleException(
79-
"javadoc doclint reported ${problems.size()} problem(s); see the messages above.")
109+
"javadoc doclint reported ${result.problems.size()} problem(s); see the messages above.")
80110
}
81111
}
82112
}

0 commit comments

Comments
 (0)