Skip to content
Development
Skill

/java-migration

Guide for upgrading Java projects between major versions (8→11→17→21→25). Use when user says "upgrade Java", "migrate to Java 25", "update Java version", or when modernizing legacy projects.

From plugin
claude-code-java
77218 skills

Claude Code

$ npx -y skills add decebals/claude-code-java --skill java-migration --agent claude-code

SKILL.md

java-migration.SKILL.md
name: java-migration
description: Guide for upgrading Java projects between major versions (8→11→17→21→25). Use when user says "upgrade Java", "migrate to Java 25", "update Java version", or when modernizing legacy projects.
license: MIT

Java Migration Skill

Step-by-step guide for upgrading Java projects between major versions.

When to Use

  • User says "upgrade to Java 25" / "migrate from Java 8" / "update Java version"
  • Modernizing legacy projects
  • Spring Boot 2.x → 3.x → 4.x migration
  • Preparing for LTS version adoption

Migration Paths

Java 8 (LTS) → Java 11 (LTS) → Java 17 (LTS) → Java 21 (LTS) → Java 25 (LTS)
     │              │               │              │               │
     └──────────────┴───────────────┴──────────────┴───────────────┘
                         Always migrate LTS → LTS

---

Quick Reference: What Breaks

| From → To | Major Breaking Changes | |-----------|------------------------| | 8 → 11 | Removed `javax.xml.bind`, module system, internal APIs | | 11 → 17 | Sealed classes (preview→final), strong encapsulation | | 17 → 21 | Pattern matching changes, `finalize()` deprecated for removal | | 21 → 25 | Security Manager removed, Unsafe methods removed, 32-bit dropped |

---

Migration Workflow

Step 1: Assess Current State

# Check current Java version
java -version

# Check compiler target in Maven
grep -r "maven.compiler" pom.xml

# Find usage of removed APIs
grep -r "sun\." --include="*.java" src/
grep -r "javax\.xml\.bind" --include="*.java" src/

Step 2: Update Build Configuration

**Maven:**

<properties>
    <java.version>21</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
</properties>

<!-- Or with compiler plugin -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.12.1</version>
    <configuration>
        <release>21</release>
    </configuration>
</plugin>

**Gradle:**

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

Step 3: Fix Compilation Errors

Run compile and fix errors iteratively:

mvn clean compile 2>&1 | head -50

Step 4: Run Tests

mvn test

Step 5: Check Runtime Warnings

# Run with illegal-access warnings
java --illegal-access=warn -jar app.jar

---

Java 8 → 11 Migration

Removed APIs

| Removed | Replacement | |---------|-------------| | `javax.xml.bind` (JAXB) | Add dependency: `jakarta.xml.bind-api` + `jaxb-runtime` | | `javax.activation` | Add dependency: `jakarta.activation-api` | | `javax.annotation` | Add dependency: `jakarta.annotation-api` | | `java.corba` | No replacement (rarely used) | | `java.transaction` | Add dependency: `jakarta.transaction-api` | | `sun.misc.Base64*` | Use `java.util.Base64` | | `sun.misc.Unsafe` (partially) | Use `VarHandle` where possible |

Add Missing Dependencies (Maven)

<!-- JAXB (if needed) -->
<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>4.0.4</version>
    <scope>runtime</scope>
</dependency>

<!-- Annotation API -->
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

Module System Issues

If using reflection on JDK internals, add JVM flags:

--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED

**Maven Surefire:**

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <argLine>
            --add-opens java.base/java.lang=ALL-UNNAMED
        </argLine>
    </configuration>
</plugin>

New Features to Adopt

// var (local variable type inference)
var list = new ArrayList<String>();  // instead of ArrayList<String> list = ...

// String methods
"  hello  ".isBlank();      // true for whitespace-only
"  hello  ".strip();        // better trim() (Unicode-aware)
"line1\nline2".lines();     // Stream<String>
"ha".repeat(3);             // "hahaha"

// Collection factory methods (Java 9+)
List.of("a", "b", "c");     // immutable list
Set.of(1, 2, 3);            // immutable set
Map.of("k1", "v1");         // immutable map

// Optional improvements
optional.ifPresentOrElse(
    value -> process(value),
    () -> handleEmpty()
);

// HTTP Client (replaces HttpURLConnection)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com"))
    .build();
HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

---

Java 11 → 17 Migration

Breaking Changes

| Change | Impact | |--------|--------| | Strong encapsulation | `--illegal-access` no longer works, must use explicit `--add-opens` | | Sealed classes (final) | If you used preview features | | Pattern matching instanceof | Preview → final syntax change |

New Features to Adopt

// Records (immutable data classes)
public record User(String name, String email) {}
// Auto-generates: constructor, getters, equals, hashCode, toString

// Sealed classes
public sealed class Shape permits Circle, Rectangle {}
public final class Circle extends Shape {}
public final class Rectangle extends Shape {}

// Pattern matching for instanceof
if (obj instanceof String s) {
    System.out.println(s.length());  // s already cast
}

// Switch expressions
String result = switch (day) {
    case MONDAY, FRIDAY -> "Work";
    case SATURDAY, SUNDAY -> "Rest";
    default -> "Midweek";
};

// Text blocks
String json = """
    {
Read more
@decebals
Ships withclaude-code-java

Agent Skills for Java projects, following the open Agent Skills specification This project is not affiliated with Anthropic.

Stars on GitHub

Momentum

stars in total
772
Star history of decebals/claude-code-java on GitHub, a chart by star-history.com

Other skills on claude-code-java.

clean-code

clean-code

Clean Code principles (DRY, KISS, YAGNI), naming, function design and readability. Use when code is hard to read, with long…

design-patterns

design-patterns

Common design patterns with Java examples (Factory, Builder, Strategy, Observer, Decorator, etc.). Use when user asks "implement…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about java-migration.

Which coding agents can use java-migration?
java-migration installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.