DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • A Spring Boot App With Half the Startup Time
  • Alternative Structured Concurrency
  • Comparing Top 3 Java Reporting Tools
  • Optimizing Java Applications for Arm64 in the Cloud

Trending

  • The Rise of Agentic SRE: Humans, Agents, and Reliability
  • Real-World Problems Being Solved by Java
  • The Observability Gap: Why Your Monitoring Strategy Isn't Ready for What's Coming Next
  • WebSockets, gRPC, and GraphQL in the Core
  1. DZone
  2. Coding
  3. Java
  4. I Built a Java Version Manager by Fixing Other Tools' Open Bugs

I Built a Java Version Manager by Fixing Other Tools' Open Bugs

There is no point in shipping another Java Version Manager unless it is best in class, so I mined the test suites and bug trackers of SDKMAN, jenv, mise, volta, and asdf.

By 
David Lerner user avatar
David Lerner
·
Aug. 04, 26 · Analysis
Likes (0)
Comment
Save
Tweet
Share
59 Views

Join the DZone community and get the full member experience.

Join For Free

Every Java developer knows the ritual. A JAVA_HOME export in one profile file, a different one in another. sdk use java 21 in this terminal, but the other terminal is still on 8. The build passes in your shell and fails in the IDE because the IDE launched from the dock and never sourced your init line. A teammate's "works on my machine" that turns out to mean "works on my shell."

I got tired of it, so I built Jolta. It's Volta, but for Java. This article is partly about what it does, but mostly about how I built it, because the process is the part I'd recommend to anyone building in a crowded tool category: I mined my competitors' bug trackers and turned their backlogs into my test suite.

The Pitch, in a Paragraph

With Jolta, you never think about Java versions again (if you don't want to). brew install, jolta setup, done. Now cd into any project and java, javac, Maven, Gradle, your IDE's run button, git hooks, and CI scripts all use the right JDK for that directory, including on a fresh machine where the pinned JDK isn't installed yet (it fetches it on first use). There's no sdk use, no jenv add, no remembering to switch back. The pin is a plain .java-version file you commit, and it's authoritative everywhere a process can be launched from.

The Tech, Briefly

Jolta is a single static Rust binary whose shims are the resolver. Each shim (java, javac, jar, and the rest of the JDK toolset) is a symlink back to the binary. Every invocation walks up from its own working directory to the nearest .java-version, picks a JDK from anything on the machine (Jolta's own installs, Homebrew, /Library/Java, the JAVA_HOME_17_X64-style variables CI images set), exports JAVA_HOME, and execs the real tool. Overhead is about two milliseconds.

Two design consequences matter more than any feature list. First, there are no shell hooks and no per-shell state, so nothing can go stale. Resolution happens inside the process launch itself, which is why IDEs, cron jobs, and CI steps get the right JDK without any setup. Second, JAVA_HOME is set per-invocation by the shim, so Maven and Gradle daemons, which read JAVA_HOME directly, can't escape it.

That second point is an architectural difference, not a quality difference. SDKMAN is shell functions by construction: sdk use mutates the current interactive shell, and that model cannot follow a subprocess into a directory with a different pin. jenv shims per-invocation, but its JAVA_HOME comes from a shell plugin that runs at prompt time; keeping it truthful is its longest-running open issue (jenv #232).

The Interesting Part: Building a Test Suite From Other People's Backlogs

This is the part worth stealing.

Version managers are a mature category. volta, jenv, SDKMAN, mise, and asdf have collectively accumulated a decade of bug reports, each one a user hitting an edge case, already triaged and written up for free. So before writing much code, I mined them in three passes:

  1. Their test suites first. Whatever volta asserts in tests/acceptance, whatever jenv checks in its bats files, whatever SDKMAN specs: all of it became conformance cases. If a competitor thought a behavior was worth pinning, it probably is.
  2. Then their closed issues. Every fixed bug is an edge case that shipped to users at least once. Each one became a regression test before Jolta could exhibit it.
  3. Then their open issues. This is the fun part: bugs that are reported, confirmed, and still sitting in a backlog. I fixed them proactively, in a tool where they'd never been reported because they'd never shipped.

A few concrete examples of what that mining caught:

Upstream issue The bug What Jolta does instead
mise #9679 A wrong-architecture/wrong-libc JDK "installs" cleanly, then every run dies in the loader with a cryptic error An exec probe at install time: the JVM must actually run before the install is promoted
mise #1887 A bare GA release ("21") shadows newer point builds (21.0.x) in resolution Numeric version keys; a major pin always resolves to the highest satisfying build
mise #6907 An early-access build silently satisfies a GA pin (or vice versa) EA and GA are gated: an -ea spec matches only EA, GA specs prefer GA
volta #1183 A stray directory at a shim path silently blocks that shim forever The shims directory is wholly owned and cleared entry-by-entry on every reshim
volta #2075 Downloads aren't checksum-verified Sidecar SHA-256 verification, including for offline mirrors
jenv #294 Shimming a bundled runtime (GraalVM ships node) hijacks the user's other version managers Bundled language runtimes are deliberately never shimmed
jenv #232 JAVA_HOME goes stale and Maven/Gradle bypass the manager Per-invocation JAVA_HOME from the shim, plus a doctor that names exactly what's shadowing what


The result is a suite of 300+ regression tests, dozens of them pinned to issues that are still open in other tools' trackers. When someone asks what Jolta does that the others fundamentally can't, this is half the answer: it can't not have these bugs, because they're in CI.

The method generalizes. If you're building anything in a category with incumbents, their issue tracker is a prioritized specification of everything hard about the domain, written by your future users. Read it before you write your architecture.

If You Do Care What Java You're Running

Jolta is fully featured to let you customize your Java versions until your heart is content.  Jolta downloads and manages eight distributions (Temurin, Corretto, GraalVM, Oracle, Zulu, Liberica, SapMachine, GraalVM CE) and recognizes twelve for pinning. You can set a preferred vendor: a Corretto shop that pins 11 gets Corretto 11.0.31 even when a higher Temurin build is installed, because vendor preference should beat build-number greed. Exact pins mean exact: 21.0.2 is never quietly satisfied by a neighboring build, and auto-install fetches that exact build. .sdkmanrc files work out of the box for teams migrating. There's an offline mirror mode for air-gapped CI, first-class Windows support (hard-link shims, PowerShell hook, no Developer Mode required), and a jolta doctor whose exit code is the verdict.

What It Doesn't Do

Jolta manages JDKs, period. SDKMAN also manages Maven, Gradle, and Kotlin; mise manages your whole polyglot toolchain. If you want one tool for node + python + java, use mise. It's good. Jolta's bet is narrower: that Java version switching should be correct from every entry point and invisible the rest of the time.

Try It

Shell
 
brew install OneAppPlatform/tap/jolta
jolta setup


The curl one-liner and Windows instructions are in the README.

In every category I could find, I tried to make this version manager best in class. Give it a try and tell me if I hit my mark.

Java Development Kit Tool Java (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • A Spring Boot App With Half the Startup Time
  • Alternative Structured Concurrency
  • Comparing Top 3 Java Reporting Tools
  • Optimizing Java Applications for Arm64 in the Cloud

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook