I Migrated a 350k-Line Java/JSP Application to TypeScript in Five Days

gkrishna2 pts0 comments

Migrating 350,000 Lines from Java/JSP to TypeScript with AI Agents

Skip to content

AI & Machine Learning

How I Migrated a 350,000-Line Java/JSP Application to TypeScript in Five Days

Published by

krishnagokula

on

July 31, 2026

Featured image generated locally with ComfyUI through the WSL gateway for the Java/JSP-to-TypeScript migration article.<br>" data-image-caption="AI agents supplied the migration throughput; verification converted it into measurable progress.<br>" data-large-file="https://i0.wp.com/gokulakrishna.co/wp-content/uploads/2026/07/ai-agent-java-to-typescript-migration.jpg?fit=1024%2C566&ssl=1" />

I recently migrated a 350,000-line Java/JSP application to TypeScript using AI agents.

Our original estimate for a conventional migration was three engineers and close to a year. Instead, one engineer orchestrating pools of up to 20 sub-agents at each stage got the application running in a development environment in five days.

The headline sounds like a story about faster code generation. It is not.

The decisive factor was verification. Once the agents had a reliable way to compare the old and new systems, parallelism became useful rather than chaotic.

350,000

lines of Java/JSP

5 days

to a running development environment

20

sub-agents in each stage

Why parallel agents were only half the solution

Jarred Sumner’s account of the Bun rewrite gave me useful ideas for running agents in parallel. Bun had an important advantage: a language-independent TypeScript test suite. The implementation could change while the expected behaviour remained measurable.

Our application had no equivalent safety net.

Only about half of the existing tests worked. Many had weak or missing assertions, and others depended directly on infrastructure. A large agent pool could generate code quickly, but without an independent oracle it could also produce 20 plausible versions of the wrong system.

We needed a way to answer a simple question at every stage: does the new application behave like the one already running?

The migration sequence

Database<br>APIs<br>UI<br>Business logic<br>Improvements

That order was deliberate. Each stage created a more stable foundation for the next, and it limited the number of variables that could change at once.

1. Reconstructing the database contract

The legacy application did not have a reliable database schema we could treat as authoritative.

We reconstructed the application-facing Oracle schema from the SQL queries embedded throughout the codebase. The agents identified tables, columns, joins, constraints and data assumptions from the queries, then we validated the reconstructed contract against the running system.

This was more than a database exercise. The schema defined the vocabulary shared by every API, page and business rule that followed. Starting anywhere else would have forced the agents to build on guesses.

2. Rebuilding the APIs

Once the data contract was stable, agents could migrate API components in parallel. Each work item was narrow: rebuild a component, exercise it against both systems, compare the result and resolve the discrepancy.

This gave the UI migration a dependable backend target instead of asking agents to infer behaviour simultaneously at every layer.

3. Migrating the UI

The UI required more than checking HTTP status codes. We needed to know whether the same data appeared, whether the same elements were present and whether the same interactions produced the same outcomes.

This is where the parity harness became the centre of the migration.

Building a parity harness where tests were missing

The parity harness ran the legacy and TypeScript applications side by side and compared them at three levels:

API responses and resulting database state<br>Page elements and screenshots<br>User interactions in both applications

Inline editorial image generated locally with ComfyUI through the WSL gateway for the parity-harness section.<br>" data-image-caption="The parity harness compared observable behaviour across the legacy and TypeScript systems.<br>" data-large-file="https://i0.wp.com/gokulakrishna.co/wp-content/uploads/2026/07/ai-agent-parity-harness.jpg?fit=1024%2C566&ssl=1" src="https://i0.wp.com/gokulakrishna.co/wp-content/uploads/2026/07/ai-agent-parity-harness.jpg?resize=1216%2C672&ssl=1" alt="A symmetrical amber and teal visualization of a parity harness comparing legacy and TypeScript application stacks." class="wp-image-156" srcset="https://i0.wp.com/gokulakrishna.co/wp-content/uploads/2026/07/ai-agent-parity-harness.jpg?w=1216&ssl=1 1216w, https://i0.wp.com/gokulakrishna.co/wp-content/uploads/2026/07/ai-agent-parity-harness.jpg?resize=300%2C166&ssl=1 300w, https://i0.wp.com/gokulakrishna.co/wp-content/uploads/2026/07/ai-agent-parity-harness.jpg?resize=1024%2C566&ssl=1 1024w, https://i0.wp.com/gokulakrishna.co/wp-content/uploads/2026/07/ai-agent-parity-harness.jpg?resize=768%2C424&ssl=1 768w" sizes="(max-width: 1000px) 100vw, 1000px" />The parity harness...

parity harness agents typescript application content

Related Articles