Generated banner for Java Development
Generated logo for Java Development

Java Development

GitHubOfficialFirst committed by jduboisDistributed by GitHub

  • Skill
  • Tool integration
  • Software development
  • MIT
  • No issues found

From the author

Day-to-day plain Java development without a framework: Maven and Gradle usage and wrappers, project layout, dependency and vulnerability management, modern Java idioms by JDK version (records, sealed types, pattern matching, virtual threads), SLF4J logging, error and null handling, immutability, concurrency basics, static analysis and formatting (Spotless, Error Prone, -Xlint), packaging (jar, jlink, jpackage) and GitHub Actions CI. Use when writing, building, reviewing or maintaining ordinary Java code.
— the description by jdubois

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides comprehensive support for standard Java development, focusing on build tool management (Maven/Gradle), dependency hygiene, and the application of modern Java idioms based on the project's specific JDK version. It emphasizes best practices for code quality, static analysis, and packaging, ensuring that development remains consistent with the project's existing configuration and standards.

What it does

  • Manages Maven and Gradle build configurations, wrappers, and multi-module layouts.
  • Provides version-specific Java idiom guidance from JDK 8 through 25.
  • Handles dependency management, vulnerability scanning, and conflict resolution.
  • Configures static analysis tools like Spotless, Error Prone, and -Xlint.
  • Supports packaging applications into jars, jlink images, or jpackage installers.
  • Maintains CI pipelines using GitHub Actions.

When to use it

  • When writing, building, or refactoring plain Java code without a framework.
  • When upgrading or aligning code to match a project's specific Java release.
  • When diagnosing build failures, dependency conflicts, or vulnerability alerts.
  • When setting up or maintaining project-wide formatting and static analysis rules.
  • When preparing a Java application for deployment or distribution.

Advantages

  • Ensures strict adherence to project-specific Java versions and build configurations.
  • Promotes clean, idiomatic code using the latest features supported by the project.
  • Reduces technical debt through proactive dependency and vulnerability management.
  • Standardizes build processes and CI/CD workflows.
  • Prevents common pitfalls related to JDK-specific changes and preview features.

Usage examples

“How do I implement a record-based switch expression in this project?”
The agent checks the project's Java release; if it is 21 or higher, it provides a code snippet using record patterns and exhaustive switch expressions.
“Check for dependency updates and resolve a conflict in my Maven build.”
The agent runs dependency analysis commands, identifies the conflicting versions, and suggests a fix using dependencyManagement in the pom.xml.
“Add a GitHub Actions workflow to run my Gradle build.”
The agent generates a standard CI file using actions/setup-java and the project's wrapper, ensuring the build is verified on every push.
“How can I use virtual threads for my I/O tasks?”
The agent verifies the project is on JDK 21+, explains the use of Executors.newVirtualThreadPerTaskExecutor, and warns about blocking synchronization.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/github/java-development/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip java-development.zip -d .agents/skills

Documentation by jdubois

Java Development (plain Java)

Everyday guidance for Java projects that are not tied to a framework. If the project uses Spring Boot, Quarkus, Helidon or similar, prefer that framework's skills for framework concerns and use this one for the plain-Java parts.

Rules that always apply

  1. Detect before you write. Read pom.xml/build.gradle*, .mvn/, gradle/, .java-version/.sdkmanrc, .editorconfig, CI files, and a few source files. Match the build tool, Java release, formatter, naming, logging and test libraries already in use.

  2. Never upgrade implicitly. Do not change the Java release, build-tool version, plugin or dependency versions, or add a formatter/linter/static analyzer the project lacks, as a side effect of another task. Suggest it and ask. Version upgrades are their own task (java-upgrade, if installed).

  3. Use the wrapper (./mvnw, ./gradlew) when present; otherwise the installed mvn/gradle. Do not commit a wrapper unprompted.

  4. Verify with a build. After any change run the project's own verification (./mvnw -B verify or ./gradlew build) and report the result. Run a narrower command first while iterating. If you could not run it, say so.

  5. Ask the user before: changing public APIs or serialized/DB/wire formats, raising the Java release, adding runtime dependencies, adding tools to the build, deleting or weakening tests, changing CI, or when two reasonable designs have different trade-offs.

  6. Prefer the standard library and small, explicit code over new dependencies. No Lombok unless already used.

Pick idioms by the project's Java release

Check maven.compiler.release/<release>, java.toolchain, or sourceCompatibility; never use a feature newer than that release. Summary (details and snippets in references/modern-java.md):

ReleaseYou can use
8lambdas, streams, Optional, java.time
11var, String.isBlank/strip/lines, java.net.http.HttpClient, List.of/Map.of (9)
17records, sealed classes, text blocks, switch expressions, instanceof patterns
21pattern matching for switch, record patterns, virtual threads, SequencedCollection (getFirst/getLast/reversed)
22-24unnamed variables _ (22), Stream.gather (24)
25scoped values, instance main/compact source files, module import declarations (all final)

Structured concurrency (StructuredTaskScope) is still a preview API in 25 and 27 (verified: needs --enable-preview); do not use it in production code unless the user opts in to preview features.

Build tools in practice

  • Maven: ./mvnw -B verify (compile, unit tests, integration tests, packaging), -pl <module> -am for one module, dependency:tree, -DskipTests only when the user asks. Gradle: ./gradlew build, test --tests 'pkg.Class', dependencies, dependencyInsight --dependency <name>.

  • Standard layout: src/main/java, src/main/resources, src/test/java, src/test/resources; package by feature, one top-level type per file, no split packages.

  • Set the Java version explicitly (maven.compiler.release / Gradle toolchain with options.release) and UTF-8 encoding; do not rely on the JDK that happens to run the build.

  • Wrapper, BOM and dependency:tree/versions: usage, version catalogs and multi-module layout: references/build-and-dependencies.md.

Dependencies and vulnerabilities

  • Import BOMs (junit-bom, testcontainers-bom, the framework's BOM) instead of repeating versions; one version per library across modules.

  • Inspect before changing: mvn dependency:tree -Dincludes=group:artifact / gradlew dependencyInsight. Resolve conflicts with dependencyManagement or Gradle constraints, not by excluding randomly.

  • Check updates with mvn versions:display-dependency-updates (add -Dmaven.version.ignore to hide alpha/beta/RC) and report them; do not apply major upgrades without asking.

  • Vulnerabilities: use what the project has (Dependabot/Renovate alerts, OWASP dependency-check, OSV-Scanner, GitHub dependency review). Suggest one if none exists; do not add it silently. Keep secrets out of scanner config; NVD-based scanners need an API key to be practical.

Version-dependent failures (verified)

  • JDK 23+ no longer runs annotation processors implicitly (Lombok, MapStruct, Dagger...): -proc:none is the default unless -processor, --processor-path or --processor-module-path is given. Declare the processor path in the build (Maven annotationProcessorPaths, Gradle annotationProcessor) or pass -proc:full. JDK 21+ prints a warning when it detects implicit use; -proc:full is also backported to 17.0.11, 11.0.23 and 8u411. Source: https://inside.java/2024/06/18/quality-heads-up/.

  • Virtual threads and synchronized: on JDK 21-23 a virtual thread that blocks inside synchronized is pinned to its carrier; JEP 491 removes nearly all such pinning in JDK 24+. On 21-23 prefer ReentrantLock around blocking calls. Source: https://openjdk.org/jeps/491.

  • Error Prone on JDK 16+ needs the --add-exports/--add-opens javac flags, and on JDK 21 -XDaddTypeAnnotationsToSymbol=true (see the quality reference).

  • Never use a language feature newer than the project's release (see the table above).

Static analysis and formatting (only if already present, or the user agrees)

Respect what is configured: if the project uses Spotless/Checkstyle/SpotBugs/Error Prone, run them and fix findings; if not, do not add them. When asked to introduce them, start with -Xlint:all and Spotless (formatter only), then Error Prone. Verified configs for Maven and Gradle on JDK 21 and 25 (including the JDK-21-only -XDaddTypeAnnotationsToSymbol=true requirement and Maven .mvn/jvm.config flags) are in references/quality-and-packaging.md. Never reformat the whole codebase in an unrelated change.

Packaging and CI

  • Plain library jar: mvn package/gradlew jar. Runnable app: shaded/fat jar or lib/ directory plus manifest Main-Class; custom runtime with jlink; native installer/app-image with jpackage (verified on macOS, see references/quality-and-packaging.md).

  • GitHub Actions: actions/checkout, actions/setup-java with distribution: temurin, an explicit java-version, built-in dependency cache, then ./mvnw -B verify or ./gradlew build. Snippet and notes in references/quality-and-packaging.md. Do not change CI without asking.

java-junit (unit tests), java-testcontainers (integration tests with Docker), java-hibernate-jpa (persistence), java-debugging (failures and stack traces), java-diagnostics (performance, memory, threads, JFR), java-upgrade (JDK/framework upgrades), lsp-setup (Java language server for navigation and refactoring).

References

  • references/modern-java.md: idioms and verified snippets (records, sealed types, switch patterns, text blocks, virtual threads, SequencedCollection, unnamed variables), preview status, pitfalls.

  • references/build-and-dependencies.md: Maven/Gradle commands, wrappers, BOMs, conflict diagnosis, update checking, Dependabot/Renovate, vulnerability scanning.

  • references/quality-and-packaging.md: logging setup, -Xlint, Spotless, Error Prone, Checkstyle/SpotBugs notes, jar/jlink/jpackage, GitHub Actions.

Files

references/quality-and-packaging.md

Logging, static analysis, packaging and CI

Verified with Maven 3.10.0 and Gradle 9.8.1 on JDK 21.0.12 and 25.0.4 unless marked unverified.

Logging: SLF4J + one backend

<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.20</version></dependency>
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.6.5</version><scope>runtime</scope></dependency>
private static final Logger log = LoggerFactory.getLogger(Main.class);

log.info("order {} placed for {}", orderId, customerId);     // placeholders, no concatenation
log.warn("payment failed for order {}", orderId, exception); // exception last: full stack trace
log.atInfo().addKeyValue("area", area).log("computed");     // SLF4J 2 fluent API (verified)
  • Libraries depend only on slf4j-api; the application chooses the backend. Exactly one backend on the runtime classpath (otherwise SLF4J warns about multiple bindings).

  • Minimal src/main/resources/logback.xml (verified): a ConsoleAppender with pattern %d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} requestId=%X{requestId} - %msg %kvp%n, <logger name="your.package" level="DEBUG"/>, root level INFO. %X{requestId} renders the MDC request ID and %kvp renders fluent addKeyValue fields; %msg alone renders neither. Without a config file Logback logs at DEBUG to the console.

  • Guard expensive argument construction with a lambda (log.atDebug().log(() -> ...)) or isDebugEnabled. Levels: ERROR = needs attention now, WARN = unexpected but handled, INFO = business events, DEBUG/TRACE = diagnostics.

  • Never log secrets, tokens, full request bodies or personal data; use MDC (MDC.put("requestId", id) ... finally MDC.remove) for correlation. Do not use System.out for diagnostics in application code.

  • Do not log an exception and also rethrow it (duplicate noise); log at the place that handles it.

Compiler warnings: -Xlint

Maven:

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.16.0</version>
  <configuration>
    <release>21</release>
    <compilerArgs><arg>-Xlint:all</arg><arg>-Werror</arg></compilerArgs>
  </configuration>
</plugin>

Gradle: tasks.withType<JavaCompile>().configureEach { options.release = 21; options.compilerArgs.addAll(listOf("-Xlint:all", "-Werror")) }.

-Werror turns warnings into build failures; verified as clean for the sample project on 21 and 25, but on an existing codebase it can fail on hundreds of warnings. Introduce -Xlint:all first and add -Werror only when the project is clean and the user agrees.

Spotless (formatting)

Maven (verified 3.10.4; spotless:check fails on violations, spotless:apply fixes):

<plugin>
  <groupId>com.diffplug.spotless</groupId>
  <artifactId>spotless-maven-plugin</artifactId>
  <version>3.10.4</version>
  <configuration>
    <java><googleJavaFormat/><removeUnusedImports/></java>
  </configuration>
</plugin>

Gradle (verified 8.10.4): plugins { id("com.diffplug.spotless") version "8.10.4" } and spotless { java { googleJavaFormat(); removeUnusedImports() } }; run ./gradlew spotlessCheck / spotlessApply.

Format style is a team decision: google-java-format uses 2-space indentation. If the project already has .editorconfig/Eclipse/IntelliJ formatting, configure Spotless to match instead (or do not add it). Apply spotless:apply to touched files only, never as a drive-by reformat of the repo. Works the same on JDK 21 and 25.

Error Prone (bug patterns at compile time)

Maven, verified with error_prone_core 2.50.0 on JDK 21 and 25 (it caught String.equals(Integer) as EqualsIncompatibleType):

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.16.0</version>
  <configuration>
    <release>21</release>
    <compilerArgs>
      <arg>-XDcompilePolicy=simple</arg>
      <arg>-XDaddTypeAnnotationsToSymbol=true</arg>   <!-- required on JDK 21; accepted on 25 -->
      <arg>--should-stop=ifError=FLOW</arg>
      <arg>-Xplugin:ErrorProne -XepDisableWarningsInGeneratedCode</arg>
    </compilerArgs>
    <annotationProcessorPaths>
      <path>
        <groupId>com.google.errorprone</groupId>
        <artifactId>error_prone_core</artifactId>
        <version>2.50.0</version>
      </path>
    </annotationProcessorPaths>
  </configuration>
</plugin>

and .mvn/jvm.config (JDK 16+ strong encapsulation; one flag per line):

--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED

Without -XDaddTypeAnnotationsToSymbol=true on JDK 21 the compiler fails with "-XDaddTypeAnnotationsToSymbol=true is required by Error Prone on JDK 21" (verified). Error Prone warnings appear as [BugPattern] compiler warnings and become errors under -Werror; suppress a specific finding with @SuppressWarnings("BugPattern") plus a comment, not a global disable.

Gradle (verified with net.ltgt.errorprone 5.1.1, which adds the JVM flags itself):

plugins { java; id("net.ltgt.errorprone") version "5.1.1" }
dependencies { errorprone("com.google.errorprone:error_prone_core:2.50.0") }

Checkstyle and SpotBugs (unverified here)

Run them only if the project configures them (maven-checkstyle-plugin, spotbugs-maven-plugin, Gradle checkstyle/com.github.spotbugs). Use the project's existing rule files; do not create a new ruleset or suppress findings wholesale. SpotBugs analyses bytecode, so check its JDK support before upgrading Java. They overlap with Error Prone; adding all three is rarely justified.

Packaging

Executable jar needs dependencies. For a plain app (verified: the jar alone fails with NoClassDefFoundError for SLF4J):

mvn -B package dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/lib
java -cp 'target/app.jar:target/lib/*' demo.Main

or use a shade/assembly plugin (or Gradle application + installDist) to produce a distributable. Set Main-Class in the jar manifest (maven-jar-plugin <archive><manifest><mainClass>).

jlink (verified, JDK 21): build a trimmed runtime:

MODS=$(jdeps --ignore-missing-deps --multi-release 21 --print-module-deps --class-path 'target/lib/*' target/app.jar)
jlink --add-modules "$MODS,jdk.unsupported" --strip-debug --no-header-files --no-man-pages --output target/rt
target/rt/bin/java -cp 'target/app.jar:target/lib/*' demo.Main

jdeps misses modules used by reflection or ServiceLoader; if the app fails with NoClassDefFoundError/missing provider, add modules (e.g. java.sql, java.xml, jdk.crypto.ec) explicitly. Runtime size was 44 MB for java.base only.

jpackage (verified on macOS with --type app-image): the --input directory must contain only the jar and its dependencies, not the output directory (using target as input recursed until "File name too long"):

mkdir target/in && cp target/app.jar target/lib/*.jar target/in/
jpackage --type app-image --name devapp --input target/in --main-jar app.jar \
  --main-class demo.Main --runtime-image target/rt --dest target/app

Native installers (dmg, pkg, msi, deb, rpm) need platform tooling and signing and were not tested; each must be built on its own OS.

GitHub Actions CI (unverified: not executed)

actions/setup-java v6 and actions/checkout v7 were the latest major release tags as of 2026-10 (checked through the GitHub API); verify the current majors, and pin to a full commit SHA if the repository's policy requires it.

name: CI
on:
  push:
    branches: [main]
  pull_request:
permissions:
  contents: read
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        java: [21, 25]
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-java@v6
        with:
          distribution: temurin
          java-version: ${{ matrix.java }}
          cache: maven            # or gradle
      - run: ./mvnw -B verify     # or ./gradlew build

Match the matrix to the Java releases the project supports (and the build's release setting); one JDK is fine for an application. For Gradle also consider gradle/actions/setup-gradle. Keep permissions minimal, never print secrets, and do not edit existing workflows without asking.

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 an API key

Security

No issues found by our static scan· No issues found

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
GitHub avatar of jduboisjdubois
Publisher
GitHub (Official)
Distributed by
GitHub
Source
github/awesome-copilot · skills/java-development · 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-development.zip