Java EE to Jakarta EE with JDK-17, and Spring Boot: Step by step guide
Do’s and Don’ts
Java EE to Jakarta EE with JDK-17, and Spring Boot: Step by step guide
Do’s and Don’ts

Story of How I Migrated from Javax to Jakarta
When migrating to JDK-17, it is important to migrate from Java EE to Jakarta EE to support continued development, security, and compatibility with newer version of Java. Also, there has been a rebranding of javax to jakarta after Oracle transferred its ownership to Eclipse Foundation in 2019. As Oracle is the developer of Java EE ( javax is part of it), the namespace javax has been renamed to jakarta to avoid trademark issues. In this article, I will share a few tips and step-by-step guide to make this transition smoother. We will also focus on other libraries which were using javax and completely migrate tojakarta without any reference to javax.
Before this migration, my application used primefaces, java 11, and other javax libraries.
Prepare the environment
- Download JDK-17 jar from official Oracle website
- IDE: Apache NetBeans is good as it supports EL Expressions in Facelets. I used Eclipse (latest, 2024–09)
- Coffee (very important, will need it every time till the app is stable)
[A sip of Coffee] Let’s start
Step -1 (minus 1): Do not replace all javax to jakarta
NOT all libraries are converted tojakarta. Some are still in javax. So its a bad idea to replace all javax with jakarta. (As of early 2024)
A few libraries like, javax.servlet, javax.ejb, javax.persistence, javax.transaction, javax.jms, javax.mail, javax.xml, javax.ws.rs, javax.validation, javax.json etc.are not transformed to jakarta yet.
Step 0: Start by pom
First, start by upgrading to JDK-17. I also upgraded to spring-boot v3.1 as part of this upgrade.
<jakartaee-api.version>10.0.0</jakartaee-api.version>
<jdkVersion>17</jdkVersion>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakartaee-api.version}</version>
<scope>provided</scope>
</dependency>
To upgrade to Spring-Boot:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.8</version>
<relativePath />
</parent>
Step 1: web.xml
Replace all **javax.faces namespace to `jakarta.faces`**in web.xml
Step 2: faces-config.xml changes
Add the following. This is basically for all the expression beans for resolving name from spring container.
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
<lifecycle>
<phase-listener>org.springframework.web.jsf.DelegatingPhaseListenerMulticaster</phase-listener>
</lifecycle>
Step 3: Convert classes to Spring and also add Named annotation (for EL Expressions).
Migrate all the managed beans defined in faces-config.xml to annotation based.
Example:
<managed-bean>
<managed-bean-name>loginBean</managed-bean-name>
<managed-bean-class>com.company.ui.login.LoginBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
to
import org.springframework.web.context.annotation.SessionScope;
import jakarta.inject.Named;
@Named(value="pc_LoginBean")
@SessionScope
public class LoginBean {
}
Remember, if a bean is defined as<managed-bean-scope>request</managed-bean-scope> (Request Scoped) then its class should also be annotated with RequestScope instead of SessionScope above.
This is important step in migrating to spring boot with EL Expressions. Choosing between RequestScope or SessionScope affects the application. Generally, I used RequestScope for controllers, and DAO objects. For beans I used SessionScope.
Step 4: Dependency Hierarchy
In Eclipse, go to pom.xml and switch to Dependency Hierarchy tab. Filter by javaxin top right corner. It will show all libraries who uses javax. Visit each library on https://mvnrepository.com/ and search for its jakarta compatible version.
Remember, you can also give a try by adding <classifier>jakarta</classifier> in dependency for the library.
Also, explicitly exclude javax dependencies / older jakarta dependencies and include them again. (This is great step to minimize errors and resolve conflicting dependencies issue)
You need to repeat this step for each library till the application builds and runs successfully. If everything is good, the application should be up.
[Refill coffee after resolving each library]
Extra Resource: Integration of Log4j2.xml
You can also migrate traditional log4j to log4j2.xml
POM changes for log4j2
Exclude current log dependencies especially log4j-to-slf4j, log4j-api, spring-boot-starter-logging and add:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Initialization of log4j2
public static void loadLog4j2(String log4j2Propertiesfilepath)
throws ResourceLoadException, IOException {
Configurator.initialize(null, log4j2Propertiesfilepath);
}
Sample log4j2.xml file
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace">
<Properties>
<Property name="baseDir">${sys:log.baseDir}</Property>
<Property name="currentTimestamp">$${date:yyyyMMdd_HHmmss}</Property>
<Property name="smtpEnabled">${sys:smtp.enabled}</Property>
<Property name="smtpUsername">${sys:smtp.username}</Property>
<Property name="smtpPassword">${sys:smtp.password}</Property>
</Properties>
<Appenders>
<!-- Console appender configuration -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
</Console>
<!-- Rolling file appender configuration -->
<RollingFile name="File"
fileName="${baseDir}/project_${currentTimestamp}_log.log" append="true"
filePattern="${baseDir}/project_${currentTimestamp}_%i_log.log">
<Policies>
<SizeBasedTriggeringPolicy size="1000KB" />
</Policies>
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
<DefaultRolloverStrategy max="5"/>
</RollingFile>
<!-- SMTP appender configuration -->
<SMTP name="Email"
subject="Error in ProjectA - Development"
to="developers@project.com"
from="projectA@project.com"
smtpHost="smtp.sendgrid.net"
smtpPort="587"
smtpProtocol="smtp"
smtpUsername="${smtpUsername}"
smtpPassword="${smtpPassword}">
<PatternLayout pattern="%d{ABSOLUTE} %5p %c{1}:%L - %m%n" />
</SMTP>
</Appenders>
<Loggers>
<Logger name="myLogs" level="error" additivity="false">
<AppenderRef ref="File" />
</Logger>
<!-- Root logger referring to console and email appenders -->
<Root level="error" additivity="false">
<AppenderRef ref="Console" />
<AppenderRef ref="File" />
<AppenderRef ref="${sys:smtp.enabled}" />
</Root>
</Loggers>
</Configuration>
I set up the values of log.baseDir, smtp.enabled, smtp.username, smtp.password as system variables stored in properties file of my project. It will always be loaded on start-up of the application.
Existing Issues (Especially for EL Expressions in Facelets)
In javax, if you opened any .xhtml files, and pressed control and clicked on any java class or method, it used to navigate to that specific method/file.
After migration, this has stopped working and so is code assist in xhtml files for java classes/methods.
However, if you use Apache NetBeans, and while opening project if you choose “Transform to Jakarta EE” option, the above mentioned issue works.
I have raised this issue in StackOverflow, and Eclipse Community Forum. A user has already reported this in eclipse-jsf GitHub project.
StackOverflow: https://stackoverflow.com/questions/78991647/controlclick-on-el-expression-in-facelets-not-working-in-eclipse-after-migratio
Eclipse Community Forum: https://www.eclipse.org/forums/index.php?t=msg&goto=1871190&#msg_1871190
eclipse-jsf GitHub project: https://github.com/eclipse-jsf/webtools.jsf/issues/8
Cheers!
메타데이터
- post_id
- e73744d3e2f4
- slug
- java-ee-to-jakarta-ee-with-jdk-17-and-spring-boot-step-by-step-guide-e73744d3e2f4
- url
- https://medium.com/@hsjoshi28/java-ee-to-jakarta-ee-with-jdk-17-and-spring-boot-step-by-step-guide-e73744d3e2f4
- canonical_url
- https://medium.com/@hsjoshi28/java-ee-to-jakarta-ee-with-jdk-17-and-spring-boot-step-by-step-guide-e73744d3e2f4
- author_url
- https://medium.com/@hsjoshi28
- status
- ok
- fetched_at
- 2026-07-22 17:31:28