{"id":2165,"date":"2026-02-20T10:42:01","date_gmt":"2026-02-20T05:12:01","guid":{"rendered":"https:\/\/sharanamshah.com\/mymusings\/?p=2165"},"modified":"2026-02-20T10:42:23","modified_gmt":"2026-02-20T05:12:23","slug":"how-to-automate-java-ee-to-jakarta-ee-namespace-migration-with-python","status":"publish","type":"post","link":"https:\/\/sharanamshah.com\/mymusings\/blog\/2026\/02\/20\/how-to-automate-java-ee-to-jakarta-ee-namespace-migration-with-python\/","title":{"rendered":"How to Automate Java EE to Jakarta EE Namespace Migration with Python"},"content":{"rendered":"<h1>How to automate Java EE to Jakarta EE namespace migration with Python<\/h1>\n<h2>The real-world scenario<\/h2>\n<p>Imagine you are tasked with upgrading a decade-old enterprise application from <b>Java EE 8<\/b> to <b>Jakarta EE 10<\/b>. The biggest hurdle is the namespace change: almost every import and XML configuration must change from <b>javax.*<\/b> to <b>jakarta.*<\/b>. Doing this manually for thousands of <b>.java<\/b>, <b>web.xml<\/b>, and <b>persistence.xml<\/b> files is a recipe for carpal tunnel syndrome and subtle bugs. It is like trying to rename a specific brand of bolt in every machine across a factory floor. This script acts as your automated technician, swapping every relevant label instantly and accurately.<\/p>\n<h2>The solution<\/h2>\n<p>We will use a Python script leveraging the <b>pathlib<\/b> library for robust file system navigation and the <b>re<\/b> module for precise string replacement. The script recursively scans a project directory, identifies source and configuration files, and applies a mapping of legacy <b>javax<\/b> packages to their modern <b>jakarta<\/b> equivalents while preserving unrelated namespaces like <b>javax.sql<\/b> or <b>javax.crypto<\/b> which did not change.<\/p>\n<h2>Prerequisites<\/h2>\n<p>Ensure you have the following installed on your system:<\/p>\n<ul>\n<li><b>Python 3.7<\/b> or higher<\/li>\n<li>Write access to the project folder you wish to migrate<\/li>\n<\/ul>\n<h2>The code<\/h2>\n<pre><code>\n\"\"\"\n-----------------------------------------------------------------------\nAuthors: Sharanam &amp; Vaishali Shah\nRecipe: Jakarta EE Namespace Migrator\nIntent: Automatically update javax namespaces to jakarta in source files.\n-----------------------------------------------------------------------\n\"\"\"\n\nimport re\nfrom pathlib import Path\n\ndef migrate_namespaces(target_dir):\n    # Define the mapping of legacy namespaces to Jakarta EE equivalents\n    # Note: We focus on namespaces that actually moved to Jakarta\n    mappings = {\n        r'javax.servlet': 'jakarta.servlet',\n        r'javax.persistence': 'jakarta.persistence',\n        r'javax.ejb': 'jakarta.ejb',\n        r'javax.el': 'jakarta.el',\n        r'javax.faces': 'jakarta.faces',\n        r'javax.inject': 'jakarta.inject',\n        r'javax.json': 'jakarta.json',\n        r'javax.jws': 'jakarta.jws',\n        r'javax.mail': 'jakarta.mail',\n        r'javax.resource': 'jakarta.resource',\n        r'javax.security.auth.message': 'jakarta.security.auth.message',\n        r'javax.security.enterprise': 'jakarta.security.enterprise',\n        r'javax.websocket': 'jakarta.websocket',\n        r'javax.ws.rs': 'jakarta.ws.rs',\n        r'javax.xml.bind': 'jakarta.xml.bind',\n        r'javax.xml.soap': 'jakarta.xml.soap',\n        r'javax.xml.ws': 'jakarta.xml.ws',\n        r'javax.batch': 'jakarta.batch',\n        r'javax.enterprise': 'jakarta.enterprise',\n        r'javax.validation': 'jakarta.validation',\n        r'http:\/\/xmlns.jcp.org\/xml\/ns\/javaee': 'https:\/\/jakarta.ee\/xml\/ns\/jakartaee'\n    }\n\n    # Define file types that usually contain these namespaces\n    extensions = {'.java', '.xml', '.properties', '.jsp', '.tag'}\n\n    base_path = Path(target_dir)\n    \n    if not base_path.exists():\n        print(f\"Error: Path {target_dir} does not exist.\")\n        return\n\n    print(f\"Starting migration in: {base_path.resolve()}\")\n\n    files_modified = 0\n\n    # Walk through the directory recursively\n    for file_path in base_path.rglob('*'):\n        if file_path.suffix in extensions:\n            try:\n                content = file_path.read_text(encoding='utf-8')\n                new_content = content\n                \n                # Apply each mapping using regex\n                for old_ns, new_ns in mappings.items():\n                    new_content = re.sub(old_ns, new_ns, new_content)\n\n                if new_content != content:\n                    file_path.write_text(new_content, encoding='utf-8')\n                    print(f\"Updated: {file_path.relative_to(base_path)}\")\n                    files_modified += 1\n            except Exception as e:\n                print(f\"Could not process {file_path}: {e}\")\n\n    print(f\"Migration complete. Total files modified: {files_modified}\")\n\nif __name__ == \"__main__\":\n    # Change 'my-jakarta-project' to your actual project folder\n    target_project_directory = \"src\" \n    migrate_namespaces(target_project_directory)\n<\/code><\/pre>\n<h2>Code walkthrough<\/h2>\n<p>First, we initialize a <b>mappings<\/b> dictionary. This is the core logic, containing pairs of old patterns and new strings. We use <b>Raw Strings<\/b> for the keys because <b>javax.servlet<\/b> contains dots which are special characters in <b>Regex<\/b>; we must escape them.<\/p>\n<p>The script uses <b>Path.rglob(&#8216;*&#8217;)<\/b> to perform a recursive search. Unlike older methods, <b>pathlib<\/b> handles different operating system path separators automatically, making this script cross-platform. We filter for specific <b>extensions<\/b> like <b>.java<\/b> and <b>.xml<\/b> to avoid corrupting binary files like images or compiled classes.<\/p>\n<p>Inside the loop, we read the file content as <b>UTF-8<\/b>. We use <b>re.sub()<\/b> to perform the replacement. If the <b>new_content<\/b> differs from the original <b>content<\/b>, we write the changes back to the disk. This minimizes disk I\/O by only saving files that actually required updates.<\/p>\n<h2>Sample output<\/h2>\n<p>When you run the script in the root of your project, you will see the following progress in your <b>Terminal<\/b>:<\/p>\n<pre><code>\nStarting migration in: \/Users\/sharanam\/projects\/legacy-app\nUpdated: src\/main\/java\/com\/example\/UserServlet.java\nUpdated: src\/main\/resources\/META-INF\/persistence.xml\nUpdated: src\/main\/webapp\/WEB-INF\/web.xml\nUpdated: src\/main\/java\/com\/example\/entity\/User.java\nMigration complete. Total files modified: 4\n<\/code><\/pre>\n<h2>Conclusion<\/h2>\n<p>Automating the transition to <b>Jakarta EE<\/b> saves hours of tedious work and eliminates the risk of missing a single import buried in a large codebase. By using this Python utility, you ensure consistency across your entire project. Always remember to run this script on a fresh <b>Git<\/b> branch so you can review the diffs before committing the architectural shift.<\/p>\n<hr style=\"margin: 50px 0;border: 0;border-top: 1px solid #eaeaea\">\n<div style=\"background-color: #fcfcfc;padding: 35px;border-left: 5px solid #d63638;border-radius: 6px\">\n<h3 style=\"margin-top: 0;color: #23282d;font-size: 24px;font-weight: 700\">\ud83d\ude80 Don&#8217;t Just Learn Jakarta EE \u2014 Master It.<\/h3>\n<p style=\"font-size: 17px;line-height: 1.6;color: #444;margin-bottom: 20px\">\n            This tutorial was just the tip of the iceberg. To truly advance your career and build <strong>professional-grade systems<\/strong>, you need the full architectural blueprint.\n        <\/p>\n<p style=\"font-size: 17px;line-height: 1.6;color: #444;margin-bottom: 25px\">\n            My book, <strong><a href=\"https:\/\/sharanamshah.com\/mymusings\/home\/books-ive-authored\/jakarta-ee-10-for-beginners\/\" target=\"_blank\" style=\"color: #d63638;text-decoration: underline\">Jakarta EE 10 For Beginners<\/a><\/strong>, takes you from &#8220;making it work&#8221; to &#8220;making it scale.&#8221; I cover advanced patterns, real-world case studies, and the industry best practices that senior engineers use daily.\n        <\/p>\n<p style=\"margin-bottom: 0\">\n            <a href=\"https:\/\/sharanamshah.com\/mymusings\/home\/books-ive-authored\/jakarta-ee-10-for-beginners\/\" target=\"_blank\" style=\"background-color: #d63638;color: white;padding: 15px 30px;text-decoration: none;border-radius: 5px;font-weight: bold;font-size: 18px;display: inline-block\"><br \/>\n                \ud83d\udcd6 Grab Your Copy Now &rarr;<br \/>\n            <\/a>\n        <\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to use Python to automate the migration of legacy javax namespaces to the new jakarta namespaces in your Jakarta EE projects.<\/p>\n","protected":false},"author":1,"featured_media":1989,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[94],"tags":[],"class_list":["post-2165","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-everyday-automation-hacks"],"_links":{"self":[{"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/posts\/2165","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/comments?post=2165"}],"version-history":[{"count":1,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/posts\/2165\/revisions"}],"predecessor-version":[{"id":2175,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/posts\/2165\/revisions\/2175"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/media\/1989"}],"wp:attachment":[{"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/media?parent=2165"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/categories?post=2165"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/tags?post=2165"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}