Skip to content

Copilot Instructions for Java Enterprise Services

GitHub Copilot.github/copilot-instructions.mdCoding

Java service conventions for Copilot: immutable-by-default classes, Optional only as a return type, JUnit 5 with AssertJ, and exceptions that carry context instead of being swallowed.

Use when: Use in a Java 17+ backend service when you want Copilot to produce modern, immutable, well-tested Java instead of setter-heavy beans and bare try/catch blocks.

@library0 upvotes0 remixes0 comments

Get this skill

Add the skill file with the CLI, by hand, or over MCP.

Save this to your project or home directory so GitHub Copilot can load it.

npx goodprompts add copilot-java-enterprise-instructions
Saves to./.github/copilot-instructions.md
npx goodprompts add copilot-java-enterprise-instructions
Saves to ./.github/copilot-instructions.md

Skill file

.github/copilot-instructions.md2,948 characters
# Java Service Instructions
## Immutability
- Default every field to `private final`; introduce mutability only with a comment explaining why.
- Data carriers are `record`s. Do not generate JavaBean classes with getters/setters for new value types — records or builders only.
- Collections exposed from any class are unmodifiable: return `List.copyOf(...)` or wrap with `Collections.unmodifiableList(...)`; never expose the internal list.
- No setters on entities for fields that are part of the entity's identity or invariants — use intention-revealing methods (`order.markShipped(clock.instant())`).
- Static mutable state is forbidden, including "caches" implemented as static `HashMap`s. Use an injected cache abstraction.
## Optional usage
- `Optional` is a return type only. Never use it for fields, method parameters, or collection elements.
- Never call `.get()` without `.isPresent()` — and prefer `orElseThrow(() -> new SpecificException(...))`, `map`, or `ifPresent` over presence checks entirely.
- Do not return `Optional<Collection<T>>` — return an empty collection.
- Repository finders for a single row return `Optional<T>`; service methods that require the row to exist resolve it immediately with `orElseThrow` and a domain exception.
## Error handling
- Never catch `Exception` or `Throwable` except at the outermost boundary (request filter, message-consumer loop), and there, log with full stack trace and context fields.
- Empty catch blocks are forbidden. If an exception is genuinely ignorable, log it at DEBUG with a comment saying why.
- Wrap-and-rethrow must preserve the cause: `throw new PaymentFailedException("charge " + chargeId, e)` — never drop `e`.
- Domain exceptions extend a small sealed hierarchy under `exception/`; do not invent a new top-level exception per class.
- Log or rethrow, never both — double-logging the same failure at multiple layers is a bug.
## JUnit 5 patterns
- JUnit 5 (`@Test` from `org.junit.jupiter`) with AssertJ assertions (`assertThat(...)`). Hamcrest and JUnit 4 are forbidden.
- Test method names are sentences in camelCase: `refundFailsWhenOrderAlreadyRefunded()`. No `test` prefix.
- Use `@ParameterizedTest` with `@CsvSource`/`@MethodSource` for input matrices instead of duplicated tests.
- Exception assertions use `assertThatThrownBy(...).isInstanceOf(...).hasMessageContaining(...)` — never try/catch/fail in tests.
- Inject a fixed `Clock` everywhere time is read; tests must never call `Instant.now()` or sleep.
- Mock with Mockito only at I/O boundaries; construct real objects for everything in the same module.
## General
- Streams over loops when the operation is a clean map/filter/collect; loops when there is branching, early exit, or checked exceptions involved.
- No Lombok in new code; records and explicit constructors cover the need.
- Run `./mvnw verify` (Checkstyle + tests) before suggesting any commit; never commit with `@Disabled` tests added.
Comments

Comments

Sign in to commentSign in

Remixes

Loading remixes…