Modernizing legacy code: Staying on track after 30 years of Java

Bryan Friedman
|
August 12, 2025
modernizing legacy java code featured image
Contents

Key Takeaways

Thirty years after its first release, Java remains one of the most widely used languages in enterprise software development. But for large organizations, keeping Java and its frameworks up to date is still one of the hardest challenges in software maintenance.

Upgrading across thousands of repositories, dealing with code drift, closing testing gaps, and hardening CI/CD pipelines can feel like swapping out the tires on a car that’s still on the racetrack. Yet trying to keep racing on worn tires is even riskier. Eventually, something will give—outdated frameworks and libraries can lead to security vulnerabilities, higher operating costs, and missed opportunities to take advantage of new features.

Several sessions at the recent Code Remix Summit highlighted this challenge of keeping Java and its frameworks current, and just how hard it can be for enterprises to maintain momentum when upgrades feel constant and high stakes. Speakers from JPMorgan Chase, Choice Hotels, and the Spring team each described the same underlying problem: how do you modernize Java at scale without slowing delivery or introducing risk?

The scale of the Java upgrade challenge

Nick McKinney from JPMorgan Chase brought the scale of the challenge into sharp focus. His team manages more than 40,000 Spring Boot applications, and he calculated that with the regular cadence of Spring Boot and Java long-term support updates, they were facing about two and a half upgrades per Spring Boot repository, per year. Multiply that across the entire portfolio and the effort becomes overwhelming.

Unsupported versions introduce a range of challenges:

  • Features – New Spring Boot and Java releases bring functionality older versions will never get.
  • Performance – Upgrades often deliver measurable efficiency gains.
  • Bug fixes – Older versions force teams to live with issues that have already been resolved upstream.
  • Security fixes – Vulnerabilities like Log4Shell hit unsupported versions hardest.
  • Supportability – Once a version falls outside its support window, it’s harder to get vendor help or community fixes.

Delaying upgrades only compounds these challenges, making each subsequent migration even harder and riskier.

Automating with a pit crew approach

When you’re in the middle of a race, you don’t want one person fumbling with a lug wrench. You want a professional pit crew, trained and equipped to do the job with precision. For JPMorgan Chase and many others, Moderne and OpenRewrite have become that pit crew.

OpenRewrite recipes act like those expert hands with the right tools. They reduce the barrier for developers, ensure upgrades are consistent, and handle repetitive work at scale so teams can focus on the trickier issues, like tests that don’t catch regressions or pipelines that fail under pressure. As McKinney explained, OpenRewrite recipes even include “historical upkeep,” so a Spring Boot 3.5 recipe also applies all the migrations from 2.7, 3.0, 3.1, and so on.

JPMorgan Chase now has over 16,000 users of OpenRewrite running recipes, helping them to increase the percentage of applications on supported versions, especially after the Spring Boot 3.0 end-of-life cliff.

McKinney was clear, though, that while developers shouldn’t expect automation to remove all effort, it does allow them to complete common migration tasks much faster.

Choice Hotels also relied on this pit crew approach during its Java 8 to 21 migration. Using OpenRewrite recipes allowed them to handle sweeping changes efficiently and coordinate upgrades across many services in parallel.

Continuous migration: Keeping the car moving at peak pace

While JPMorgan Chase and Choice Hotels have used OpenRewrite and Moderne to help with sprawling modernization efforts, it’s even better when developer teams can get ahead in the first place.

DaShaun Carter’s Refactoring the ROI of Software session at Code Remix Summit reframed modernization as a continuous, background process, not a one-off project. That way, it’s like having a pit crew on call for every lap, not just when disaster strikes. By codifying migrations into a policy and automating the transformation, it keeps your codebase evergreen.

Carter calls it “Continuous Integration / Continuous Migration” (CI/CM). Just like CI/CD made it easier to get to production quickly and safely, CI/CM makes it easier to deliver outdated software faster too. As he says, “CI/CD gave us speed; CI/CM gives us resilience and more. With OpenRewrite, we can now treat migrations just like we treat our tests: automated, repeatable, and safe.” 

In practice, this means building pipelines that:

  1. Detect drift in dependencies and configurations.
  2. Automatically rewrite code using OpenRewrite recipes.
  3. Open pull requests with those changes.
  4. Validate and merge the changes without slowing the rest of the team.

Strengthened pipelines and complete tests ensure these changes don’t pile up as broken PRs, but instead become quick, predictable tune-ups that keep the car safely moving at full speed. This is especially relevant for large Java portfolios: the language’s 30-year history and extensive frameworks make drift and dependency sprawl a real threat. Building CI/CM practices around Java upgrades can help enterprises stay on track.

Preparing for the next Java generation

Even after 30 years of Java, the pace of change isn’t slowing. Spring Framework 7 and Spring Boot 4.0 are coming later this year, and they make it easier to take advantage of Java 21’s most powerful capabilities. Engineers want to work with modern tools, and outdated technology sends the wrong message about an organization’s culture and priorities.

As Josh Long from the Spring team reminded the audience in his Bootiful Spring session: “That's a whole new generational release. These versions are going to be big. Lots of new stuff. Lots of cool stuff. So it's high time that you upgraded.” 

Long highlighted virtual threads (Project Loom) for non-blocking I/O at scale, and demonstrated how easy it is to build GraalVM native images with Spring to dramatically improve startup time and resource usage. He also touched on Spring AI, showing how a modernized stack opens the door to integrate AI models and vector databases without friction. According to Long, paying attention to fundamentals like modularity and visibility defaults in Java can help keep systems clean and upgrade-ready.

Finally, he underscored the importance of tending to your codebase—avoiding CVEs, staying ahead of deprecations, and using tools like OpenRewrite and Moderne to keep systems clean and upgrade-ready.

Keep rolling forward into the next 30

The lessons shared at Code Remix Summit were clear: keeping Java up to date isn’t optional. Falling behind on Java and its frameworks leads to security risks, mounting technical debt, and missed opportunities to leverage new capabilities. The best path forward is to reduce upgrade friction through automation, build continuous migration into your development process, and stay ahead of deprecations so you can take full advantage of modern Java features. You can’t win the race if you’re still driving on worn tires.

Thirty years on, Java is still evolving. The organizations that treat modernization as a core competency, as Choice Hotels and JPMC do, will be the ones best positioned to thrive in the next decade.

Follow their lead—schedule a demo to see how Moderne can help you modernize faster.