Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong version of transitive Maven dependency included in build #37620

Closed
neon-dev opened this issue Dec 8, 2023 · 9 comments
Closed

Wrong version of transitive Maven dependency included in build #37620

neon-dev opened this issue Dec 8, 2023 · 9 comments
Labels
area/maven kind/bug Something isn't working

Comments

@neon-dev
Copy link
Contributor

neon-dev commented Dec 8, 2023

Describe the bug

Apache poi-ooxml 5.2.5 requires commons-compress 1.25.0
Quarkus 3.6.1 requires commons-compress 1.24.0
When building the project, 1.24.0 is included and the project only breaks at runtime when trying to call affected methods.

Expected behavior

Writing a POI workbook should work.

Actual behavior

Trying to write a POI workbook fails with the following error:

java.lang.NoSuchMethodError: 'void org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream.putArchiveEntry(org.apache.commons.compress.archivers.zip.ZipArchiveEntry)'
	at org.apache.poi.openxml4j.opc.internal.ZipContentTypeManager.saveImpl(ZipContentTypeManager.java:65)
	at org.apache.poi.openxml4j.opc.internal.ContentTypeManager.save(ContentTypeManager.java:450)
	at org.apache.poi.openxml4j.opc.ZipPackage.saveImpl(ZipPackage.java:608)
	at org.apache.poi.openxml4j.opc.OPCPackage.save(OPCPackage.java:1532)
	at org.apache.poi.openxml4j.opc.OPCPackage.close(OPCPackage.java:506)
	at org.apache.poi.ooxml.POIXMLDocument.close(POIXMLDocument.java:189)
	at org.apache.poi.xssf.usermodel.XSSFWorkbook.close(XSSFWorkbook.java:640)

How to Reproduce?

  1. Get and extract reproducer.zip
  2. Run it via mvn quarkus:dev

Output of uname -a or ver

No response

Output of java -version

OpenJDK Runtime Environment Temurin-21.0.1+12 (build 21.0.1+12-LTS)

Quarkus version or git rev

3.6.1

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

This is not the first time I experienced such issues. Last time was on Quarkus 3.5 when trying to include commons-text 1.11.0, causing similar runtime errors due to version conflicts with transitive dependency of commons-lang3.

I could not figure out how to force the correct version in the pom.xml. IntelliJ's dependency analysis doesn't even show conflicts and instead claims that the poi-ooxml requires exactly the same version of commons-compress that Quarkus requires, which is wrong (and changes once you comment out all quarkus dependencies).
Any help would be greatly appreciated! Hopefully such issues can be detected at compile time in the future.

@neon-dev neon-dev added the kind/bug Something isn't working label Dec 8, 2023
Copy link

quarkus-bot bot commented Dec 8, 2023

/cc @quarkusio/devtools (maven)

@gastaldi
Copy link
Contributor

gastaldi commented Dec 8, 2023

This is fixed in #37187. I've marked to backport it to 3.6

@gastaldi gastaldi closed this as completed Dec 8, 2023
@gastaldi
Copy link
Contributor

gastaldi commented Dec 8, 2023

To avoid such errors, make sure the expected version is declared BEFORE everything else in your project's <dependencyManagement>

@gastaldi
Copy link
Contributor

gastaldi commented Dec 8, 2023

Also, to avoid future POI incompatibilities, use the quarkus-poi extension instead: https://docs.quarkiverse.io/quarkus-poi/dev/index.html

@neon-dev
Copy link
Contributor Author

neon-dev commented Dec 8, 2023

Also, to avoid future POI incompatibilities, use the quarkus-poi extension instead: https://docs.quarkiverse.io/quarkus-poi/dev/index.html

Thank you, I was not aware of this extension!

To avoid such errors, make sure the expected version is declared BEFORE everything else in your project's <dependencyManagement>

This unfortunately does not work in such cases. Therefore I hoped you could introduce compile time checks or anything really. Maven does not seem to be aware of any conflicts and always uses what Quarkus ships with.
Only if I manually define the transitive dependency in the pom.xml can I control what version to include.

@gastaldi
Copy link
Contributor

gastaldi commented Dec 8, 2023

Maven does not seem to be aware of any conflicts and always uses what Quarkus ships with.

That is not really accurate: Maven decides what library to use depending on how close it is to the dependency tree: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#transitive-dependencies

@neon-dev
Copy link
Contributor Author

neon-dev commented Dec 8, 2023

Could you provide a working example for reference of how to avoid such issues from the start?
This does not work:

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.acme</groupId>
  <artifactId>code-with-quarkus</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <properties>
    <compiler-plugin.version>3.11.0</compiler-plugin.version>
    <maven.compiler.release>21</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
    <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
    <quarkus.platform.version>3.6.1</quarkus.platform.version>
    <skipITs>true</skipITs>
    <surefire-plugin.version>3.1.2</surefire-plugin.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>5.2.5</version>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>${quarkus.platform.group-id}</groupId>
        <artifactId>${quarkus.platform.artifact-id}</artifactId>
        <version>${quarkus.platform.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <build>
    <plugins>
      <plugin>
        <groupId>${quarkus.platform.group-id}</groupId>
        <artifactId>quarkus-maven-plugin</artifactId>
        <version>${quarkus.platform.version}</version>
        <extensions>true</extensions>
        <executions>
          <execution>
            <goals>
              <goal>build</goal>
              <goal>generate-code</goal>
              <goal>generate-code-tests</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${compiler-plugin.version}</version>
        <configuration>
          <compilerArgs>
            <arg>-parameters</arg>
          </compilerArgs>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${surefire-plugin.version}</version>
        <configuration>
          <systemPropertyVariables>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
            <maven.home>${maven.home}</maven.home>
          </systemPropertyVariables>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>${surefire-plugin.version}</version>
        <executions>
          <execution>
            <goals>
              <goal>integration-test</goal>
              <goal>verify</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <systemPropertyVariables>
            <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
            <maven.home>${maven.home}</maven.home>
          </systemPropertyVariables>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Including a transitive dependency of course fixes current conflicts, but doesn't protect against future conflicts with other depenencies.

@gastaldi
Copy link
Contributor

gastaldi commented Dec 8, 2023

There is no magic solution. In this case, if you want to force commons-compress 1.25.0, you just explicitly add the dependency declaration before the Quarkus BOM:

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.acme</groupId>
  <artifactId>code-with-quarkus</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <properties>
    <compiler-plugin.version>3.11.0</compiler-plugin.version>
    <maven.compiler.release>21</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
    <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
    <quarkus.platform.version>3.6.1</quarkus.platform.version>
    <skipITs>true</skipITs>
    <surefire-plugin.version>3.1.2</surefire-plugin.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>5.2.5</version>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <dependencyManagement>
    <dependencies>
      <!-- This forces the project to use the correct version -->
      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-compress</artifactId>
          <version>1.25.0</version>
      </dependency>
      <dependency>
        <groupId>${quarkus.platform.group-id}</groupId>
        <artifactId>${quarkus.platform.artifact-id}</artifactId>
        <version>${quarkus.platform.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <build>
    <plugins>
      <plugin>
        <groupId>${quarkus.platform.group-id}</groupId>
        <artifactId>quarkus-maven-plugin</artifactId>
        <version>${quarkus.platform.version}</version>
        <extensions>true</extensions>
        <executions>
          <execution>
            <goals>
              <goal>build</goal>
              <goal>generate-code</goal>
              <goal>generate-code-tests</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${compiler-plugin.version}</version>
        <configuration>
          <compilerArgs>
            <arg>-parameters</arg>
          </compilerArgs>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${surefire-plugin.version}</version>
        <configuration>
          <systemPropertyVariables>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
            <maven.home>${maven.home}</maven.home>
          </systemPropertyVariables>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>${surefire-plugin.version}</version>
        <executions>
          <execution>
            <goals>
              <goal>integration-test</goal>
              <goal>verify</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <systemPropertyVariables>
            <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
            <maven.home>${maven.home}</maven.home>
          </systemPropertyVariables>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

@neon-dev
Copy link
Contributor Author

neon-dev commented Dec 8, 2023

Thank you for the quick help, I really appreciate it!
So we unfortunately cannot easily detect conflicts beforehand. Running mvn dependency:tree -Dverbose shows +- org.apache.commons:commons-compress:jar:1.24.0:compile (version managed from 1.25.0) which does not really scream "we have a problem here".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/maven kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants