failsafe-lib / failsafe

Fault tolerance and resilience patterns for the JVM
https://failsafe.dev
Apache License 2.0
4.16k stars 295 forks source link

Configure explicit Java module descriptors #359

Closed aalmiray closed 1 year ago

aalmiray commented 1 year ago

Use the ModiTect plugin to add module descriptors while retaining Java 8 compatibility.

Fix for #358

NOTE: The release must be run with Java9+ or else it will fail to generate module descriptors. The CI workflow runs tests with 8, 11, and 17 which is fine as long as the package phase is not invoked.

aalmiray commented 1 year ago
$ jarviz bytecode show --file core/target/failsafe-3.3.1-SNAPSHOT.jar 
subject: failsafe-3.3.1-SNAPSHOT.jar
Unversioned classes. Bytecode version: 52 (Java 8) total: 114
Versioned classes 9. Bytecode version: 53 (Java 9) total: 1

$ jarviz module descriptor --file core/target/failsafe-3.3.1-SNAPSHOT.jar 
subject: failsafe-3.3.1-SNAPSHOT.jar
name: dev.failsafe.core
version: 3.3.1-SNAPSHOT
open: false
automatic: false
exports:
  dev.failsafe
  dev.failsafe.event
  dev.failsafe.function
  dev.failsafe.internal
  dev.failsafe.internal.util
  dev.failsafe.spi
requires:
  java.base mandated

$ jarviz module descriptor --file modules/okhttp/target/failsafe-okhttp-3.3.1-SNAPSHOT.jar 
subject: failsafe-okhttp-3.3.1-SNAPSHOT.jar
name: dev.failsafe.okhttp
version: 3.3.1-SNAPSHOT
open: false
automatic: false
exports:
  dev.failsafe.okhttp
requires:
  dev.failsafe.core
  java.base mandated
  okhttp3

$ jarviz module descriptor --file modules/retrofit/target/failsafe-retrofit-3.3.1-SNAPSHOT.jar 
subject: failsafe-retrofit-3.3.1-SNAPSHOT.jar
name: dev.failsafe.retrofit
version: 3.3.1-SNAPSHOT
open: false
automatic: false
exports:
  dev.failsafe.retrofit
requires:
  dev.failsafe.core
  java.base mandated
  retrofit2
jhalterman commented 1 year ago

Thanks for this @aalmiray. My only comment (above) is wanting to ensure that we don't break 1.8 compatibility.

aalmiray commented 1 year ago

Understood. This is how classes would look like once packaged:

$ jarviz bytecode show --file core/target/failsafe-3.3.1-SNAPSHOT.jar 
subject: failsafe-3.3.1-SNAPSHOT.jar
Unversioned classes. Bytecode version: 52 (Java 8) total: 114
Versioned classes 9. Bytecode version: 53 (Java 9) total: 1

The build was run with Java 11. The single class with bytecode 53 is module-info.class which is placed in the versioned space:

$ unzip -l core/target/failsafe-3.3.1-SNAPSHOT.jar 
Archive:  core/target/failsafe-3.3.1-SNAPSHOT.jar
  Length      Date    Time    Name
---------  ---------- -----   ----
     1359  03-16-2023 08:07   META-INF/MANIFEST.MF
        0  03-16-2023 08:07   META-INF/
        0  03-16-2023 08:07   dev/
        0  03-16-2023 08:07   dev/failsafe/
        0  03-16-2023 08:07   dev/failsafe/internal/
        0  03-16-2023 08:07   dev/failsafe/internal/util/
        0  03-16-2023 08:07   dev/failsafe/function/
        0  03-16-2023 08:07   dev/failsafe/spi/
        0  03-16-2023 08:07   dev/failsafe/event/
        0  03-16-2023 08:07   META-INF/maven/
        0  03-16-2023 08:07   META-INF/maven/dev.failsafe/
        0  03-16-2023 08:07   META-INF/maven/dev.failsafe/failsafe/
     1511  03-16-2023 08:07   dev/failsafe/RateLimiterConfig.class
...
     1845  03-16-2023 08:07   dev/failsafe/Failsafe.class
     1371  03-16-2023 08:07   dev/failsafe/FailurePolicyConfig.class
        0  03-16-2023 08:07   META-INF/versions/
        0  03-16-2023 08:07   META-INF/versions/9/
      319  03-16-2023 08:07   META-INF/versions/9/module-info.class
Tembrel commented 1 year ago

Understood. This is how classes would look like once packaged:

I have had multi-release packaging of other dependencies break my Java 8 builds (of my system that uses Failsafe), not because the multi-release jar was incompatible with Java 8, but because the published pom.xml didn't work well with Apache Ivy.

I have been able to work around this using special Ivy configurations, and would probably be able to figure out how to do the same in this case, but it almsot certainly will be a hit. I want proponents of Java modules to recognize that keeping compatibility is a lot harder than it appears at first blush.

aalmiray commented 1 year ago

Do you happen to know why the pom.xml was not compatible with Ivy? In the case of this PR the change is found inside the <build> section which has no bearing on how dependencies are resolved from a consumer's point of view.

Tembrel commented 1 year ago

I don't know enough about Maven pom files to give an authoritative answer, but here's the line I had to change in my ivy.xml file (for the StreamEx library):

    <dependency org="one.util" name="streamex" rev="0.8.1"/>

This stopped working until I changed it to:

    <dependency org="one.util" name="streamex" rev="0.8.1">
      <!-- Distributed as multi-release-jar; ask for jar explicitly -->
      <artifact name="streamex" type="jar" />
    </dependency>

You could reasonably say that it's not such a big deal, but it took me a long time to figure this out, and until I did, I was shut out of updating to the latest release of StreamEx.

I am reasonably confident that a similar transformation would work if Failsafe goes this route, but I don't know for sure. There are probably others who, for various reasons, are stuck on Java 8 and who don't directly use Maven but depend on its ecosystem.

aalmiray commented 1 year ago

It looks like streamex-0.8.0 explicitly changed its packaging go "multirelease-jar" https://central.sonatype.com/artifact/one.util/streamex/0.8.0 Version 0.8.1 went back to default "jar" packaging.

This was a conscious decision of the author to modify the companion metadata (pom.xml) and has nothing to do with the actual JAR contents.

ModiTect does not alter in any way the chosen packaging, rest assured the fix you had to put in place for streamex was explicit for that version alone.

Tembrel commented 1 year ago

Fingers crossed.

jhalterman commented 1 year ago

Thanks for this @aalmiray! Also, jarviz is a great little tool!

jhalterman commented 1 year ago

This was released in Failsafe 3.3.1.

aalmiray commented 1 year ago

Thank you for merging and releasing 😁