Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8289491

Diagnostics are not passed if certain libraries are in your classpath

    XMLWordPrintable

Details

    • generic
    • generic

    Description

      A DESCRIPTION OF THE PROBLEM :
      Recently I've observed a strange behavior of the Java Compiler obtained from "ToolProvider.getSystemJavaCompiler()".

      * If I try to parse a not-compilable java file in a "bare" maven project, I can obtain the errors as expected.
      * If I add certain dependencies (I've first observed this when adding log4j), the compiler does not provide any information regarding compiler errors anymore.

      To demonstrate this behavior, I've created an example repository for this: https://github.com/dfuchss/JavaCompilerIsStrange
      During a discussion on StackOverflow (https://stackoverflow.com/questions/72737445/system-java-compiler-behaves-different-depending-on-dependencies-defined-in-mave#) the problem has been identified.
      It seems that the when annotation processing is meant to happen the parser errors are wrapped into a DeferredDiagnosticHandler but are not transferred to the original DiagnosticHandler.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Use JavacTask#parse() to parse an not compilable java code.
      2. Use a DiagnosticCollector to collect the issues during parsing
      3. Add some library (I've tested that with org.apache.logging.log4j:log4j-core:2.17.2 and org.kohsuke.metainf-services:metainf-services:1.9) to the classpath
      4. After adding the library, you won't get any error after parsing

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The same errors shall be collected.
      ACTUAL -
      No errors are collected during the parse process.

      ---------- BEGIN SOURCE ----------
      See https://github.com/dfuchss/JavaCompilerIsStrange

      Example.java:

      public class Example {

      public static void main(String[] args) {
      System.out.println("Hello World!")

      for(int i = 0; i < 10; i++) {
      System.out.println("Number is " + i);
      }
      }

      }

      Main.java:

      package org.fuchss;

      import com.sun.source.tree.CompilationUnitTree;
      import com.sun.source.tree.LineMap;
      import com.sun.source.util.JavacTask;
      import com.sun.source.util.SourcePositions;
      import com.sun.source.util.Trees;

      import javax.tools.DiagnosticCollector;
      import javax.tools.JavaCompiler;
      import javax.tools.StandardJavaFileManager;
      import javax.tools.ToolProvider;
      import java.io.File;
      import java.io.IOException;
      import java.nio.charset.StandardCharsets;
      import java.util.Collections;
      import java.util.List;

      public class Main {
      public static void main(String[] args) throws Exception {

      var javac = ToolProvider.getSystemJavaCompiler();
      var listener = new DiagnosticCollector<>();

      try (final StandardJavaFileManager fileManager = javac.getStandardFileManager(listener, null, StandardCharsets.UTF_8)) {
      var javaFiles = fileManager.getJavaFileObjectsFromFiles(List.of(new File("src/main/resources/Example.java")));

      final JavaCompiler.CompilationTask task = javac.getTask(null, fileManager, listener, null, null, javaFiles);
      final Trees trees = Trees.instance(task);
      final SourcePositions positions = trees.getSourcePositions();
      for (final CompilationUnitTree ast : executeCompilationTask(task)) {
      final String filename = ast.getSourceFile().getName();
      final LineMap map = ast.getLineMap();

      // TODO Do something here ..
      // ast.accept(...);
      }
      }

      for (var errors : listener.getDiagnostics())
      System.out.println(errors);

      if (listener.getDiagnostics().isEmpty())
      throw new Error("Shall not be possible to compile.");
      }

      private static Iterable<? extends CompilationUnitTree> executeCompilationTask(final JavaCompiler.CompilationTask task) {
      Iterable<? extends CompilationUnitTree> abstractSyntaxTrees = Collections.emptyList();
      try {
      abstractSyntaxTrees = ((JavacTask) task).parse();
      // ((JavacTask) task).analyze();
      } catch (IOException exception) {
      exception.printStackTrace();
      }
      return abstractSyntaxTrees;
      }

      }

      pom.xml (see profiles):
      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>

          <groupId>org.fuchss</groupId>
          <artifactId>strange</artifactId>
          <version>1.0-SNAPSHOT</version>
          <dependencies>
              <dependency>
                  <groupId>org.junit.jupiter</groupId>
                  <artifactId>junit-jupiter-engine</artifactId>
                  <version>5.8.2</version>
                  <scope>test</scope>
              </dependency>
          </dependencies>
          <build>
              <plugins>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-surefire-plugin</artifactId>
                      <version>3.0.0-M7</version>
                  </plugin>
              </plugins>
          </build>

          <properties>
              <maven.compiler.source>11</maven.compiler.source>
              <maven.compiler.target>11</maven.compiler.target>
          </properties>

          <profiles>
              <profile>
                  <id>strange</id>
                  <activation>
                      <activeByDefault>false</activeByDefault>
                  </activation>
                  <dependencies>
                      <dependency>
                          <groupId>org.kohsuke.metainf-services</groupId>
                          <artifactId>metainf-services</artifactId>
                          <version>1.9</version>
                      </dependency>
                  </dependencies>
              </profile>
          </profiles>
      </project>
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      As mentioned in StackOverflow, you can disable the annotation processing:

      final JavaCompiler.CompilationTask task = javac.getTask(
           null, fileManager, listener, List.of("-proc:none"), null, javaFiles
      );

      FREQUENCY : always


      Attachments

        Activity

          People

            jlahoda Jan Lahoda
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated: