Java Upgrade
GitHubOfficialFirst committed by jduboisDistributed by GitHub
- Skill
- Guidelines
- Software development
- MIT
- Low risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to upgrading Java applications across LTS versions (11 to 17, 17 to 21, 21 to 25). It helps developers assess their current environment, update build configurations, and incrementally adopt modern Java features like records, sealed classes, pattern matching, and virtual threads. The skill emphasizes safety by recommending small, reviewable changes and provides specific migration patterns for each version transition.
What it does
- Detects current Java versions from build files like pom.xml and build.gradle.
- Provides version-specific upgrade guides for LTS transitions.
- Offers code migration patterns for modern Java features.
- Advises on updating build configurations and dependencies.
- Integrates with external tools like OpenRewrite for automated refactoring.
- Provides guidance on handling namespace migrations such as javax to jakarta.
When to use it
- When you need to upgrade a Java project to a newer JDK version.
- When you want to modernize existing Java code with newer language features.
- When you are unsure of the specific migration steps between two Java LTS versions.
- When you need to adopt features like records, sealed classes, or virtual threads.
Advantages
- Provides a clear, step-by-step path for complex version upgrades.
- Focuses on safe, incremental refactoring to minimize breaking changes.
- Includes specific code examples for modern Java syntax.
- Helps identify necessary build tool and dependency updates.
- Directs users to official documentation and migration resources.
Usage examples
- “How do I upgrade my Java 11 project to Java 17?”
- The agent will analyze your build files, outline the steps for the 11 to 17 transition, and provide specific migration patterns for features like records and sealed classes.
- “Show me how to use virtual threads in my Java 21 project.”
- The agent will explain the transition from platform threads to virtual threads using Executors.newVirtualThreadPerTaskExecutor and provide a code example.
- “How can I use pattern matching for switch in Java 21?”
- The agent will provide a comparison between traditional switch statements and the new pattern matching syntax, including examples with guarded patterns.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/github/java-upgrade/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip java-upgrade.zip -d .agents/skills
Documentation by jdubois
Java Upgrade
Help upgrade a Java project step by step and adopt new language features safely.
Need a more powerful, automated upgrade?
The Microsoft plugin modernize-java ("GitHub Copilot modernization - Java Upgrade CLI Plugin", also listed in this repository's plugins/external.json) upgrades Java applications from the command line. It can:
analyze the project, assess dependencies and generate a customizable upgrade plan you can review and edit;
execute the plan to automatically transform the codebase;
fix build issues and resolve migration errors during the upgrade, running test validations;
validate the application against known CVEs after the upgrade;
output a detailed summary (file changes, updated dependencies, test results, remaining issues) suitable for PRs or CI logs.
This skill provides lightweight, step-by-step guidance and works without the plugin; the plugin is the more powerful option for large or multi-step upgrades. It is a separate Microsoft plugin, not part of this repository's skills. To try it (see the plugin README for the recommended model):
npm install -g @github/copilot
copilot plugin marketplace add microsoft/modernize-java
copilot plugin install modernize-java@modernize-java
copilot --agent modernize-java:modernize-javaWorkflow
Detect the current and target versions. Read
pom.xml(maven.compiler.release,java.version, toolchains),build.gradle*(java.toolchain,sourceCompatibility) and CI files. Never assume a target: ask the user if it is not stated.Upgrade one LTS at a time (11 → 17 → 21 → 25). Build and run the tests after each step.
Load only the guide you need from the table below. Do not load all of them.
Update the build first (compiler release, plugins, dependencies that need newer versions), then adopt language features incrementally in small, reviewable changes.
Verify:
./mvnw verifyor./gradlew build, and fix deprecation and removal warnings before adopting new features.Automate and check upstream. Use OpenRewrite when available (for example
org.openrewrite.java.migrate.UpgradeToJava21) and always fetch the version-specific official guide before editing; review the generated diff.
Upstream sources (read before upgrading)
Fetch the page for the target version; prefer it over this skill when they conflict. Full list with build-tool and agent compatibility pages: references/upstream-sources.md.
OpenJDK release page: https://openjdk.org/projects/jdk/21/ (change the number) and JEP index https://openjdk.org/jeps/0
Oracle migration guide: https://docs.oracle.com/en/java/javase/21/migrate/getting-started.html
Oracle release notes: https://www.oracle.com/java/technologies/javase/21-relnote-issues.html
jdeprscan/jdeps: https://docs.oracle.com/en/java/javase/21/docs/specs/man/jdeprscan.html, https://docs.oracle.com/en/java/javase/21/docs/specs/man/jdeps.htmlGradle compatibility matrix: https://docs.gradle.org/current/userguide/compatibility.html
OpenRewrite: https://docs.openrewrite.org/recipes/java/migrate/upgradetojava21
Per-version guides
| Upgrade | Guide |
|---|---|
| Java 11 → 17 | references/java-11-to-17.md |
| Java 17 → 21 | references/java-17-to-21.md |
| Java 21 → 25 | references/java-21-to-25.md |
Rules
Prefer behavior-preserving refactorings; do not change public APIs unless asked.
Detect the project's frameworks (Spring Boot, Quarkus, Jakarta EE) and check their minimum supported Java version before raising the target.
Do not adopt preview features unless the user opts in and the build enables them explicitly.
For
javax.*tojakarta.*namespace changes, use thejavax-to-jakarta-migrationskill if it is installed (gh skills install github/awesome-copilot javax-to-jakarta-migration); otherwise do the migration inline: update imports,META-INFservice files and XML descriptors, and bump dependencies to Jakarta EE 9+ equivalents.If the
modernize-javaplugin is installed and the user wants an automated upgrade, defer to it and use this skill for the per-version guides and thejavaxtojakartasafeguards.
Files
- ATTRIBUTION.mdAdded by AutoGineer855 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md4.8 KiB
- references/java-11-to-17.md21.5 KiB
- references/java-17-to-21.md13.7 KiB
- references/java-21-to-25.md9.7 KiB
- references/upstream-sources.md2.3 KiB
references/java-11-to-17.md
Java 11 to Java 17 Upgrade Guide
Project Context
This guide provides comprehensive GitHub Copilot instructions for upgrading Java projects from JDK 11 to JDK 17, covering major language features, API changes, and migration patterns based on 47 JEPs integrated between these versions.
Language Features and API Changes
JEP 395: Records (Java 16)
Migration Pattern: Convert data classes to records
// Old: Traditional data class
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String name() { return name; }
public int age() { return age; }
@Override
public boolean equals(Object obj) { /* boilerplate */ }
@Override
public int hashCode() { /* boilerplate */ }
@Override
public String toString() { /* boilerplate */ }
}
// New: Record (Java 16+)
public record Person(String name, int age) {
// Compact constructor for validation
public Person {
if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
}
// Custom methods can be added
public boolean isAdult() {
return age >= 18;
}
}JEP 409: Sealed Classes (Java 17)
Migration Pattern: Use sealed classes for restricted inheritance
// New: Sealed hierarchy (all permitted types must be in the same package/module;
// top-level public types each live in their own file)
public sealed interface Shape permits Circle, Rectangle, Triangle {
double area();
}
public record Circle(double radius) implements Shape {
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public record Rectangle(double width, double height) implements Shape {
@Override
public double area() {
return width * height;
}
}
// non-sealed allows further inheritance; a record is implicitly final,
// so use a class if the type must stay open for extension
public non-sealed class Triangle implements Shape {
private final double base, height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
public double base() { return base; }
@Override
public double area() {
return 0.5 * base * height;
}
}JEP 394: Pattern Matching for instanceof (Java 16)
Migration Pattern: Simplify instanceof checks
// Old: Traditional instanceof with casting
public String processObject(Object obj) {
if (obj instanceof String) {
String str = (String) obj;
return str.toUpperCase();
} else if (obj instanceof Integer) {
Integer num = (Integer) obj;
return "Number: " + num;
} else if (obj instanceof List<?>) {
List<?> list = (List<?>) obj;
return "List with " + list.size() + " elements";
}
return "Unknown type";
}
// New: Pattern matching for instanceof (Java 16+)
public String processObject(Object obj) {
if (obj instanceof String str) {
return str.toUpperCase();
} else if (obj instanceof Integer num) {
return "Number: " + num;
} else if (obj instanceof List<?> list) {
return "List with " + list.size() + " elements";
}
return "Unknown type";
}
// Works great with sealed classes
public String describeShape(Shape shape) {
if (shape instanceof Circle circle) {
return "Circle with radius " + circle.radius();
} else if (shape instanceof Rectangle rect) {
return "Rectangle " + rect.width() + "x" + rect.height();
} else if (shape instanceof Triangle triangle) {
return "Triangle with base " + triangle.base();
}
return "Unknown shape";
}JEP 361: Switch Expressions (Java 14)
Migration Pattern: Convert switch statements to expressions
// Old: Traditional switch statement
public String getDayType(DayOfWeek day) {
String result;
switch (day) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
result = "Workday";
break;
case SATURDAY:
case SUNDAY:
result = "Weekend";
break;
default:
throw new IllegalArgumentException("Unknown day: " + day);
}
return result;
}
// New: Switch expression (Java 14+)
public String getDayType(DayOfWeek day) {
return switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Workday";
case SATURDAY, SUNDAY -> "Weekend";
};
}
// With yield for complex logic
public int calculateScore(Grade grade) {
return switch (grade) {
case A -> 100;
case B -> 85;
case C -> 70;
case D -> {
System.out.println("Consider improvement");
yield 55;
}
case F -> {
System.out.println("Needs retake");
yield 0;
}
};
}JEP 406: Pattern Matching for switch (Preview in Java 17)
Migration Pattern: Enhanced switch with patterns (Preview feature)
// Requires --enable-preview flag
public String formatValue(Object obj) {
return switch (obj) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case null -> "null value";
default -> "Unknown: " + obj.getClass().getSimpleName();
};
}
// With guarded patterns (Java 17 preview syntax: && guard; the "when" keyword arrived in Java 21)
public String categorizeNumber(Object obj) {
return switch (obj) {
case Integer i && i < 0 -> "Negative integer";
case Integer i && i == 0 -> "Zero";
case Integer i && i > 0 -> "Positive integer";
case Double d && d.isNaN() -> "Not a number";
case Number n -> "Other number: " + n;
case null -> "null";
default -> "Not a number";
};
}JEP 378: Text Blocks (Java 15)
Migration Pattern: Use text blocks for multi-line strings
// Old: Concatenated strings
String html = "<html>\n" +
" <body>\n" +
" <h1>Hello World</h1>\n" +
" <p>Welcome to Java 17!</p>\n" +
" </body>\n" +
"</html>";
String sql = "SELECT p.id, p.name, p.email, " +
" a.street, a.city, a.state " +
"FROM person p " +
"JOIN address a ON p.address_id = a.id " +
"WHERE p.active = true " +
"ORDER BY p.name";
// New: Text blocks (Java 15+)
String html = """
<html>
<body>
<h1>Hello World</h1>
<p>Welcome to Java 17!</p>
</body>
</html>
""";
String sql = """
SELECT p.id, p.name, p.email,
a.street, a.city, a.state
FROM person p
JOIN address a ON p.address_id = a.id
WHERE p.active = true
ORDER BY p.name
""";
// With string interpolation methods
String json = """
{
"name": "%s",
"age": %d,
"city": "%s"
}
""".formatted(name, age, city);JEP 358: Helpful NullPointerExceptions (Java 14)
Migration Guidance: Better NPE debugging (enabled by default in Java 17)
// Old NPE message: "Exception in thread 'main' java.lang.NullPointerException"
// New NPE message shows exactly what was null:
// "Cannot invoke 'String.length()' because the return value of 'Person.getName()' is null"
public class PersonProcessor {
public void processPersons(List<Person> persons) {
// This will show exactly which person.getName() returned null
persons.stream()
.mapToInt(person -> person.getName().length()) // Clear NPE if getName() returns null
.sum();
}
// Better error messages help with complex expressions
public void complexExample(Map<String, List<Person>> groups) {
// NPE will show exactly which part of the chain is null
int totalNameLength = groups.get("admins")
.get(0)
.getName()
.length();
}
}JEP 371: Hidden Classes (Java 15)
Migration Pattern: Use for framework and proxy generation
// For frameworks creating dynamic proxies
public class DynamicProxyExample {
public static <T> T createProxy(Class<T> interfaceClass, InvocationHandler handler) {
// Hidden classes provide better encapsulation for dynamically generated classes
MethodHandles.Lookup lookup = MethodHandles.lookup();
// Framework code would use hidden classes for better isolation
// This is typically handled by frameworks, not application code
return interfaceClass.cast(
Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class<?>[]{interfaceClass},
handler
)
);
}
}JEP 334: JVM Constants API (Java 12)
Migration Pattern: Use for compile-time constants
import java.lang.constant.*;
// For advanced metaprogramming and tooling: nominal descriptors of classes and methods
public class ConstantExample {
public static void main(String[] args) {
ClassDesc stringDesc = ClassDesc.of("java.lang.String");
MethodTypeDesc lengthDesc = MethodTypeDesc.of(ConstantDescs.CD_int);
System.out.println(stringDesc.descriptorString()); // Ljava/lang/String;
System.out.println(lengthDesc.descriptorString()); // ()I
}
}JEP 415: Context-Specific Deserialization Filters (Java 17)
Migration Pattern: Enhanced security for object deserialization
import java.io.*;
public class SecureDeserialization {
// Set up deserialization filters for security
public static void setupSerializationFilters() {
// Global filter
ObjectInputFilter globalFilter = ObjectInputFilter.Config.createFilter(
"java.base/*;java.util.*;!*"
);
ObjectInputFilter.Config.setSerialFilter(globalFilter);
}
public <T> T deserializeSecurely(byte[] data, Class<T> expectedType) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bis)) {
// Context-specific filter
ObjectInputFilter contextFilter = ObjectInputFilter.Config.createFilter(
expectedType.getName() + ";java.lang.*;!*"
);
ois.setObjectInputFilter(contextFilter);
return expectedType.cast(ois.readObject());
}
}
}JEP 356: Enhanced Pseudo-Random Number Generators (Java 17)
Migration Pattern: Use new random generator interfaces
import java.util.random.*;
// Old: Limited Random class
Random oldRandom = new Random();
int oldValue = oldRandom.nextInt(100);
// New: Enhanced random generators (Java 17+)
RandomGenerator generator = RandomGeneratorFactory
.of("Xoshiro256PlusPlus")
.create(System.nanoTime());
RandomGenerator.SplittableGenerator splittableGenerator =
RandomGeneratorFactory.<RandomGenerator.SplittableGenerator>of("L64X128MixRandom").create();
// Better for parallel processing
splittableGenerator.splits(4)
.parallel()
.mapToInt(rng -> rng.nextInt(1000))
.forEach(System.out::println);
// Streamable random values
generator.ints(10, 1, 101)
.forEach(System.out::println);I/O and Networking Improvements
JEP 380: Unix-Domain Socket Channels (Java 16)
Migration Pattern: Use Unix domain sockets for local IPC
import java.io.IOException;
import java.net.StandardProtocolFamily;
import java.net.UnixDomainSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.file.Path;
// Old: TCP sockets for local communication
// ServerSocketChannel server = ServerSocketChannel.open();
// server.bind(new InetSocketAddress("localhost", 8080));
// New: Unix domain sockets (Java 16+)
public class UnixSocketExample {
public void createUnixDomainServer() throws IOException {
Path socketPath = Path.of("/tmp/my-app.socket");
UnixDomainSocketAddress address = UnixDomainSocketAddress.of(socketPath);
try (ServerSocketChannel server = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) {
server.bind(address);
while (true) {
try (SocketChannel client = server.accept()) {
// Handle client connection
handleClient(client);
}
}
}
}
public void connectToUnixSocket() throws IOException {
Path socketPath = Path.of("/tmp/my-app.socket");
UnixDomainSocketAddress address = UnixDomainSocketAddress.of(socketPath);
try (SocketChannel client = SocketChannel.open(address)) {
// Communicate with server
ByteBuffer buffer = ByteBuffer.allocate(1024);
client.read(buffer);
}
}
private void handleClient(SocketChannel client) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = client.read(buffer);
// Process client data
}
}JEP 352: Non-Volatile Mapped Byte Buffers (Java 14)
Migration Pattern: Use for persistent memory operations
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import jdk.nio.mapmode.ExtendedMapMode; // module jdk.nio.mapmode
public class PersistentMemoryExample {
public void usePersistentMemory() throws IOException {
Path nvmFile = Path.of("/mnt/pmem/data.bin");
try (FileChannel channel = FileChannel.open(nvmFile,
StandardOpenOption.READ,
StandardOpenOption.WRITE,
StandardOpenOption.CREATE)) {
// Map as persistent memory
MappedByteBuffer buffer = channel.map(
FileChannel.MapMode.READ_WRITE, 0, 1024,
ExtendedMapMode.READ_WRITE_SYNC
);
// Write data that persists across crashes
buffer.putLong(0, System.currentTimeMillis());
buffer.putInt(8, 12345);
// Force write to persistent storage
buffer.force();
}
}
}Build System Configuration
Maven Configuration
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>17</release>
<!-- Enable preview features if using JEP 406 -->
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- For running tests with preview features -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
</plugins>
</build>Gradle Configuration
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.withType<JavaCompile> {
options.release.set(17)
// Enable preview features if needed
options.compilerArgs.addAll(listOf("--enable-preview"))
}
tasks.withType<Test> {
useJUnitPlatform()
// Enable preview features for tests
jvmArgs("--enable-preview")
}Deprecations and Removals
JEP 411: Deprecate the Security Manager for Removal
Migration Pattern: Remove Security Manager dependencies
// Old: Using Security Manager
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
// New: Alternative security approaches
// Use application-level security, containers, or process isolation
// Most applications don't need Security Manager functionalityJEP 398: Deprecate the Applet API for Removal
Migration Pattern: Migrate from Applets to modern web technologies
// Old: Java Applet (deprecated)
public class MyApplet extends Applet {
@Override
public void start() {
// Applet code
}
}
// New: Modern alternatives
// 1. Convert to standalone Java application
public class MyApplication extends JFrame {
public MyApplication() {
setTitle("My Application");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Application code
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new MyApplication().setVisible(true);
});
}
}
// 2. Use Java Web Start alternative (jlink)
// 3. Convert to web application using modern frameworksJEP 372: Remove the Nashorn JavaScript Engine
Migration Pattern: Use alternative JavaScript engines
// Old: Nashorn (removed in Java 17)
// ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
// New: Alternative approaches
// 1. Use GraalVM JavaScript engine
ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
// 2. Use external JavaScript execution
ProcessBuilder pb = new ProcessBuilder("node", "script.js");
Process process = pb.start();
// 3. Use web-based approach or embedded browserJVM and Performance Improvements
JEP 377: ZGC - A Scalable Low-Latency Garbage Collector (Java 15)
Migration Pattern: Enable ZGC for low-latency applications
# Enable ZGC
-XX:+UseZGC # Production-ready since Java 15; no experimental unlock needed
# Monitor ZGC performance
-Xlog:gc*:file=gc.logJEP 379: Shenandoah - A Low-Pause-Time Garbage Collector (Java 15)
Migration Pattern: Enable Shenandoah for consistent latency
# Enable Shenandoah
# Not included in every JDK build (e.g. Oracle JDK); production-ready since Java 15 where available
-XX:+UseShenandoahGC
# Shenandoah tuning
-XX:ShenandoahGCHeuristics=adaptiveJEP 341: Default CDS Archives (Java 12) & JEP 350: Dynamic CDS Archives (Java 13)
Migration Pattern: Improved startup performance
# CDS is enabled by default, but you can create custom archives
# Create custom CDS archive
java -XX:DumpLoadedClassList=classes.lst -cp myapp.jar com.example.Main
java -Xshare:dump -XX:SharedClassListFile=classes.lst -XX:SharedArchiveFile=myapp.jsa -cp myapp.jar
# Use custom CDS archive
java -XX:SharedArchiveFile=myapp.jsa -cp myapp.jar com.example.MainTesting and Migration Strategy
Phase 1: Foundation (Weeks 1-2)
Update build system
Modify Maven/Gradle configuration for Java 17
Update CI/CD pipelines
Verify dependency compatibility
Address removals and deprecations
Remove Nashorn JavaScript engine usage
Replace deprecated Applet APIs
Update Security Manager usage
Phase 2: Language Features (Weeks 3-4)
Implement Records
Convert data classes to records
Add validation in compact constructors
Test serialization compatibility
Add Pattern Matching
Convert instanceof chains
Implement type-safe casting patterns
Phase 3: Advanced Features (Weeks 5-6)
Switch Expressions
Convert switch statements to expressions
Use new arrow syntax
Implement complex yield logic
Text Blocks
Replace concatenated multi-line strings
Update SQL and HTML generation
Use formatting methods
Phase 4: Sealed Classes (Weeks 7-8)
Design sealed hierarchies
Identify inheritance restrictions
Implement sealed class patterns
Combine with pattern matching
Testing and validation
Comprehensive test coverage
Performance benchmarking
Compatibility verification
Performance Considerations
Records vs Traditional Classes
Records are more memory efficient
Faster creation and equality checks
Automatic serialization support
Consider for data transfer objects
Pattern Matching Performance
Eliminates redundant type checks
Reduces casting overhead
Better JVM optimization opportunities
Use with sealed classes for exhaustiveness
Switch Expressions Optimization
More efficient bytecode generation
Better constant folding
Improved branch prediction
Use for complex conditional logic
Best Practices
Use Records for Data Classes
Immutable data containers
API data transfer objects
Configuration objects
Apply Pattern Matching Strategically
Replace instanceof chains
Use with sealed classes
Combine with switch expressions
Adopt Text Blocks for Multi-line Content
SQL queries
JSON templates
HTML content
Configuration files
Design with Sealed Classes
Domain modeling
State machines
Algebraic data types
API evolution control
Leverage Enhanced Random Generators
Parallel processing scenarios
High-quality random numbers
Statistical applications
Gaming and simulation
This comprehensive guide enables GitHub Copilot to provide contextually appropriate suggestions when upgrading Java 11 projects to Java 17, focusing on language enhancements, API improvements, and modern Java development practices.
Requirements and compatibility
Written for: GitHub Copilot
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Node.js
Security
What our scanner noticed· Low risk
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- First committed by
jdubois
- Publisher
- GitHub (Official)
- Distributed by
- GitHub
- Source
- github/awesome-copilot · skills/java-upgrade · commit 797337f
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Contributors
- jdubois
AutoGineer is not affiliated with or endorsed by jdubois or GitHub.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download java-upgrade.zip