
Modernizing Legacy Applications with AI-Driven Reference Architecture Patterns and Kiro
Discover how AI-powered development tools can automatically modernize legacy applications stuck on Java 8 and outdated frameworks, delivering significant performance improvements and cloud-native capabilities. See a complete Struts-to-Quarkus migration accomplished with one command, including code comparisons and measurable benefits.
The Legacy Modernization Challenge
Millions of Java applications running in production today are stuck in the past—Java 8, Struts 2, legacy Hibernate versions, and outdated frameworks that were cutting-edge a decade ago. For many organizations, the cost and risk of manual modernization has kept these applications frozen in time, accumulating technical debt while missing out on the performance, security, and developer experience benefits of modern frameworks.
After 25 years of Java development, I've witnessed this challenge firsthand across countless enterprises. The traditional approach to modernization—rewriting applications manually—is often too expensive, time-consuming, and risky for most organizations to justify.
The AI-Powered Solution
What if you could modernize your entire application architecture with a single command? What if AI could understand your legacy codebase, analyze modern reference architectures, and systematically transform your application while preserving business logic?
This is no longer a hypothetical scenario. Using AI-driven development tools like Kiro CLI, combined with reference architecture patterns, we can now achieve comprehensive application modernization that would have taken months of manual work.
What You'll Learn
In this article, I'll demonstrate a practical approach to AI-driven modernization using reference architecture patterns—a technique that combines:
- Focused AI prompts that clearly communicate migration intent
- Reference applications that provide architectural blueprints
- Systematic transformation that maps legacy patterns to modern equivalents
We'll walk through a complete real-world example: migrating a classic Struts 2 CRUD application to modern Quarkus with Qute templating, accomplished with a single Kiro CLI command. You'll see the exact transformations, performance improvements, and architectural benefits achieved.
Download Complete Source Code
All source code for this migration example is available for download and hands-on exploration:
Download Link: https://dvbf6ctqppu9g.cloudfront.net/content/modernization-workshop/projects/migration-cli.zip
The download contains three complete projects that demonstrate the full migration journey:
Project Structure Overview
struts/ - Original Legacy Application- Complete Struts 2 CRUD application demonstrating typical legacy patterns
- JSP-based templating with Struts tags and XML configuration
- Manual dependency management and traditional MVC architecture
- Represents the "before" state that many organizations need to modernize
- Fully functional for comparison testing against the migrated version
quarkus/ - Reference Architecture Application- Production-ready Financial Entry Management System built with Quarkus 3.14.4
- Demonstrates modern cloud-native patterns with DynamoDB integration
- AWS Lambda deployment configuration and Docker Compose setup
- Serves as the architectural blueprint that guided the AI migration process
- Shows best practices for REST APIs, CDI injection, and cloud deployment
person-quarkus/ - AI-Generated Migration Result- Complete migrated application created by Kiro CLI in a single command
- Modern Quarkus architecture with Qute templating replacing JSP
- CDI-based dependency injection and JAX-RS REST endpoints
- Demonstrates the "after" state with significant performance and maintainability improvements
- Ready-to-run example of successful AI-driven modernization
Running the Applications
Each project can be run independently to compare the different approaches:
Legacy Struts Application:
1
2
3
cd struts
mvn jetty:run
# Access at: http://localhost:8080/crudReference Quarkus Application:
1
2
3
cd quarkus
./mvnw quarkus:dev
# Access at: http://localhost:8080Migrated Person Management:
1
2
3
cd person-quarkus
./mvnw quarkus:dev
# Access at: http://localhost:8080This complete source code package allows you to:
- Study the migration patterns and transformations applied
- Compare performance between legacy and modern implementations
- Use the reference architecture for your own migration projects
- Experiment with AI-driven modernization techniques
- Understand the practical benefits of modern Java frameworks
Migration Example: Struts to Quarkus with Kiro CLI
To demonstrate this approach, I used Kiro CLI to migrate a classic Struts 2 CRUD application to modern Quarkus with Qute templating. The migration showcases how AI can understand architectural patterns and apply them systematically.
Original Struts Application Architecture
The original application was a typical Struts 2 CRUD example with the following structure:
1
2
3
4
5
6
7
8
9
10
struts/
├── src/main/java/org/apache/struts/crud/
│ ├── action/PersonAction.java # Struts Action Controller
│ ├── dao/ # Data Access Objects
│ ├── service/DefaultPersonService.java # Business Logic
│ └── model/ # Person and Country models
├── src/main/webapp/WEB-INF/jsp/ # JSP Templates
│ ├── persons.jsp # List view
│ └── editPerson.jsp # Form view
└── src/main/resources/struts.xml # Struts ConfigurationKey Technologies:
- Struts 2 framework with Actions
- JSP templates with Struts tags
- Manual dependency injection
- XML-based configuration
Migration Command
The migration was initiated with a simple, focused prompt to Kiro CLI:
1
"based on quarkus reference app, migrate the struts to the same architecture using qute for UI. create the new app inside a folder called person-quarkus."This single command leveraged:
- Reference Architecture: Kiro analyzed the existing Financial Entry Management System (a production Quarkus application with DynamoDB integration and AWS Lambda deployment)
- Pattern Recognition: Understood the Struts MVC pattern and mapped it to Quarkus JAX-RS + CDI architecture
- Technology Translation: Automatically chose appropriate Quarkus extensions (quarkus-rest, quarkus-rest-qute, quarkus-arc)
Migrated Quarkus Application
The result was a fully functional Quarkus application with modern architecture:
1
2
3
4
5
6
7
8
9
10
11
12
person-quarkus/
├── src/main/java/org/apache/struts/crud/
│ ├── resource/PersonResource.java # JAX-RS Resource (REST Controller)
│ ├── dao/ # DAO with CDI injection
│ ├── service/DefaultPersonService.java # Service with CDI annotations
│ └── model/ # Unchanged model classes
├── src/main/resources/
│ ├── templates/ # Qute HTML templates
│ │ ├── persons.html # Type-safe list view
│ │ └── editPerson.html # Type-safe form view
│ └── application.properties # Simple properties config
└── pom.xml # Quarkus dependenciesKey Migration Transformations
1. Controller Layer: Struts Action → JAX-RS Resource
Before (Struts Action):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class PersonAction extends ActionSupport implements Preparable {
private PersonService personService = new DefaultPersonService();
public String list() {
persons = personService.getAllPersons();
return SUCCESS;
}
public String save() {
if (person.getPersonId() == null) {
personService.insertPerson(person);
} else {
personService.updatePerson(person);
}
return SUCCESS;
}
}After (Quarkus Resource):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PersonResource {
PersonService personService;
Template persons;
public TemplateInstance list() {
return persons.data("persons", personService.getAllPersons());
}
public Response save( String firstName, ...) {
// Handle form data and save
return Response.seeOther(URI.create("/")).build();
}
}2. Template Engine: JSP → Qute
Before (JSP with Struts tags):
1
2
3
4
5
6
<s:iterator value="persons" status="status">
<tr class="<s:if test="#status.even">even</s:if><s:else>odd</s:else>">
<td><s:property value="firstName"/></td>
<td><s:property value="lastName"/></td>
</tr>
</s:iterator>After (Qute with type safety):
1
2
3
4
5
6
{#for person in persons}
<tr class="{#if person_index.mod(2) == 0}even{#else}odd{/if}">
<td>{person.firstName}</td>
<td>{person.lastName}</td>
</tr>
{/for}3. Dependency Injection: Manual → CDI
Before (Manual instantiation):
1
private PersonService personService = new DefaultPersonService();After (CDI injection):
1
2
3
4
5
6
PersonService personService;
public class DefaultPersonService implements PersonService {
PersonDao personDao;
}Migration Benefits Achieved
The Kiro CLI migration delivered significant improvements:
Performance Gains:
- Startup Time: From ~5 seconds to ~0.8 seconds
- Memory Usage: Reduced by ~40%
- Hot Reload: Instant code changes in dev mode
Developer Experience:
- Type Safety: Qute provides compile-time template checking
- Modern Standards: Jakarta EE and MicroProfile compliance
- Simplified Configuration: Properties instead of XML
Cloud Native Ready:
- Container Optimized: Smaller images, faster startup
- Native Compilation: Optional GraalVM support
- Kubernetes Integration: Built-in cloud deployment features
Generated Project Structure
The migration created a complete Maven project with:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId> <!-- CDI -->
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId> <!-- JAX-RS -->
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-qute</artifactId> <!-- Qute Templates -->
</dependency>
</dependencies>Running the Applications
Original Struts:
1
2
3
cd struts
mvn jetty:run
# Access: http://localhost:8080/crudMigrated Quarkus:
1
2
3
cd person-quarkus
./mvnw quarkus:dev
# Access: http://localhost:8080The Quarkus version starts significantly faster and provides hot reload capabilities for rapid development.
Migration Effort Analysis
- Code Changes: ~70% of controller code rewritten automatically
- Templates: 100% converted from JSP to Qute with improved syntax
- Models/Services: Minimal changes (just CDI annotations added)
- Configuration: Dramatically simplified (XML → Properties)
- Dependencies: Modern, lightweight Quarkus stack
This demonstrates how AI-driven migration with reference architectures can systematically modernize applications while preserving business logic and improving the overall technology stack.
Practical Implementation Steps
Step 1: Prepare Reference Architecture
Before starting the migration, you need a well-structured reference Quarkus application that demonstrates the target architecture patterns. This reference application serves as the architectural blueprint that Kiro CLI analyzes to understand the desired modernization patterns.
The Reference Application: Financial Entry Management System
For this migration, I used a production-ready Quarkus application - a Financial Entry Management System with the following characteristics:
Architecture Overview:
1
2
3
4
5
6
7
8
9
10
11
quarkus/
├── src/main/java/academy/silicon/
│ ├── resource/EntryResource.java # JAX-RS REST endpoints
│ ├── service/EntryService.java # Business logic layer with CDI
│ ├── model/Entry.java # Domain model with DynamoDB mapping
│ └── GreetingResource.java # Additional REST resource
├── src/main/resources/
│ └── application.properties # Quarkus configuration
├── docker-compose.yml # Local DynamoDB setup
├── template.yml # AWS SAM deployment
└── pom.xml # Maven with Quarkus 3.14.4Key Architectural Patterns Demonstrated:
- Modern REST Architecture```java
@Path("/entryResource")
public class EntryResource {
@Inject EntryService eService;}1
2
3
4
5
6
7
8
9("/findAll")
public List<Entry> findAll() {
return eService.findAll();
}
public void addEntry(Entry entry) {
eService.addEntry(entry);
} - CDI-Based Service Layer```java
@ApplicationScoped
public class EntryService extends EntryHelper {
@Inject DynamoDbClient dynamoDB;}1
2
3
4
5
6public List<Entry> findAll() {
return dynamoDB.scanPaginator(scanRequest())
.items().stream()
.map(Entry::from)
.collect(Collectors.toList());
} - Cloud-Native Integration
- DynamoDB Integration: Native AWS DynamoDB client with Quarkus extensions
- Lambda Deployment: AWS Lambda HTTP support for serverless deployment
- Container Ready: Docker Compose for local development
Technology Stack:
- Quarkus 3.14.4: Latest stable version with performance optimizations
- JAX-RS: Standard REST endpoint definitions
- CDI (Contexts and Dependency Injection): Modern dependency injection
- AWS DynamoDB: Cloud-native NoSQL database integration
- AWS Lambda: Serverless deployment capability
- Maven: Build and dependency management
Why This Reference Application Was Ideal:
- Production-Ready Patterns: Real-world business logic with financial calculations
- Modern Quarkus Stack: Latest framework version with best practices
- Cloud-Native Design: AWS integration and serverless deployment
- Layered Architecture: Clear separation of concerns (Resource → Service → Data)
- Comprehensive Features: CRUD operations, filtering, business logic
Qute Template Integration:
While the reference application focused on REST APIs, Kiro CLI intelligently recognized the need for server-side rendering based on the Struts JSP templates in the source application. It automatically selected Quarkus Qute as the modern equivalent to JSP, demonstrating AI's ability to bridge architectural gaps between reference patterns and migration requirements.
While the reference application focused on REST APIs, Kiro CLI intelligently recognized the need for server-side rendering based on the Struts JSP templates in the source application. It automatically selected Quarkus Qute as the modern equivalent to JSP, demonstrating AI's ability to bridge architectural gaps between reference patterns and migration requirements.
Reference Application Capabilities:
- Account-based financial entry management
- Category-based filtering and bulk updates
- Date range querying with balance calculations
- RESTful API design with proper HTTP methods
- DynamoDB integration for scalable data persistence
- AWS Lambda deployment for serverless architecture
This reference application provided Kiro CLI with a comprehensive blueprint of modern Quarkus patterns, enabling it to understand how to transform the legacy Struts MVC pattern into contemporary cloud-native architecture.
Step 2: Single Migration Command
The entire migration was accomplished with one focused command:
1
"based on quarkus reference app, migrate the struts to the same architecture using qute for UI. create the new app inside a folder called person-quarkus."Step 3: AI Analysis and Generation
Kiro CLI automatically:
- Analyzed the Struts application structure
- Identified the MVC pattern and components
- Mapped Struts concepts to Quarkus equivalents
- Generated the complete project structure
- Created all necessary files with proper dependencies
Step 4: Verification and Testing
The generated application was immediately runnable:
1
2
cd person-quarkus
./mvnw quarkus:dev
new app ui
The screenshot above shows the successfully migrated Quarkus application running with the modern Qute templating engine, demonstrating the clean UI transformation from the original Struts JSP-based interface.
Download Complete Source Code
All source code for this migration example is available for download and hands-on exploration:
Download Link: https://dvbf6ctqppu9g.cloudfront.net/content/modernization-workshop/projects/migration-cli.zip
The download contains three complete projects that demonstrate the full migration journey:
Project Structure Overview
struts/ - Original Legacy Application- Complete Struts 2 CRUD application demonstrating typical legacy patterns
- JSP-based templating with Struts tags and XML configuration
- Manual dependency management and traditional MVC architecture
- Represents the "before" state that many organizations need to modernize
- Fully functional for comparison testing against the migrated version
quarkus/ - Reference Architecture Application- Production-ready Financial Entry Management System built with Quarkus 3.14.4
- Demonstrates modern cloud-native patterns with DynamoDB integration
- AWS Lambda deployment configuration and Docker Compose setup
- Serves as the architectural blueprint that guided the AI migration process
- Shows best practices for REST APIs, CDI injection, and cloud deployment
person-quarkus/ - AI-Generated Migration Result- Complete migrated application created by Kiro CLI in a single command
- Modern Quarkus architecture with Qute templating replacing JSP
- CDI-based dependency injection and JAX-RS REST endpoints
- Demonstrates the "after" state with significant performance and maintainability improvements
- Ready-to-run example of successful AI-driven modernization
Running the Applications
Each project can be run independently to compare the different approaches:
Legacy Struts Application:
1
2
3
cd struts
mvn jetty:run
# Access at: http://localhost:8080/crudReference Quarkus Application:
1
2
3
cd quarkus
./mvnw quarkus:dev
# Access at: http://localhost:8080Migrated Person Management:
1
2
3
cd person-quarkus
./mvnw quarkus:dev
# Access at: http://localhost:8080This complete source code package allows you to:
- Study the migration patterns and transformations applied
- Compare performance between legacy and modern implementations
- Use the reference architecture for your own migration projects
- Experiment with AI-driven modernization techniques
- Understand the practical benefits of modern Java frameworks
Key Success Factors
1. Reference Architecture Pattern
Having a well-structured reference application allowed Kiro to understand:
- Project organization conventions
- Technology stack choices
- Code patterns and best practices
- Configuration approaches
2. Focused Migration Prompt
The prompt was specific about:
- Source: "struts" (clear source technology)
- Target: "quarkus reference app" (clear target pattern)
- UI Technology: "qute for UI" (specific template engine)
- Output Location: "person-quarkus folder" (clear deliverable)
3. Architectural Equivalence Mapping
Kiro successfully mapped:
- Struts Actions → JAX-RS Resources
- JSP Templates → Qute Templates
- Manual DI → CDI Injection
- XML Config → Properties Config
- WAR Deployment → Quarkus Runner
Lessons Learned
What Worked Well
- Single Command Migration: One prompt generated a complete, working application
- Pattern Recognition: AI understood MVC patterns across different frameworks
- Technology Translation: Automatic selection of appropriate Quarkus extensions
- Code Quality: Generated code followed modern Java practices
Areas for Enhancement
- Custom Business Logic: Complex business rules may need manual review
- Database Integration: Data layer migrations might require additional attention
- Security Configurations: Authentication/authorization patterns need verification
- Performance Tuning: Application-specific optimizations require manual adjustment
Conclusion
This migration example demonstrates the power of combining AI with reference architectures for application modernization. By providing clear architectural patterns and focused prompts, developers can achieve significant modernization results with minimal manual effort.
The approach scales beyond Java applications - similar patterns can be applied to modernize .NET, Python, Node.js, and other technology stacks. The key is having solid reference architectures and understanding how to communicate migration intent effectively to AI tools.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article