Skip to content

Add a sample to showcase migrating a legacy Java EE Ant project to a Jakarta EE 10 Maven project #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 42 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f2156ea
Update README
allxiao Mar 19, 2025
7e161c6
add execution permisson to shell scripts
majguo Mar 22, 2025
0dd7bed
worker doesn't listen to port 8081
majguo Mar 22, 2025
281c8a1
clean before starting web/worker apps
majguo Mar 23, 2025
11d2a53
update readme
majguo Mar 24, 2025
ceca68a
add dev container config
majguo Mar 25, 2025
dd38867
fix typo in readme
majguo Mar 25, 2025
f097bb4
add diff (#16)
yiliuTo Apr 26, 2025
eb2f93f
add formula source (#14)
yiliuTo May 8, 2025
0ff9d41
migrate rabbitmq to service bus (#18)
yiliuTo May 8, 2025
3f373da
delete the new project and diff file (#19)
yiliuTo May 8, 2025
6f6ea65
add open liberty sample
fangjian0423 May 21, 2025
de7996a
add mybatis, jackson, ServletFilter, cert
fangjian0423 May 29, 2025
8b5fa9b
refactor, use ibatis instead of mybatis
fangjian0423 May 29, 2025
8b5c454
jar location update
fangjian0423 May 30, 2025
a466801
fix dep
galiacheng Jul 30, 2025
b9c1b9e
run the app with docker
galiacheng Jul 30, 2025
84e1afe
use java 17
galiacheng Jul 30, 2025
b8a71fd
the application is working now.
galiacheng Jul 31, 2025
5229f7e
add spring student home
galiacheng Jul 31, 2025
f12c3a3
remove helloworld servlet
galiacheng Jul 31, 2025
2f06db6
improve
galiacheng Jul 31, 2025
c302f82
add doc
galiacheng Jul 31, 2025
c885ace
add description
galiacheng Jul 31, 2025
749a2cc
update screenshot
galiacheng Jul 31, 2025
4386a73
rename project
galiacheng Jul 31, 2025
7819deb
clean up
galiacheng Jul 31, 2025
9807f4f
remove version specification from docker-compose.yml
galiacheng Jul 31, 2025
14127df
update screenshot
galiacheng Jul 31, 2025
cea5477
format image display in README.md for better alignment
galiacheng Jul 31, 2025
69a456f
adjust image width in README.md for better alignment
galiacheng Jul 31, 2025
a391ebb
update Java version requirement to 11 in README.md and manual-setup.md
galiacheng Jul 31, 2025
be52473
align image to the left in README.md for better presentation
galiacheng Jul 31, 2025
93f3a98
Merge remote-tracking branch 'up/main' into jimmy/jakarta-ee
galiacheng Jul 31, 2025
1406313
Add new sample for Student Web App using Jakarta EE and update descri…
galiacheng Jul 31, 2025
db655eb
Rename back.
galiacheng Jul 31, 2025
78fc45a
Update README.md to correct directory name for Student Web App
galiacheng Jul 31, 2025
16f6496
Fix link formatting for Student Web App in README.md
galiacheng Jul 31, 2025
acbbf3c
Refactor README.md and add getting-started.md for clearer migration i…
galiacheng Aug 1, 2025
76ec2a1
add migration steps
Aug 1, 2025
d728f91
Proposed edits to README
edburns Aug 8, 2025
b8d0180
Merge pull request #3 from azure-javaee/edburns/amj-834-proposed-edit…
galiacheng Aug 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

- [asset manager](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/main/asset-manager) : This is a complete workshop with an end-to-end scenario that migrates an app to Azure using predefined and custom formulas. After the migration, the app will run on Azure Container Apps and interact with Auzure Blob, Azure Service Bus and Azure Database for PostgreSQL.

-[Todo Web API with Oracle Database](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/main/todo-web-api-use-oracle-db) A To-do application using Oracle database for storage. It leverages Oracle-specific SQL features and data types, for instance, VARCHAR2. This sample migrates the application to use Azure Database for PostgreSQL instead.
- [Todo Web API with Oracle Database](https://github.com/Azure-Samples/java-migration-copilot-samples/tree/main/todo-web-api-use-oracle-db) A To-do application using Oracle database for storage. It leverages Oracle-specific SQL features and data types, for instance, VARCHAR2. This sample migrates the application to use Azure Database for PostgreSQL instead.

- [Student Web App - Jakarta EE](jakarta-ee/student-web-app) A Java EE web application running on Open Liberty with a hybrid architecture that supports both traditional servlets and Spring MVC. The application manages student profiles with CRUD operations and demonstrates migrating from Ant to Maven and Java EE to Jakarta EE.

## Branches

Expand Down
30 changes: 30 additions & 0 deletions jakarta-ee/student-web-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
target/
build/
dist/
*.war

# IDE files
.idea/
*.iml
.vscode/
/bin/
.project
.classpath
.settings/

# Local configuration files (contain environment-specific paths)
local.properties
liberty_config/server.env

# Compile-time dependencies (can be downloaded)
compile-lib/*.jar

# Docker files
mysql-connector/

# OS files
.DS_Store
Thumbs.db

# Log files
*.log
33 changes: 33 additions & 0 deletions jakarta-ee/student-web-app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
FROM open-liberty:25.0.0.7-kernel-slim-java17-openj9

# Copy Liberty configuration
COPY --chown=1001:0 liberty_config/server-docker.xml /config/server.xml
COPY --chown=1001:0 liberty_config/server-docker.env /config/server.env

# Copy application
COPY --chown=1001:0 dist/OpenLibertyApp.war /config/apps/

# Create directories for libraries
RUN mkdir -p /opt/ol/wlp/usr/shared/resources/mysql

# Copy MySQL connector for JDBC driver
COPY --chown=1001:0 mysql-connector/mysql-connector-j-8.0.33.jar /opt/ol/wlp/usr/shared/resources/mysql/

# Configure Liberty features
RUN features.sh

# Expose ports
EXPOSE 9080 9443

# Set environment variables for Docker environment
ENV WLP_USER_DIR=/opt/ol/wlp/usr \
SERVER_NAME=defaultServer \
MYSQL_LIB_DIR=/opt/ol/wlp/usr/shared/resources/mysql \
LIBERTY_SERVER_DIR=/config \
KEYSTORE_LOCATION=/config/resources/security/key.p12 \
KEYSTORE_PASSWORD=defaultPassword \
TRUSTED_KEYSTORE_LOCATION=/config/resources/security/trust.p12 \
TRUSTED_KEYSTORE_PASSWORD=defaultPassword \
LTPA_KEY_FILE_SFA=/config/resources/security/ltpa.keys \
LTPA_KEY_PASSWORD_SFA=defaultPassword \
JDBC_DRIVER_CLASS=com.mysql.cj.jdbc.Driver
80 changes: 80 additions & 0 deletions jakarta-ee/student-web-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Migrate a legacy Java EE Ant project to a Jakarta EE 10 Maven project

This workshop guides you through migrating a legacy Java EE Ant project to a Jakarta EE 10 Maven project. After completing the workshop, the project will be fully migrated from Java EE to Jakarta EE 10, upgraded from Spring Framework 5.3.39 to 6.2.x, and ready to build with Maven.

## About this Sample Project

A Java EE web application running on Open Liberty with a hybrid architecture that supports both traditional servlets and Spring MVC. The application manages student profiles with CRUD operations and demonstrates migrating from Ant to Maven and Java EE to Jakarta EE.

For the project architecture, see [project details](doc/architecture.md).
For how to start this project, see [getting started](doc/getting-started.md)

## Prerequisites

- **Java 17** or higher
- **Apache Ant**, tested version: `1.10.14`.
- **Maven**, tested version: `3.8.7`.
- **Docker & Docker Compose** (Optional, for running the sample application)
- [Visual Studio Code](https://code.visualstudio.com/download)
- [VS Code Extension: GitHub Copilot App Modernization](https://marketplace.visualstudio.com/items?itemName=vscjava.migrate-java-to-azure)
- This extension depends on [VS Code Extension: GitHub Copilot App Modernization – Upgrade for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-upgrade). Both extensions will be installed automatically when you install **GitHub Copilot App Modernization**.

## Assess the Project

Please follow the steps below to assess and detect the Eclipse/Ant project:

1. Open [student-web-app](jakarta-ee/student-web-app) in VSCode.

1. Click **GitHub Copilot app modernization for Java** from the left side tool bar.

Click the `Toggle Chat` icon on the top, select `Agent` mode. If the **reload button** (looks like an arrow going counter clockwise) appears at the bottom, click it to reload the tools registration. This is only required the first time you install the extensions.

![assessment-start](assets/assessment-start.png)

1. Click **Run Assessment** button from the **Assessment** section on the left side view. It will open GitHub Copilot Chat window at the right side, and start to assess the project with the predefined prompt.

1. Interact with Copilot in the chat window and select **Continue** to proceed whenever you're ok with the actions suggested by the Copilot.

1. After the assessment is done, an **Assessment Report** will be generated and opened in the editor. From the bottom of the report, you can see **Build Tool (Ant)** in section **Java Modernization**, and associated action **Migrate** to migrate the project to Maven project.

![assessment-ant-to-maven-solution](assets/assessment-ant-to-maven-solution.png)

## Convert Ant project to Maven project

Now you can convert the Ant project to Maven project.

1. Select Action **Migrate** associated with **Build Tool (Ant)**, and start the migration with the predefined prompt. We recommend using the LLM model **Claude Sonnet 3.7** for the migration.

![convert-ant-to-maven](assets/convert-ant-to-maven.png)

1. Interact with Copilot in the chat window and select **Continue** to proceed whenever you're ok with the actions suggested by the Copilot.

If you see the request from Copilot to ask you confirm the migration plan, please review and manually confirm the migration plan before proceeding. For example, input `Confirm` in the chat box and click `Send`.

1. After the migration is complete, select **Keep** for changed files.

## Assess and detect the legacy Java EE and Spring Framework project

Please follow the similar steps before to assess and detect the legacy Java EE and Spring Framework project:

1. Select **GitHub Copilot app modernization for Java** from the left side tool bar.
1. Select **Run Assessment** from the **Assessment** section. It will open GitHub Copilot Chat window at the right side, and start to assess the project with the predefined prompt.
1. Interact with Copilot in the chat window and select **Continue** to proceed whenever you're ok with the actions suggested by the Copilot.
1. After the assessment is done, an **Assessment Report** will be generated and opened in the editor. From the bottom of the report, you can see **Framework Upgrade (Java EE/Jakarta EE)** and **Framework Upgrade (Spring Framework)** in section **Java Modernization**, and associated action **Upgrade** to upgrade the project.

Before you proceed with the next step, manually clean up the assistant files of the assessment tool. They will be automatically cleaned up in the future releases of the tool.

1. Replace `appcat` with `*` in the `.github\appmod-java\.gitignore` file to ignore all files within the `.github\appmod-java` directory.
1. Open **Source Control** view in VSCode, and select **Discard All Changes** to discard all changes made by the assessment tool.

Comment on lines +68 to +69
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we discarding all changes? When I did this, it discarded the ant to maven migration. I don't think that's what you wanted me to do, right? Is there a commit step missing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will proceed as if I was supposed to commit the changes from the ant to maven migration before proceeding.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should discuss with AppCat team to revert to the previous state. The expected behavior for an assessment process is that it's purely functional without side effect.
It's not a problem before because we didn't work on Eclipse / Ant related projects at that time.

## Upgrade the Project to Jakarta EE 10 and Spring Framework 6.x

Now you can upgrade the project. In this workshop, you select to upgrade Spring Framework version as it will also upgrade dependent Java EE version.

1. Select Action **Upgrade** associated with **Upgrade Spring Framework Version**, and start the upgrade with the predefined prompt. Recommend to use LLM model **Claude Sonnet 3.7** for the migration.
1. Interact with Copilot in the chat window and select **Continue** to proceed whenever you're ok with the actions suggested by the Copilot.
1. After the migration is complete, select **Keep** if there are any changed files.

There is an Upgrade Summary generated, review and do any follow-up actions based on your needs.


Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- Enable component scanning -->
<context:component-scan base-package="ca.on.gov.edu.coreft.service"/>
<context:component-scan base-package="ca.on.gov.edu.coreft.dao"/>

<!-- Service and DAO beans will be auto-discovered -->

</beans>
28 changes: 28 additions & 0 deletions jakarta-ee/student-web-app/WebContent/WEB-INF/spring-servlet.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!-- Enable component scanning for controllers -->
<context:component-scan base-package="ca.on.gov.edu.coreft.controller"/>

<!-- Enable Spring MVC annotations -->
<mvc:annotation-driven/>

<!-- View resolver for JSP pages -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>

<!-- Enable default servlet handler for static resources -->
<mvc:default-servlet-handler/>

</beans>
78 changes: 78 additions & 0 deletions jakarta-ee/student-web-app/WebContent/WEB-INF/web.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>OpenLibertyApp</display-name>

<!-- Spring Context Configuration -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<!-- Spring Context Loader Listener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Spring MVC Dispatcher Servlet -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>

<!-- Index Servlet to handle root path with student data -->
<servlet>
<servlet-name>IndexServlet</servlet-name>
<servlet-class>ca.on.gov.edu.coreft.IndexServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>IndexServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!-- Existing Servlets for backward compatibility -->
<servlet>
<servlet-name>AddStudentServlet</servlet-name>
<servlet-class>ca.on.gov.edu.coreft.AddStudentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddStudentServlet</servlet-name>
<url-pattern>/addStudent</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>StudentProfileListServlet</servlet-name>
<servlet-class>ca.on.gov.edu.coreft.StudentProfileListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>StudentProfileListServlet</servlet-name>
<url-pattern>/studentProfileList</url-pattern>
</servlet-mapping>

<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/StudentDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

<resource-ref>
<description>Mail Session</description>
<res-ref-name>mail/StudentMailSession</res-ref-name>
<res-type>javax.mail.Session</res-type>
<res-auth>Container</res-auth>
</resource-ref>

</web-app>
77 changes: 77 additions & 0 deletions jakarta-ee/student-web-app/WebContent/add_student_profile.jsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.*" %>
<html>
<head>
<title>Add Student Profile - Spring Framework</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }
.container { max-width: 600px; margin: 0 auto; background-color: white; padding: 30px; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
.header { background-color: #4CAF50; color: white; padding: 20px; margin: -30px -30px 30px -30px; border-radius: 10px 10px 0 0; }
.form-group { margin-bottom: 20px; }
label { display: block; margin-bottom: 5px; font-weight: bold; color: #333; }
input[type="text"], input[type="email"] { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-size: 16px; }
input[type="submit"] { background-color: #4CAF50; color: white; padding: 12px 30px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; }
input[type="submit"]:hover { background-color: #45a049; }
.nav { margin-bottom: 20px; }
.nav a { color: #4CAF50; text-decoration: none; margin-right: 15px; }
.nav a:hover { text-decoration: underline; }
.success { color: #3c763d; background-color: #dff0d8; padding: 10px; margin: 10px 0; border-radius: 5px; border: 1px solid #d6e9c6; }
.error { color: #a94442; background-color: #f2dede; padding: 10px; margin: 10px 0; border-radius: 5px; border: 1px solid #ebccd1; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Add Student Profile</h1>
<p>Spring Framework 5.3 Integration</p>
</div>

<div class="nav">
<a href="/">← Back to Home</a>
<a href="/students">View All Students</a>
<a href="/studentProfileList">Legacy Student List</a>
</div>

<%
String successMessage = (String) request.getAttribute("successMessage");
String errorMessage = (String) request.getAttribute("errorMessage");
if (successMessage != null) {
%>
<div class="success">
<%= successMessage %>
</div>
<% } %>

<% if (errorMessage != null) { %>
<div class="error">
<%= errorMessage %>
</div>
<% } %>

<form action="/addStudent" method="post">
<div class="form-group">
<label for="name">Student Name:</label>
<input type="text" id="name" name="name" required placeholder="Enter student's full name">
</div>

<div class="form-group">
<label for="email">Email Address:</label>
<input type="email" id="email" name="email" required placeholder="Enter student's email">
</div>

<div class="form-group">
<label for="major">Major/Field of Study:</label>
<input type="text" id="major" name="major" required placeholder="Enter student's major">
</div>

<div class="form-group">
<input type="submit" value="Add Student">
</div>
</form>

<div style="margin-top: 30px; font-size: 12px; color: #666; border-top: 1px solid #eee; padding-top: 20px;">
<p><strong>Note:</strong> This form now uses Spring MVC for processing student data.</p>
</div>
</div>
</body>
</html>
Loading