← All cases

01 · Case study

Java 21 upgrade of a GIS platform

Japanese geospatial mapping platformJava · GeoTools · GeoServer · Spring · PostGIS

The system

Java classes
316
JSP pages
337
JARs in WEB-INF/lib
129
Maven dependencies now
156

The problem

The build was Ant, and the dependency manager was a folder. One hundred and twenty-nine JARs sat in webapps/map/WEB-INF/lib, several of them from 2007 and 2011, and thirteen of those existed nowhere on the public internet — a custom KML library, two Japanese metadata standards, a patched GeoTools shapefile driver, an in-house OAuth implementation. Nothing declared a version. Nothing could be audited. The system could not move to a supported Java, because nobody could say what it depended on.

What ran

  1. Read it

    The structural map over the source, the JSP layer and the Ant build, so the dependency set is derived from what the code imports rather than from what the lib folder happens to contain.

  2. Resolve every dependency

    Each of the 129 JARs matched to a Maven coordinate, or recorded as unresolvable with the reason. The unresolvable ones are the finding, not a failure — they are what a lib folder hides.

  3. Plan against the release notes

    Every JDK release being crossed read for what it actually changed — the removed APIs, the default charset, the encapsulation, the collectors that went away — so a compile error is explained by the release that caused it.

  4. Approve

    The plan is presented in full before anything is written. Nothing is touched before this gate.

  5. Apply, step by step

    Each step is its own commit with its own diff, so the migration reads as a sequence a reviewer can follow rather than one enormous change.

What it did

Dependency resolution

gt-jdbc-postgis 2.7.5 → 8.7 · HSQLDB 1.8.0.7 → 2.3.4 · JSR-275 beta → units-of-measurement 1.0 · JAI Tools 1.1.1 → 1.3.1 via repo.osgeo.org · Eclipse EMF 2.6 → 2.15.0 on corrected coordinates

GeoTools type casting and generics

commit 476c72d — 9 files, +38 −33. The GeoJSON, KML, shapefile and DXF writers, the SLD servlet and resource, and the shape utilities.

Commons FileUpload and Jakarta

commit c572878 — 9 files, +654 −343. FileUpload 1.5 → 2.0.0-M2, javax.servlet → jakarta.servlet across 8 classes, with a ServletRequestContext wrapper for the new API.

Where it ended

The build is Maven with 156 declared dependencies and maven.compiler.release at 21. Every step landed as its own commit with a published diff. The thirteen JARs with no public coordinate are recorded by name, with what each one does and how it was handled — which is the part a security review asks for and a lib folder can never answer.

What happens next

  • Install the remaining custom JARs into a private repository, or replace them — each one is already named with its purpose.
  • Run the dependency CVE check now that every version is declared. It could not run before, because nothing had a version.
  • Take the JSP layer next. It is 337 files and it is the part still holding the system to a servlet container.

The reason this one is worth reading is the ordering. The Java version was never the hard part — the hard part was that nobody could enumerate the dependencies, so no upgrade could be planned. Resolve the dependency set first and the upgrade becomes a sequence of small, reviewable commits.