Book a scoping call
Case study · Ecommerce · 2026

From Java 17 and Spring 5 to Java 25 and Spring 6, with 47 critical and high vulnerabilities cut to 0

An independent London wine merchant runs its online store and its back office on one Java codebase built up over more than fifteen years. We moved both onto a supported platform in tested steps, with no rewrite, while the client kept releasing features.

47 to 0
critical and high-severity advisories in the dependency tree: 12 critical and 35 high before the work, none afterOSV scan, before and after
Java 25
the current long-term support release, with Spring 6.2, Spring Security 6.5 and Hibernate 6.6Both applications
4 weeks
for the core upgrade, with no rewrite and no feature freezeEngagement
Client
An independent London wine merchant: shops, a website, a trade business, and wine held in bond for customers who buy by the case
Sector
Ecommerce and retail, with stock, storage billing and fulfilment behind it
Scope
An online store and a back-office ERP that share one business core and one database
Engagement
Application modernization in verifiable steps; core upgrade in about four weeks
Stack
Java 25, Jakarta EE 10, Spring 6.2, Spring Security 6.5, Hibernate ORM 6.6, Tomcat 10.1, PostgreSQL, OpenRewrite, Playwright
Offer today
Application Modernization Sprint
Challenge

A system that still worked, on foundations that no longer got fixes

Nothing was broken. Orders went out, invoices printed and customers checked out every day. The risk sat underneath the application, and it grew every month.

Spring 5.3, Spring Security 5.8 and Hibernate 5.5 had stopped receiving open-source security fixes, and the web layer sat on the javax generation that current libraries are leaving behind. A dependency scan found 12 critical and 35 high-severity advisories, including log4j 1.x and old file upload and search libraries, many with no fix available on the versions in use. The browser code relied on jQuery 1.11 and jQuery UI 1.8, releases from the early 2010s. Several components had been abandoned by their authors and had no version for Spring 6, so they blocked the upgrade path until they were replaced. Automated tests covered little of what the business runs on, which left every change carrying hidden risk.

The system takes card payments and holds customer data. A rewrite was out of proportion to the problem, and staying put was not an option either.

Approach

One manageable step at a time

  1. Map and plan

    We scanned the full dependency tree to set a baseline, listed every Spring 6 and Hibernate 6 change that would touch this codebase, and agreed an order of work in which each step could be verified on its own.

  2. Build the safety net first

    Before any framework moved, we added regression tests around what the business relies on: PDF invoices and documents, spreadsheet imports, product search, orders and billing queries, plus browser tests that walk real journeys through both applications. They earned their place during the upgrade by catching two breaks before release, one that would have stopped all PDF generation and one that would have broken spreadsheet imports.

  3. Upgrade in steps

    Each step ended with both applications building, starting and passing the suite. First the vulnerabilities that needed no framework change. Then the platform: Jakarta EE 10, Spring 6.2, Spring Security 6.5, Hibernate 6.6 and Tomcat 10.1, with more than 800 files moved to the new namespaces by automated refactoring and every change reviewed. Then the browser libraries, with the page scripts that used removed functions rewritten. Last, the build and runtime moved to Java 25.

  4. Verify end to end

    All 79 automated tests passed and both applications ran on the new server. We then walked the real routes of both applications page by page. Hibernate 6 is stricter than Hibernate 5, so queries that used to pass silently now failed, including one that stalled the product search index at start-up. We found and fixed them before users could meet them.

  5. Hand over

    The client's developers received a runbook covering what changed, how to run the new stack and which behaviour differs for users, together with the test suites and the before and after security reports.

Judgement calls

Replace what blocks the upgrade, keep what works

The order workflow runs on an old embedded engine that is built too deeply into the business to remove in one phase. Its known vulnerability sat in a single class the application never calls, so we repackaged the engine without that class. Order processing did not change, and the vulnerable code no longer ships. For PDF documents we replaced a library from 2009 with a maintained fork that keeps the same interface, so the invoice and document templates carried on working untouched.

There was no feature freeze. The client's team kept shipping on the main line throughout, including new work on stock and price sync with the shop tills, and we merged each change into the upgrade as it landed.

Before and after

The stack, by release line

ComponentBeforeAfter
Java17 (2021)25 (2025)
Enterprise Java APIJava EE 8, javax (2017)Jakarta EE 10 (2022)
Spring Framework5.3 (2020)6.2 (2024)
Spring Security5.8 (2022)6.5 (2025)
Hibernate ORM5.5 (2021)6.6 (2024)
Application serverTomcat 9 (2018)Tomcat 10.1 (2022)
jQuery1.11 (2014)3.7 (2023)
jQuery UI1.8 (2010)1.13 (2021)
DataTables1.10 (2014)1.13 (2022)
Bootstrap (store)3.3 (2014)3.4 (2018)

Years are when each release line first shipped. The patch versions deployed are newer.

Results

Secure today, and easier to keep that way

The upgrade also brought CSRF protection on every form, routes denied by default unless a rule allows them, anti-clickjacking headers, a Content Security Policy running in monitoring mode and integrity checks on every script loaded from a CDN.

12 to 0
critical advisories in shipped dependenciesOSV database, runtime dependencies
35 to 0
high-severity advisories in shipped dependenciesOSV database, runtime dependencies
30%
faster clean builds on the new toolchainBuild times, before and after
79
automated regression and browser tests, all passing on the new stackTest suite handed to the client
Handover

What the client received

  • Upgraded code

    Both applications on the new platform, building and running on Java 25.

  • Security reports

    Before and after vulnerability scans, with a repeatable method for running them again.

  • Test suites

    Regression tests for core business functions and browser tests for real user journeys, kept by the client.

  • Runbook

    How to build and run the new stack, and which behaviour changed for staff and customers.

  • Migration notes

    A reference for the Spring 6 and Hibernate 6 changes, so new code avoids the known pitfalls.

  • Roadmap

    A prioritised plan for the next phases of hardening and for the legacy components still to replace.

Related

The offers this engagement proves

Next step

Book a scoping call

Thirty minutes with an architect, not a salesperson. You leave with a written view of scope, price model and whether we are the right team for it.

Book a scoping callSee the proof first