Skip to content

JavacCompiler fails to resolve version with maven toolchains and Jenkins #420

Open
@nxglhez

Description

@nxglhez

Hello,

When maven-compiler-plugin is configured to fork or use a toolchains, Plexus JavacCompiler fails to determine correctly the Java version if there is a JAVA_TOOL_OPTIONS set prior, which is done automatically by Jenkins (I can't remove it): problem is that if affect the encoding as well as other parts (mostly in buildCompilerArguments) because it badly interpret the Java version to 1.3 (in my case).

The method getOutOfProcessJavacVersion use javac -version to determine compiler version, then it use use a regexp \d+(\.\d+)? on the stdout but when JAVA_TOOL_OPTIONS, there is an (annoying) warning and if the warning contains something that match the regexp, such as ... as version, it fails to return the proper JDK version:

Picked up JAVA_TOOL_OPTIONS: -Dmaven.ext.class.path="/some/path/with/name-1.3.x/foobar.jar" -Dorg.jenkinsci.plugins.pipeline.maven.reportsFolder="/some/path/with/name-1.3.x/"
javac 1.8.0_432

The regex can be tested here: https://regex101.com/r/EboVGM/1

As we can see, we have more than one result:

  • 1.3 <-- selected
  • 1.3
  • 1.8
  • 0
  • 432

If you are lucky, and like most Linux, javac will use UTF-8 while compiling: you won't notice anything.

If you are unlucky (like me), javac will not use UTF-8 while compiling, but ANSI_X3.4-1968 and it fails at the first mappable character it found (like ©).

One fix to this issue would be to resolve version from the javac line only:

String prefix = "javac ";
int prefixLength = prefix.length();
// grab the "javac " part
Optional<String> javacPrefix = Arrays.stream(text.split("\\R"))
      .filter(line -> line.startsWith(prefix))
      .map(line -> line.substring(prefixLength))
      .findFirst();
return javacPrefix.map(line -> JAVA_MAJOR_AND_MINOR_VERSION_PATTERN.matcher(line))
                  .filter(Matcher::find)
                  .map(Matcher::group)
                  .orElseThrow(() -> "Could not extract version from \"" + text + "\"");

Or we could assume that javac is always last and process only last line:

String[] lines = text.split("\\R");
String  lastLine = lines.length == 0 ? "":lines[lines.length-1];

Note: JAVA_TOOL_OPTIONS is set by Jenkins withMaven for various reasons and the docs indicate it is not possible to avoid this warning: https://github.com/jenkinsci/pipeline-maven-plugin/blob/master/FAQ.adoc#why-do-i-see-messages-warning-picked-up-java_tool_options-in-the-build-logs

When using the JAVA_TOOL_OPTIONS, the JVM outputs a message during its initialization.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions