La interfaz está localizada; las descripciones y documentos de las Skills se traducen automáticamente con IA a su idioma. El código, los comandos, rutas y términos técnicos se mantienen en el original, y prevalece el documento del autor.
Explorar Skills
Productividad · SKILL.md

jakarta-migration

jakarta-migration

Migrates Java EE 8 applications to Jakarta EE 9+ by handling namespace rewrites, dependency updates, build configuration changes, and reference implementation transitions.

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentación de la Skill

GitHub

name: jakarta-migration description: Migrates Java EE 8 applications to Jakarta EE 9+ by handling namespace rewrites, dependency updates, build configuration changes, and reference implementation transitions. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: cncf triggers: java ee migration, javax to jakarta, java ee to jakarta ee, namespace change, jakartaee-api, javax.servlet, javax.persistence, migration tool change archetypes:

  • tactical anti_triggers:
  • brainstorming
  • vague ideation
  • non-containerized architecture response_profile: verbosity: low directive_strength: high abstraction_level: operational role: implementation scope: implementation output-format: code content-types:
  • code
  • guidance
  • config
  • do-dont related-skills: jakarta-ee, microprofile

Java EE to Jakarta EE Migration

Guides the systematic migration of Java EE 8 (Java SE 8 / javax.*) applications to Jakarta EE 9+ by handling namespace rewrites, dependency updates, build configuration changes, container-specific adjustments, and validation of migrated code against a Jakarta EE reference implementation.

TL;DR Checklist

  • Inventory all javax.* imports and dependencies using grep/find across the entire project
  • Replace javax.* Maven artifacts with jakarta.* equivalents in pom.xml or build.gradle
  • Run namespace rewrite (javax→jakarta) across all Java source, XML config, and properties files
  • Update deployment descriptors (web.xml, persistence.xml, faces-config.xml) to new namespaces
  • Build against Jakarta EE 10/11 API and deploy to a reference server for smoke testing

When to Use

Use this skill when:

  • Migrating a Java EE 8 application to Jakarta EE 9+ (namespace change from javax.* to jakarta.*)
  • Upgrading from Java EE 7 (JSR 342) or earlier to any Jakarta EE version
  • Adopting Jakarta EE 10 or 11 and needing a structured migration path
  • Resolving namespace conflicts between legacy javax.* libraries and modern jakarta.* dependencies

When NOT to Use

  • Starting a brand-new project — use jakarta.* from day one, no migration needed
  • The application is already on Jakarta EE 9+ — skip directly to feature updates
  • Migrating Spring Boot applications — this is a Java EE namespace change task, not Spring-related

Core Workflow

Step 1: Inventory javax.* Usage

Before making any changes, catalog the full scope of migration. This prevents missing imports or hidden dependencies.

# Find all Java files importing javax.* packages
find . -name "*.java" -exec grep -l "import javax\." {} \; | sort > /tmp/javax-imports.txt

# Count unique javax.* package prefixes
grep -h "import javax\." **/*.java 2>/dev/null | sed 's/.*import \(\(javax\.[a-z]*\)\).*/\1/' | sort -u > /tmp/javax-packages.txt

# Show the counts per package for prioritization
cat /tmp/javax-packages.txt | while read pkg; do
    count=$(grep -r "import $pkg" --include="*.java" . | wc -l)
    echo "$count\t$pkg"
done | sort -rn > /tmp/javax-usage-report.txt

# Inventory javax.* dependencies in pom.xml files
grep -rh "<groupId>javax\." --include="pom.xml" . | sort -u > /tmp/javax-deps.txt

# Generate a summary report
echo "=== Migration Scope Report ==="
echo "Java files with javax.* imports: $(cat /tmp/javax-imports.txt | wc -l)"
echo "Unique javax packages used: $(wc -l < /tmp/javax-packages.txt)"
echo "javax dependencies in Maven: $(wc -l < /tmp/javax-deps.txt)"
cat /tmp/javax-usage-report.txt | head -20

Step 2: Update Build Dependencies

Replace all javax.* Maven/Gradle artifacts with their Jakarta EE equivalents. This is the most critical build-level change.

Before (Java EE 8 pom.xml):

<!-- Java EE 8 full API — javax namespace -->
<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>8.0.1</version>
    <scope>provided</scope>
</dependency>

<!-- Individual javax dependencies -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.persistence</groupId>
    <artifactId>javax.persistence-api</artifactId>
    <version>2.2</version>
</dependency>
<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

After (Jakarta EE 9+ pom.xml):

<!-- Jakarta EE 9 Web Profile — jakarta namespace -->
<dependency>
    <groupId>jakarta.platform</groupId>
    <artifactId>jakarta.jakartaee-api</artifactId>
    <version>9.1.0</version>
    <scope>provided</scope>
</dependency>

<!-- Or Jakarta EE 10/11 for latest specs -->
<dependency>
    <groupId>jakarta.platform</groupId>
    <artifactId>jakarta.jakartaee-api</artifactId>
    <version>10.0.0</version>
    <scope>provided</scope>
</dependency>

<!-- Individual jakarta dependencies (if you prefer fine-grained control) -->
<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.0.0</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>jakarta.persistence</groupId>
    <artifactId>jakarta.persistence-api</artifactId>
    <version>3.1.0</version>
</dependency>

Gradle equivalent (build.gradle):

// Before — Java EE 8
implementation 'javax:javaee-api:8.0.1'

// After — Jakarta EE 9+
implementation 'jakarta.platform:jakarta.jakartaee-api:10.0.0' {
    // Use provided scope for application servers that ship their own implementation
    exclude group: 'com.sun.mail', module: 'jakarta.mail'
}

Step 3: Namespace Rewriting

Perform a recursive namespace rewrite across all source files. The core transformation is javax. → jakarta. in the first package component only (e.g., javax.servlet becomes jakarta.servlet, but javax.transaction.UserTransaction becomes jakarta.transaction.UserTransaction).

Safe bash one-liner for Java sources:

# Recursive namespace rewrite for Java source files
# Handles: javax.servlet, javax.persistence, javax.enterprise, javax.ws.rs, javax.faces, 
#          javax.annotation, javax.validation, javax.inject, javax.json, javax.ejb, javax.mail
find . -name "*.java" -exec sed -i \
    -e 's/import javax\.persistence/import jakarta.persistence/g' \
    -e 's/import javax\.enterprise.import jakarta.enterprise/g' \
    -e 's/import javax\.ws\.rs/import jakarta.ws.rs/g' \
    -e 's/import javax\.servlet/import jakarta.servlet/g' \
    -e 's/import javax\.faces/import jakarta.faces/g' \
    -e 's/import javax\.validation/import jakarta.validation/g' \
    -e 's/import javax\.annotation/import jakarta.annotation/g' \
    -e 's/import javax\.inject/import jakarta.inject/g' \
    -e 's/import javax\.json/import jakarta.json/g' \
    -e 's/import javax\.ejb/import jakarta.ejb/g' \
    -e 's/import javax\.mail/import jakarta.mail/g' \
    -e 's/import javax\.transaction/import jakarta.transaction/g' \
    {} +

# Also handle package declarations (not just imports)
find . -name "*.java" -exec sed -i \
    -e 's/^package javax\.persistence/package jakarta.persistence/g' \
    -e 's/^package javax\.enterprise/package jakarta.enterprise/g' \
    -e 's/^package javax\.ws\.rs/package jakarta.ws.rs/g' \
    -e 's/^package javax\.servlet/package jakarta.servlet/g' \
    -e 's/^package javax\.faces/package jakarta.faces/g' \
    {} +

For XML deployment descriptors (web.xml, faces-config.xml, etc.):

# Update namespace URIs in XML files
find . -name "web.xml" -o -name "faces-config.xml" -o -name "*.xhtml" | xargs -I {} sed -i \
    -e 's/http:\/\/java\.sun\.com\/xml\/ns\/javaee/http:\/\/jakarta\.ee\/xml\/ns\/jakartaee/g' \
    -e 's/"http:\/\/java\.sun\.com\/xmlns\/jboss\/ws_2_0"|"urn:jboss:domain:webservices:2.0"/"http:\/\/jakarta\.ee\/xml\/ns\/jakartaee\/webservices_2_0.xsd"/g' \
    -e 's/xsi:schemaLocation=".*java.sun.com.*xmlns:jakartaee.*"/xsi:schemaLocation="http:\/\/jakarta\.ee\/xml\/ns\/jakartaee http:\/\/jakarta\.ee\/xml\/ns\/jakartaee\/jakartaee_10.xsd"/g' \
    {} +

# Update JAX-WS namespace declarations in web.xml
find . -name "web.xml" -exec sed -i \
    -e 's|<xmlns:ws.*java\.sun\.com|<xmlns:ws http://jakarta.ee/xml/ns/jakartaee|g' \
    {} +

Step 4: Update Deployment Descriptor Namespace Declarations

web.xml before:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
                             http://java.sun.com/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <display-name>My Java EE App</display-name>
    
    <!-- Servlet declarations -->
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.example.MyServlet</servlet-class>
    </servlet>
    
    <!-- Security constraints -->
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Protected Area</web-resource-name>
            <url-pattern>/secure/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>
    
    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-page>/login.xhtml</form-login-page>
        <form-error-page>/error.xhtml</form-error-page>
    </login-config>
</web-app>

web.xml after (Jakarta EE 10):

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee 
                             https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
         version="6.0">
    <display-name>My Jakarta EE App</display-name>

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.example.MyServlet</servlet-class>
    </servlet>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Protected Area</web-resource-name>
            <url-pattern>/secure/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-page>/login.xhtml</form-login-page>
        <form-error-page>/error.xhtml</form-error-page>
    </login-config>
</web-app>

Step 5: Update persistence.xml and faces-config.xml

persistence.xml namespace update:

<!-- Before (Java EE 8) -->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
                                 http://java.sun.com/xml/ns/persistence/persistence_2_2.xsd"
             version="2.2">

<!-- After (Jakarta EE 9+) -->
<persistence xmlns="https://jakarta.ee/xml/ns/jakartaee/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee/persistence 
                                 https://jakarta.ee/xml/ns/jakartaee/persistence_3_1.xsd"
             version="3.1">

faces-config.xml namespace update:

<!-- Before -->
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
                                  http://java.sun.com/xml/ns/javaee/web-facesconfig_2_3.xsd"
              version="2.3">

<!-- After -->
<faces-config xmlns="https://jakarta.ee/xml/ns/jakartaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee 
                                  https://jakarta.ee/xml/ns/jakartaee/web-facesconfig_4_0.xsd"
              version="4.0">

Step 6: Build Verification and Smoke Test

# Clean build cache to avoid stale javax.class artifacts
mvn clean compile -DskipTests

# Verify no javax.* imports remain in compiled classes
javap -cp target/classes -c com.example.MyServlet 2>/dev/null | grep "javax\." && \
    echo "WARNING: javax references found in compiled bytecode!" || \
    echo "OK: No javax references in compiled bytecode"

# Run unit tests
mvn test -Dtest=*Test

# Deploy to a Jakarta EE reference server for smoke testing (example: OpenLiberty)
# docker run -d --name ee-test-server -p 9080:9080 \
#     -v $(pwd)/target/myapp.war:/config/apps/myapp.war \
#     openliberty/open-liberty:kernel-java17-openj9-ubi

# Smoke test the deployed application
curl -s http://localhost:9080/myapp/api/health | python3 -m json.tool || echo "Deployment check failed"

Migration Patterns

Java Source Code: Before and After

Before (Java EE 8 — javax namespace):

package com.example.resource;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;

@RequestScoped
@Path("orders")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class OrderResource {

    @Inject
    private OrderService orderService;

    @PersistenceContext(unitName = "orderPU")
    private EntityManager entityManager;

    @GET
    public Response getOrders() {
        List<OrderDTO> orders = orderService.findAll();
        return Response.ok(orders).build();
    }

    @POST
    public Response createOrder(@Valid OrderRequest request) {
        Order created = orderService.create(request);
        return Response.status(Response.Status.CREATED)
                .entity(created).build();
    }
}

After (Jakarta EE 10 — jakarta namespace):

package com.example.resource;

import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.List;

@RequestScoped
@Path("orders")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class OrderResource {

    @Inject
    private OrderService orderService;

    @PersistenceContext(unitName = "orderPU")
    private EntityManager entityManager;

    @GET
    public Response getOrders() {
        List<OrderDTO> orders = orderService.findAll();
        return Response.ok(orders).build();
    }

    @POST
    public Response createOrder(@Valid OrderRequest request) {
        Order created = orderService.create(request);
        return Response.status(Response.Status.CREATED)
                .entity(created).build();
    }
}

The code structure is identical — only the import package prefixes change. The Jakarta EE 9+ specification API surface matches Java EE 8 for most commonly used features.

Maven Plugin Approach for Automated Migration

The Eclipse Foundation provides a dedicated migration tool that handles namespace rewriting automatically:

<!-- jakartaee-migration-maven-plugin in pom.xml -->
<plugin>
    <groupId>org.eclipse.ee4j</groupId>
    <artifactId>project-api-migration</artifactId>
    <version>1.0.8</version>
    <configuration>
        <namespaces>
            <namespace>
                <from>javax\.persistence</from>
                <to>jakarta.persistence</to>
            </namespace>
            <namespace>
                <from>javax\.servlet</from>
                <to>jakarta.servlet</to>
            </namespace>
            <namespace>
                <from>javax\.enterprise</from>
                <to>jakarta.enterprise</to>
            </namespace>
            <namespace>
                <from>javax\.ws\.rs</from>
                <to>jakarta.ws.rs</to>
            </namespace>
            <namespace>
                <from>javax\.faces</from>
                <to>jakarta.faces</to>
            </namespace>
        </namespaces>
    </configuration>
</plugin>

Migration Tooling

Eclipse EE4J Jakarta EE Migration Tool

The official migration tool from the Eclipse Foundation provides batch namespace rewriting across entire projects:

# Download the CLI migration tool (jakartaee-migration)
curl -LO https://repo1.maven.org/maven2/org/eclipse/ee4j/project-api-migration/1.0.8/project-api-migration-1.0.8.jar

# Run migration on a source directory
java -jar project-api-migration-1.0.8.jar \
    -s ./src/main/java \
    -d ./target/migrated-src \
    --namespace javax.servlet=jakarta.servlet \
    --namespace javax.persistence=jakarta.persistence \
    --namespace javax.enterprise=jakarta.enterprise \
    --namespace javax.ws.rs=jakarta.ws.rs \
    --namespace javax.faces=jakarta.faces \
    --namespace javax.annotation=jakarta.annotation \
    --namespace javax.validation=jakarta.validation \
    --namespace javax.inject=jakarta.inject

# Process XML descriptors
java -jar project-api-migration-1.0.8.jar \
    -s ./src/main/resources/META-INF \
    -d ./target/migrated-resources \
    --xml-namespace http://java.sun.com/xml/ns/javaee=https://jakarta.ee/xml/ns/jakartaee

IDE Migration Support

IDEToolUsage
Eclipse IDEEE4J Migration Plugin (install from Eclipse Marketplace)Right-click project → Migration → Select javax→jakarta mapping. Handles imports, package declarations, and XML namespaces in one operation.
IntelliJ IDEAManual batch replace + JakartaEE pluginUse Find in Files with regex `javax.(servlet
VS CodeExtension: "Jakarta EE Language Support" + Regex replaceSearch and replace using VS Code's built-in multi-file regex with ^.*import javax\. pattern scope limited to .java files.

Gradle Migration Plugin

For Gradle-based projects, the JakartaEE migration is typically done manually since there is no official Gradle plugin:

// build.gradle — update dependencies
dependencies {
    // Replace ALL javax.* artifacts with jakarta.* equivalents
    compileOnly 'jakarta.platform:jakarta.jakartaee-api:10.0.0'
    
    // Individual Jakarta dependencies (if you don't use the full API umbrella)
    compileOnly 'jakarta.servlet:jakarta.servlet-api:6.0.0'
    compileOnly 'jakarta.persistence:jakarta.persistence-api:3.1.0'
    compileOnly 'jakarta.enterprise:jakarta.enterprise.cdi-api:4.0.1'
    compileOnly 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0'
    compileOnly 'jakarta.faces:jakarta.faces-api:4.0.1'
}

Common Pitfalls During Migration

PitfallCauseResolution
Transitive dependencies still using javax*A third-party library depends on javax.servlet or javax.persistence directly (not through the Jakarta umbrella)Exclude the old dependency and use its Jakarta-compatible replacement. Check with `mvn dependency:tree
Build cache retaining stale javax classes~/.m2/repository or build/ directories contain compiled classes from before the migrationRun mvn clean install -U (forces update snapshots) and delete all target/ and build/ directories across all modules
Annotation processor mismatchesLombok, MapStruct, or other annotation processors generate code that references javax typesUpdate annotation processor versions to those compatible with Jakarta EE 9+. For example, Lombok ≥ 1.18.30 supports jakarta namespaces.
Container-specific API changesSome containers add vendor-specific annotations (e.g., @org.jboss.weld.annotation.Transient) that are not part of Jakarta EEReplace container-specific annotations with standard Jakarta EE equivalents or remove them if no longer needed in the new container
EL expressions with javax referencesJSF Facelets pages may contain #{javax.faces.context} references in custom EL resolversSearch all .xhtml files for javax. and update to jakarta. namespaces. Check backing beans that use javax imports.
Jakarta EE 9 vs 10 module path changesJakarta EE 9+ splits APIs into multiple JARs on the module path; class loader behavior differs from single-jar Java EE 8Test thoroughly with the target container — some applications rely on implicit class loading that no longer works in modular deployments

Constraints

MUST DO

  • Run a full inventory of javax.* usage before starting any migration (imports, dependencies, annotations, XML namespaces)
  • Verify every transitive dependency uses Jakarta EE 9+ compatible artifacts after the build update
  • Test the migrated application on the target container — different servers may have varying compliance levels
  • Update all XML deployment descriptors (web.xml, persistence.xml, faces-config.xml) to match the new namespace URIs
  • Run unit and integration tests after migration to verify behavioral equivalence

MUST NOT DO

  • Perform a blind find-and-replace of all javax strings without verifying namespace boundaries — some javax references are intentional (e.g., class names, comments) or belong to unrelated libraries
  • Mix javax.* and jakarta.* in the same classpath — this will cause ClassNotFoundException at runtime due to Java module path conflicts
  • Skip the build cache cleanup (mvn clean) before testing post-migration — stale compiled classes with javax imports will cause subtle failures
  • Deploy to production without smoke testing on a Jakarta EE reference implementation — namespace changes alone do not guarantee behavioral equivalence

Output Template

When executing or reviewing a Jakarta EE migration, produce:

  1. Migration Scope Report — Count of files/imports affected per javax.* package
  2. Dependency Changes — Before/after pom.xml (or build.gradle) showing all artifact replacements
  3. Namespace Rewrite Verification — Command output confirming zero remaining javax. references in Java source and XML descriptors
  4. Build Results — Compilation output with any errors related to namespace mismatches or missing Jakarta dependencies
  5. Deployment Validation — Smoke test results from the target Jakarta EE server

Related Skills

SkillPurpose
jakarta-eeReference for Jakarta EE platform specifications, container selection, and architecture patterns used after migration
microprofileCloud-native MicroProfile specs to add after migration if the application targets Kubernetes or service mesh deployments

Live References

Authoritative documentation for migrating from Java EE to Jakarta EE.

Skills guardadas