Skip to main content

jakarta-java25-migration

Invoke this skill to migrate Java 8/11 to Java 25 and javax.* to jakarta.* namespaces. Detects Java version < 25 in pom.xml or javax.* imports in source files. Foundation skill - invoke before sdk-replacement.

معلومات المصدر

المستودع
SAP-samples/btp-neo-java-app-migration
آخر نشاط في المصدر
٢٩ يوليو ٢٠٢٦ في ١٣:٤٨
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٦
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
jakarta-java25-migration
description
Invoke this skill to migrate Java 8/11 to Java 25 and javax.* to jakarta.* namespaces. Detects Java version < 25 in pom.xml or javax.* imports in source files. Foundation skill - invoke before sdk-replacement.
disable-model-invocation
false
allowed-tools
Read, Edit, Write, Bash, Grep, Glob
# Jakarta EE 10 and Java 25 Migration Migrate your Neo Java application from Java 8/11 and Java EE to Java 25 and Jakarta EE 10. ## Purpose Upgrade the Java runtime and migrate from `javax.*` namespaces to `jakarta.*` namespaces for forward compatibility with modern application servers and Cloud Foundry buildpacks. ## Detection This skill applies if any of these patterns are found: ### In pom.xml ```xml <!-- Java 8 or 11 source/target --> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <!-- OR --> <properties> <java.version>11</java.version> </properties> ``` ### In Java source files ```java // javax.* imports indicate pre-Jakarta EE import javax.servlet.*; import javax.persistence.*; import javax.annotation.*; import javax.mail.*; import javax.ejb.*; ``` ## Prerequisites - None (this is typically the first migration step) - Maven 3.6+ installed - Java 25+ available on PATH ## Transformation Steps ### Step 0: Create Migration Copy Before making any changes, create a copy of the application directory as a sibling folder. All migration work is done on this copy — the original stays untouched. ```bash APP_DIR=$(pwd) APP_NAME=$(basename "$APP_DIR") COPY_DIR="$(dirname "$APP_DIR")/${APP_NAME}-cf-migration" if [ -d "$COPY_DIR" ]; then echo "Migration copy already exists at $COPY_DIR — using it." else cp -r "$APP_DIR" "$COPY_DIR" echo "Created migration copy at $COPY_DIR" fi cd "$COPY_DIR" ``` Now that we are inside the copy, create the `.migration/` directory and save the config there: ```bash mkdir -p .migration ``` Save the paths to `.migration/cf-migration-config.json` (create or update the file): ```json { "sourceAppDir": "<original APP_DIR>", "migrationAppDir": "<COPY_DIR>" } ``` > **All subsequent steps in this skill and all downstream skills (`sdk-replacement`, `authentication-xsuaa`, `mta-descriptor`, etc.) must operate inside `$COPY_DIR`. The `.migration/` directory is inside the copy, not the original.** ### Step 1: Update Java Version in pom.xml **Before:** ```xml <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> ``` **After:** ```xml <properties> <maven.compiler.source>25</maven.compiler.source> <maven.compiler.target>25</maven.compiler.target> </properties> ``` > 🛑 **HARD RULE — pin the runtime JRE in the mtad, or the app 500s on every request.** > You just set `maven.compiler.target` to 25, so the WAR is Java 25 bytecode (class > file version 69). `sap_java_buildpack_jakarta`'s **default** JRE is NOT 25 (it is > currently 21) — if you do not pin it, Tomcat cannot load your servlets and fails with > `java.lang.UnsupportedClassVersionError: ... class file version 69.0, this version of > the Java Runtime only recognizes class file versions up to 65.0`, marks the servlet > unavailable, and **every request returns HTTP 500** (the app still shows `running 1/1`, > so this is easy to miss until an integration test hits it). The deployed module's > `properties:` **MUST** include BOTH env vars: > > ```yaml > properties: > JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']" > JBP_CONFIG_SAP_MACHINE_JRE: '{ version: 25.+ }' > ``` > > The `mta-descriptor` skill's `mtad-base.yaml` template already sets these — if you > start from it, keep them; if you hand-write the mtad, add them. > > ✅ **After writing the mtad, verify:** `grep JBP_CONFIG_SAP_MACHINE_JRE <mtad>` must > return the line above. Rule of thumb: **`maven.compiler.target` must equal the major > version in `JBP_CONFIG_SAP_MACHINE_JRE`** (both 25). ### Step 2: Run OpenRewrite Migration Execute the OpenRewrite recipes to automatically migrate code: ```bash mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \ -Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:RELEASE \ -Drewrite.activeRecipes=org.openrewrite.java.migrate.UpgradeToJava25,org.openrewrite.java.migrate.jakarta.JakartaEE10 \ -Drewrite.exportDatatables=true ``` > **Note:** > - Make sure you have Java SE 25 and the latest Maven version installed > - The recipe artifact coordinates ensure the latest migration recipes are downloaded > - **`-Drewrite.activeRecipes` must be passed exactly once.** Maven turns each `-D` into a Java system property, and a property has only one value per key — passing two `-D rewrite.activeRecipes=...` flags silently keeps only the last one and the first recipe is dropped without a warning. Always pass a single comma-separated list. See [the OpenRewrite Maven plugin reference](https://docs.openrewrite.org/reference/rewrite-maven-plugin) for the canonical syntax. This command will: - Update Java language features to Java 25 - Replace `javax.*` imports with `jakarta.*` - Update deprecated API usages - Migrate web.xml namespace declarations ### Step 2b: Fix OpenRewrite side-effects in pom.xml OpenRewrite makes two changes that must be corrected after it runs: #### 2b-1: Restore `jakarta.servlet-api` to `provided` scope OpenRewrite replaces `javax.servlet:javax.servlet-api` with `jakarta.servlet:jakarta.servlet-api` but sets `<scope>compile</scope>`. This is wrong — `sap_java_buildpack_jakarta` provides the servlet API at runtime, so the scope must be `provided`. If left as `compile`, the servlet API JAR is packaged into the WAR and conflicts with the buildpack's version, causing all servlets to return 404 after a successful deploy. **Detect and fix:** ```bash # Check if scope was set to compile grep -A4 "jakarta.servlet-api" pom.xml | grep "compile" ``` If the above returns a result, change the scope: ```xml <!-- WRONG — causes 404 after deploy --> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>compile</scope> </dependency> <!-- Change <scope>compile</scope> to <scope>provided</scope> — see CORRECT block below --> <!-- CORRECT --> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency> ``` > If `cf-tomcat-bom` is imported in `<dependencyManagement>`, the version tag can be omitted — the BOM manages it. #### 2b-2: Replace `javax.servlet:jstl` with Jakarta JSTL (Conditional) OpenRewrite does NOT migrate the old JSTL library. If `javax.servlet:jstl` is present in pom.xml, it must be replaced with the Jakarta EE 10 compatible version. **Detect:** ```bash grep -B2 "jstl" pom.xml | grep "javax.servlet" ``` If the above returns a result, replace the dependency: **Before:** ```xml <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> ``` **After:** ```xml <dependency> <groupId>jakarta.servlet.jsp.jstl</groupId> <artifactId>jakarta.servlet.jsp.jstl-api</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>jakarta.servlet.jsp.jstl</artifactId> <version>3.0.1</version> </dependency> ``` ### Step 3: Handle OpenCMIS Caveat > **Important:** The `org.apache.chemistry.opencmis` libraries have NOT been migrated to Jakarta EE. If your application uses OpenCMIS (Document Management), you must exclude it from the Jakarta migration. **Check for OpenCMIS usage:** ```bash grep -r "opencmis" pom.xml grep -r "org.apache.chemistry" src/main/java/ ``` **If OpenCMIS is used, add these specific exclusions:** ```xml <dependency> <groupId>org.apache.chemistry.opencmis</groupId> <artifactId>chemistry-opencmis-client-impl</artifactId> <version>${opencmis.version}</version> <exclusions> <exclusion> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> </exclusion> <exclusion> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> </exclusion> <exclusion> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-ws-policy</artifactId> </exclusion> </exclusions> </dependency> ``` > **Note:** Add the excluded libraries as separate dependencies using their latest versions, if applicable. ### Step 4: Update web.xml Namespace (if not auto-migrated) **Before:** ```xml <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"> ``` **After:** ```xml <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"> ``` ### Step 5: Common Import Migrations | Before (javax.*) | After (jakarta.*) | |------------------|-------------------| | `javax.servlet.*` | `jakarta.servlet.*` | | `javax.servlet.http.*` | `jakarta.servlet.http.*` | | `javax.persistence.*` | `jakarta.persistence.*` | | `javax.annotation.*` | `jakarta.annotation.*` | | `javax.ejb.*` | `jakarta.ejb.*` | | `javax.mail.*` | `jakarta.mail.*` | | `javax.ws.rs.*` | `jakarta.ws.rs.*` | | `javax.json.*` | `jakarta.json.*` | | `javax.validation.*` | `jakarta.validation.*` | | `com.fasterxml.jackson.jaxrs.*` | `com.fasterxml.jackson.jakarta.rs.*` | > **Important — Jackson JAX-RS providers:** The Jackson JAX-RS provider artifact changed from `jackson-jaxrs-json-provider` (javax) to `jackson-jakarta-rs-json-provider` (jakarta). In addition to the package rename, the class `JacksonJaxbJsonProvider` was renamed to `JacksonXmlBindJsonProvider`. The simpler `JacksonJsonProvider` (which supports JAXB annotations too) is the recommended replacement. OpenRewrite will update Java `import` statements, but it does **not** update class references in `web.xml`. If your `web.xml` configures JAX-RS providers via `<init-param>`, you must update those manually. #### Update web.xml JAX-RS Provider References **Detect:** ```bash grep -r "com.fasterxml.jackson.jaxrs" --include="*.xml" src/main/webapp/ ``` If this returns results, update the class name: **Before:** ```xml <init-param> <param-name>jaxrs.providers</param-name> <param-value> com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider </param-value> </init-param> ``` **After:** ```xml <init-param> <param-name>jaxrs.providers</param-name> <param-value> com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider </param-value> </init-param> ``` > **Note:** The available classes in the Jakarta artifact are `JacksonJsonProvider` (recommended) and `JacksonXmlBindJsonProvider`. The old name `JacksonJaxbJsonProvider` does **not** exist in the Jakarta artifact — using it will cause `ClassNotFoundException` at runtime even though the JAR is in the WAR. Also update the Maven dependency: **Before:** ```xml <dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-json-provider</artifactId> </dependency> ``` **After:** ```xml
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub