Add JDK management with Foojay Disco API integration
๐ JDK Management for Maven Wrapper
This PR adds comprehensive JDK management capabilities to Maven Wrapper using the Foojay Disco API, enabling automatic JDK download and installation for the only-script distribution type.
โจ Key Features
๐ฏ Automatic JDK Management
- Automatic JDK download and installation for
only-scriptdistribution - 34+ JDK distributions supported via Foojay Disco API
- Version resolution: Major versions (e.g.,
17) resolve to latest patch versions - Multi-platform support: Linux, macOS, Windows with architecture detection
- Toolchain integration: Automatic
toolchains.xmlgeneration for multi-JDK builds - Dynamic LTS detection: Uses Disco API to identify LTS versions (no hardcoded heuristics)
- Bypass option:
MVNW_SKIP_JDKenvironment variable to use system JDK
๐ง Configuration Options
# Basic JDK configuration
jdkVersion=17
jdkDistribution=temurin
# Toolchain JDK for multi-version builds
toolchainJdkVersion=11
toolchainJdkDistribution=corretto
# Update policies
jdkUpdatePolicy=daily # never, daily, weekly, monthly, always, interval:X
# Direct URLs (optional)
jdkDistributionUrl=https://example.com/jdk.tar.gz
jdkSha256Sum=abc123...
๐ Environment Variables
# Skip JDK management and use system JDK
export MVNW_SKIP_JDK=true
# Enable verbose output
export MVNW_VERBOSE=true
# Configure JDK settings
export MAVEN_WRAPPER_JDK_VERSION=17
export MAVEN_WRAPPER_JDK_DISTRIBUTION=temurin
๐ฆ Supported Distributions
Popular Distributions:
temurin- Eclipse Adoptium (default)corretto- Amazon Correttozulu- Azul Zululiberica- BellSoft Libericaoracle_open_jdk- Oracle OpenJDKmicrosoft- Microsoft OpenJDKsemeru- IBM Semeru
Specialized Distributions:
graalvm_ce11,graalvm_ce17- GraalVM Community Editionsap_machine- SAP Machinedragonwell- Alibaba Dragonwelljetbrains- JetBrains Runtimebisheng- Huawei BiShengkona- Tencent Konamandrel- Red Hat Mandrel
Complete list: Foojay Disco API
๐ ๏ธ Usage Examples
Maven Plugin
# Generate wrapper with JDK management
mvn wrapper:wrapper -Dtype=only-script -Djdk=17 -DjdkDistribution=temurin
# With toolchain support
mvn wrapper:wrapper -Dtype=only-script -Djdk=21 -DjdkDistribution=corretto -DtoolchainJdk=17 -DtoolchainJdkDistribution=temurin
Properties Configuration
# Production: Pin exact version
jdkVersion=17.0.14
jdkDistribution=temurin
jdkUpdatePolicy=never
# Development: Auto-update to latest patches
jdkVersion=17
jdkDistribution=temurin
jdkUpdatePolicy=daily
Bypassing JDK Management
# Use system JDK instead of wrapper-managed JDK
export MVNW_SKIP_JDK=true
./mvnw clean compile
# Windows
set MVNW_SKIP_JDK=true
mvnw.cmd clean compile
# Useful for CI matrix testing
MVNW_SKIP_JDK=true ./mvnw test
Multi-JDK Toolchain Setup
# Main JDK for build
jdkVersion=21
jdkDistribution=temurin
# Toolchain JDK for compilation
toolchainJdkVersion=17
toolchainJdkDistribution=corretto
๐๏ธ Implementation Details
Architecture
- Shell-based implementation for
only-scriptdistribution type - No Java dependency for JDK installation (avoids chicken-and-egg problem)
- Foojay Disco API integration for JDK resolution and download
- Cross-platform support with native shell scripts (Unix) and PowerShell (Windows)
- API URL constants for maintainability and easy version updates
Dynamic LTS Detection
- Real-time LTS detection via Disco API
/major_versionsendpoint - Intelligent caching to avoid repeated API calls
- Robust fallback to hardcoded LTS list if API unavailable
- Accurate warnings showing current LTS versions (6, 7, 8, 11, 17, 21)
- Future-proof - automatically includes new LTS versions when released
Distribution Validation
- Comprehensive validation against known Disco API distributions
- Helpful error messages showing all available distributions
- Typo prevention with clear distribution suggestions
Bypass Mechanisms
- MVNW_SKIP_JDK: Skip JDK management entirely, use system JDK
- Direct URLs: Override version/distribution resolution with exact URLs
- Environment variables: Configure JDK settings without modifying properties
Caching & Performance
- Intelligent caching with configurable update policies
- SHA-256 verification for security
- Efficient downloads with resume support
- Version resolution caching to minimize API calls
Security Features
- HTTPS downloads by default
- SHA-256 checksum verification for all downloads
- Automatic checksum resolution from Disco API
- Manual checksum override for direct URLs
๐ฏ Benefits
For Developers
- Zero JDK setup - automatic download and installation
- Consistent environments across team members
- Easy distribution switching for testing
- Toolchain support for multi-JDK projects
- Accurate LTS guidance with real-time data
- Flexible bypass options for special cases
For CI/CD
- Reproducible builds with exact version pinning
- No pre-installed JDK requirement in build environments
- Flexible update policies for different environments
- Multi-platform consistency
- Matrix testing support with MVNW_SKIP_JDK
For Projects
- Simplified onboarding - no JDK installation instructions needed
- Version consistency across all environments
- Easy JDK upgrades via configuration changes
- Professional distribution support (34+ options)
- Troubleshooting options with bypass mechanisms
๐ Migration Path
Existing projects can easily adopt JDK management:
- Switch to
only-scriptdistribution type - Add JDK configuration to
maven-wrapper.properties - Remove manual JDK setup from documentation
- Enjoy automatic JDK management
# Simple migration command
mvn wrapper:wrapper -Dtype=only-script -Djdk=17 -DjdkDistribution=temurin
๐งช Testing
- โ Cross-platform testing (Linux, macOS, Windows)
- โ Multiple JDK distributions verified
- โ Version resolution tested (major โ patch versions)
- โ Toolchain integration validated
- โ Error handling and validation tested
- โ Caching and update policies verified
- โ Dynamic LTS detection confirmed with API
- โ MVNW_SKIP_JDK bypass functionality tested
๐ Documentation
Comprehensive documentation added:
- JDK_MANAGEMENT.md - Complete feature guide
- Configuration examples for all use cases
- Environment variable documentation
- Troubleshooting guide for common issues
- Migration instructions for existing projects
- MVNW_SKIP_JDK usage examples
๐ Summary
This PR transforms Maven Wrapper into a complete JDK management solution that:
- Eliminates JDK setup friction for developers
- Ensures consistent environments across teams
- Supports 34+ professional JDK distributions
- Provides flexible configuration options for all use cases
- Maintains security with checksum verification
- Offers excellent performance with intelligent caching
- Uses dynamic LTS detection with real-time API data
- Requires zero maintenance for future JDK versions
- Includes bypass mechanisms for special cases and troubleshooting
The implementation is production-ready, well-tested, and thoroughly documented, making it easy for projects to adopt automatic JDK management while maintaining flexibility for edge cases.
Whoa .. thats amazing!
Is my understanding correct that the mvnw script now downloads and installs a JDK distrubution instead of using the system JDK?
Is my understanding correct that the
mvnwscript now downloads and installs a JDK distrubution instead of using the system JDK?
That's not completely exact. The JDK download is an opt-in if you add the required properties. The default behaviour is unchanged. There's also a MVNW_SKIP_JDK env var to skip using the JDK indicated by those properties (can be useful when running in a JDK matrix in a CI job).
Is my understanding correct that the
mvnwscript now downloads and installs a JDK distrubution instead of using the system JDK?That's not completely exact. The JDK download is an opt-in if you add the required properties. The default behaviour is unchanged. There's also a
MVNW_SKIP_JDKenv var to skip using the JDK indicated by those properties (can be useful when running in a JDK matrix in a CI job).
Ok, thanks! I was concerned that the default behavior was changing and users would have to explicitly opt-out to prevent it.
Currently broken by https://github.com/foojayio/discoapi/issues/124
To confirm my understanding: if we add the new JDK properties into .mvn/wrapper/maven-wrapper.properties, but then set the MVNW_SKIP_JDK=true env variable, mvnw will use the system JDK as always and not attempt to download a JDK?
To confirm my understanding: if we add the new JDK properties into
.mvn/wrapper/maven-wrapper.properties, but then set theMVNW_SKIP_JDK=trueenv variable,mvnwwill use the system JDK as always and not attempt to download a JDK?
Correct
To confirm my understanding: if we add the new JDK properties into
.mvn/wrapper/maven-wrapper.properties, but then set theMVNW_SKIP_JDK=trueenv variable,mvnwwill use the system JDK as always and not attempt to download a JDK?Correct
Perfect, thanks! This sounds like a great feature which we can use with our dev team to allow easy bootstrapping of the preferred JDK distribution on their workstations, whilst continuing to have our Github Actions CI pipelines use the system provided JDK.
Exciting feature!
@gnodet
is it possible to support the .java-version file for defining the default JDK version of a project? It is normally generated by jenv to lock a project local JDK.
#Useful for CI matrix testing MVNW_SKIP_JDK=true ./mvnw test
@gnodet how about to support selecting dynamicly JDK version via an environment, then the mvnw can pin almost the jdk matrix by project.
#Useful for CI matrix testing MVNW_SKIP_JDK=true ./mvnw test@gnodet how about to support selecting dynamicly JDK version via an environment, then the mvnw can pin almost the jdk matrix by project.
I've added env vars to override the JDK properties.
#Useful for CI matrix testing MVNW_SKIP_JDK=true ./mvnw test@gnodet how about to support selecting dynamicly JDK version via an environment, then the mvnw can pin almost the jdk matrix by project.
I've added env vars to override the JDK properties.
should we make all the env vars all has the same prefix MVNW_
I'm not on the committers list, but this looks like fantastic new feature! :)
#Useful for CI matrix testing MVNW_SKIP_JDK=true ./mvnw test@gnodet how about to support selecting dynamicly JDK version via an environment, then the mvnw can pin almost the jdk matrix by project.
I've added env vars to override the JDK properties.
should we make all the env vars all has the same prefix
MVNW_
They do AFAIK, did I miss something ?
#Useful for CI matrix testing MVNW_SKIP_JDK=true ./mvnw test@gnodet how about to support selecting dynamicly JDK version via an environment, then the mvnw can pin almost the jdk matrix by project.
I've added env vars to override the JDK properties.
should we make all the env vars all has the same prefix
MVNW_They do AFAIK, did I miss something ?
maven-wrapper-plugin/src/it/projects/jdk_environment_variables/pom.xml left some MAVEN_WRAPPER_
It's a great feature. Maybe we shouldn't download some binaries per default but ask the user before downloading the idk?
It's a great feature. Maybe we shouldn't download some binaries per default but ask the user before downloading the idk?
Not sure to understand. The default behaviour is unchanged, in order to have the JDK downloaded, the user needs to opt-in and add the needed properties, which will trigger the JDK download, same as the wrapper downloads the Maven distribution. This can be opt-out using env-var too. You would like an additional confirmation before actually downloading the JDK or the maven distribution ?
It's a great feature. Maybe we shouldn't download some binaries per default but ask the user before downloading the idk?
Not sure to understand. The default behaviour is unchanged, in order to have the JDK downloaded, the user needs to opt-in and add the needed properties, which will trigger the JDK download, same as the wrapper downloads the Maven distribution. This can be opt-out using env-var too. You would like an additional confirmation before actually downloading the JDK or the maven distribution ?
I don't mind for Maven because it's Maven :) but for jdk is a different (we do not maintain and we don't even know what is the license) maybe it would be better to have additional confirmation (can be disable eventually by the generator of the script)
I just tried this:
mvn org.apache.maven.plugins:maven-wrapper-plugin:3.3.3-SNAPSHOT:wrapper -Dtype=only-script -Djdk=17 -DjdkDistribution=temurin
Now if I push the generated script any user of the opensource project where I did that will have automatic download of a jdk binaries.
Great feature! From a user perspective (especially if I wear the Enterprise and not the Open Source Developer one) I have few things:
- Do you plan to release this feature a new major version of Maven Wrapper? I consider this a major change (although not necessarily breaking) since the default behaviour changes and the user has to opt-out using
MVNW_SKIP_JDK. That is, a simple update of Maven Wrapper should need cause me to suddently have a bunch of JDK installed without my knowledge (especially, since we use SDKMan already). - Is there a way that this could be integrated with SDKMan for users that want that?
- Have you considered security concerns with the distribution url? A person might check the source code, the POM etc for security stuff but fail to understand the implication of a distibution url that leads to a malicious JDK? I reckon if you use jdkDistribution then it uses the Foojay Disco API which seems to be some sort of assurance of the integrity of that JDK.
- Have you considered security concerns with the distribution url? A person might check the source code, the POM etc for security stuff but fail to understand the implication of a distibution url that leads to a malicious JDK? I reckon if you use jdkDistribution then it uses the Foojay Disco API which seems to be some sort of assurance of the integrity of that JDK.
Isn't the fact that you can pin the SHA-256 hash via the jdkSha256Sum property cover the security perspectives?
- Have you considered security concerns with the distribution url? A person might check the source code, the POM etc for security stuff but fail to understand the implication of a distibution url that leads to a malicious JDK? I reckon if you use jdkDistribution then it uses the Foojay Disco API which seems to be some sort of assurance of the integrity of that JDK.
Isn't the fact that you can pin the SHA-256 hash via the
jdkSha256Sumproperty cover the security perspectives?
No. That only verifies that the file specified in the properties file is the file that you actually downloaded. It does not provide any "security guarantees" of that JDK.
E.g.
# Direct URLs (optional)
jdkDistributionUrl=https://hackers.com/jdk_that_has_malicous_code.tar.gz
jdkSha256Sum=<a valid sha256 sum for that tarball>.
This can of course be said for regular dependencies as well. The difference here is that users are used to dependencies they're not used to a random JDK being pulled in without their knowledge.
And there tends to be infrastructure (at least from an Enterprise perspective) to scan dependencies for CVEs etc which jdkDistributionUrl would completely circumvent.
Just to be clear, I'm not against the jdkDistributionUrl - it might be useful. But, when it is used the user should be made aware (read: warned about security risks) and then actively have to approve it (which can be explicitly pre-approved using a command line option or similar).
No. That only verifies that the file specified in the properties file is the file that you actually downloaded. It does not provide any "security guarantees" of that JDK.
E.g.
# Direct URLs (optional) jdkDistributionUrl=https://hackers.com/jdk_that_has_malicous_code.tar.gz jdkSha256Sum=<a valid sha256 sum for that tarball>.This can of course be said for regular dependencies as well. The difference here is that users are used to dependencies they're not used to a random JDK being pulled in without their knowledge.
And there tends to be infrastructure (at least from an Enterprise perspective) to scan dependencies for CVEs etc which
jdkDistributionUrlwould completely circumvent.
I sort of surprised that an enterprise that is that particular about security would use maven-wrapper in the first place, but to each their own. ๐คทโโ๏ธ
Great feature! From a user perspective (especially if I wear the Enterprise and not the Open Source Developer one) I have few things:
- Do you plan to release this feature a new major version of Maven Wrapper? I consider this a major change (although not necessarily breaking) since the default behaviour changes and the user has to opt-out using
MVNW_SKIP_JDK. That is, a simple update of Maven Wrapper should need cause me to suddently have a bunch of JDK installed without my knowledge (especially, since we use SDKMan already).
Not really because the default behaviour DOES NOT change. You have to first opt-in and specify the JDK version. Once you have opted-in, you can then opt-out with MVNW_SKIP_JDK.
- Is there a way that this could be integrated with SDKMan for users that want that?
Not sure. That was really my first attempt. Unfortunately, sdkman does not keep track of old releases, which is a problem from a reproducibility pov.
- Have you considered security concerns with the distribution url? A person might check the source code, the POM etc for security stuff but fail to understand the implication of a distibution url that leads to a malicious JDK? I reckon if you use jdkDistribution then it uses the Foojay Disco API which seems to be some sort of assurance of the integrity of that JDK.
I agree with Jeremy here. A simple to secure things is to use an exact url + sha256.
If you want to keep some versatility, another way would be to be able to provide an alternative REST endpoint that could be implemented within an entreprise. At runtime, only https://api.foojay.io/disco/v3.0/packages is actually used. So an env var could specify a REST endpoint different than the default https://api.foojay.io/disco/v3.0.
I sort of surprised that an enterprise that is that particular about security would use maven-wrapper in the first place, but to each their own. ๐คทโโ๏ธ
It's not a matter of Enterprise or not. When I develop on my spare time I don't necessarily want to have a bunch of JDKs downloaded to my computer without my knowledge.
- Do you plan to release this feature a new major version of Maven Wrapper? I consider this a major change (although not necessarily breaking) since the default behaviour changes and the user has to opt-out using
MVNW_SKIP_JDK. That is, a simple update of Maven Wrapper should need cause me to suddently have a bunch of JDK installed without my knowledge (especially, since we use SDKMan already).Not really because the default behaviour DOES NOT change. You have to first opt-in and specify the JDK version. Once you have opted-in, you can then opt-out with
MVNW_SKIP_JDK.
Maybe I'm missing something here. Who is that has to opt-in?
If I download an open source project that uses Maven Wrapper and then run it with mvnw do I have to opt-in for the download of a JDK (jdkDistribution/jdkDistributionUrl) to be enabled?
- Is there a way that this could be integrated with SDKMan for users that want that?
Not sure. That was really my first attempt. Unfortunately, sdkman does not keep track of old releases, which is a problem from a reproducibility pov.
Agreed. Yes, it is.
- Have you considered security concerns with the distribution url? A person might check the source code, the POM etc for security stuff but fail to understand the implication of a distibution url that leads to a malicious JDK? I reckon if you use jdkDistribution then it uses the Foojay Disco API which seems to be some sort of assurance of the integrity of that JDK.
I agree with Jeremy here. A simple to secure things is to use an exact url + sha256.
See my use-case above. I don't see how an exact url and an sha256 in an open source project's maven-wrapper.properties helps.
If you want to keep some versatility, another way would be to be able to provide an alternative REST endpoint that could be implemented within an entreprise. At runtime, only
https://api.foojay.io/disco/v3.0/packagesis actually used. So an env var could specify a REST endpoint different than the defaulthttps://api.foojay.io/disco/v3.0.
Yes, I saw that that was added. But, I don't think that it's relevant to the security use-case I wrote above - unless I miss understood something.
@gnodet After giving this some more though, the feature is great but I'm actually leaning towards that this feature is in the wrong place.
The Maven Wrapper project is just that "it wraps Maven" (and the name implies just that) - not JDKs. What this PR is doing is wrapping the JDK.
I don't think it obvious from a user perspective that a Maven Wrapper also wraps the JDK (and it never will be with that name) and I'm not sure that the two should be mixed. It's convenient but is it the right place?
Perhaps, there needs to be a JDK Wrapper? I get a sense of "virtual environments" with Maven Wrapper and JDK Wrapper. Perhaps, the two should be merged into something new that is not Maven Wrapper?
If I download an open source project that uses Maven Wrapper and then run it with
mvnwdo I have to opt-in for the download of a JDK (jdkDistribution/jdkDistributionUrl) to be enabled?
You could just use your own Maven installation instead of using the projects embedded mvnw script and not have to worry about any of this.
It's not as if the only way to run Maven is via the wrapper...
If I download an open source project that uses Maven Wrapper and then run it with
mvnwdo I have to opt-in for the download of a JDK (jdkDistribution/jdkDistributionUrl) to be enabled?You could just use your own Maven installation instead of using the projects embedded
mvnwscript and not have to worry about any of this. It's not as if the only way to run Maven is via the wrapper...
Yes, I can, but you are missing the point completely.
Maven Wrapper was created so that I would have to think of what Maven version to use with the project.
Simply use mvnw and you're set.
Your "suggestion"/"workaround" is because the original functionality of Maven Wrapper is "broken".
I agree with Jeremy here. A simple to secure things is to use an exact url + sha256.
I do wonder: how would the checksum pining work for multi-arch / multi-OS? Is it possible to specify multiple checksums so that a user could specify checksums for differing build environments (i.e. Windows x64, macOS arm64, Linux x64, etc.)?
I sort of surprised that an enterprise that is that particular about security would use maven-wrapper in the first place, but to each their own. ๐คทโโ๏ธ
It's not a matter of Enterprise or not. When I develop on my spare time I don't necessarily want to have a bunch of JDKs downloaded to my computer without my knowledge.
Then you can easily opt-out by default by adding export MVNW_SKIP_JDK=true in your shell config.