# Java Conventions

## Style guide

Google Java Style Guide is the default. If the project ships its own (`CONTRIBUTING.md`, `.editorconfig`, `checkstyle.xml`, `google-java-format` config), follow that instead.

## Naming

| Element | Convention | Example |
|---|---|---|
| Class / interface / enum | UpperCamelCase | `ImmutableList`, `HashIntegrationTest` |
| Method / variable / parameter | lowerCamelCase | `sendMessage`, `computedValues` |
| Constant (`static final` + immutable value) | UPPER_SNAKE_CASE | `MAX_COUNT`, `DEFAULT_TIMEOUT` |
| Package | lowercase, no underscores | `com.example.deepspace` |
| Type variable | single letter or short PascalCase | `T`, `E`, `Result` |
| Test class | `<ClassUnderTest>Test` / `<ClassUnderTest>IT` | `UserServiceTest`, `OrderRepositoryIT` |

## Formatting

- Indent: **2 spaces**, never tabs.
- Column limit: **100** characters.
- Brace style: K&R — opening brace on the same line.
- One statement per line.
- Always brace `if`, `else`, `for`, `while`, `do`, even for single-statement bodies.
- `switch` statements must be exhaustive — supply a `default` case, or rely on enum/sealed-type coverage.

## Required practices

- `@Override` on every override (including interface methods).
- Never silently swallow exceptions. If you intentionally ignore one, leave a one-line comment stating why.
- Access static members via the class name (`Foo.bar()`, not `instance.bar()`).
- Do not use finalizers. Use `try-with-resources` for `AutoCloseable` and `java.lang.ref.Cleaner` for native handles.
- Declare local variables near first use, with the narrowest possible scope.
- Prefer `List.of(...)` / `Map.of(...)` / `Set.of(...)` for small immutable collections.
- Prefer `Optional<T>` as a return type for "might be missing"; never use `Optional` for fields, parameters, or collection elements.
- Use `record` for plain data carriers (Java 16+).
- Use `var` only when the right-hand side makes the type obvious to a reader.

## Tests

- Framework: **JUnit 5** unless the project uses TestNG or JUnit 4.
- File suffix: `*Test.java` for unit, `*IT.java` for integration.
- Method naming: `methodUnderTest_condition_expectedResult` (e.g. `parse_emptyInput_throws`).
- Use **AssertJ** or JUnit's `assertThat` for fluent assertions; avoid bare `assertTrue(a == b)`.
- One logical assertion per test. Multiple `assertThat` lines on the *same state* are fine.
- No `Thread.sleep` in tests — use **Awaitility** for async.
- Mock at process boundaries only (HTTP, DB, time, randomness). Do not mock value objects or DTOs.
- Use `@Nested` to group related test cases.
- Use parameterized tests (`@ParameterizedTest` + `@CsvSource` / `@MethodSource`) for table-driven coverage.

### Self-mock signals to refuse (rule from `clean-code.md` → Testing discipline)

- A field annotated with **both** `@InjectMocks` *and* `@Spy` — the SUT is being wrapped as a spy so its own methods can be stubbed. Drop `@Spy`; stub only the `@Mock` collaborators on the same class.
- `Mockito.spy(realSut)` followed by `doReturn(...).when(spy).someMethod(...)` — same anti-pattern, manually constructed.
- `MockedStatic<SomeUtil>` when `SomeUtil` is the unit under test rather than a dependency.
- `ReflectionTestUtils.setField(sut, "privateState", ...)` to drive a branch, or `ReflectionTestUtils.invokeMethod(sut, "privateHelper")` to assert on a private helper — that's reaching into privates and breaks behavioral-testing discipline.

What's fine: `@Mock` on collaborators injected into `@InjectMocks`, `verify(collaborator).methodCall(...)` on outcome boundaries (repository save, mailer send, gateway charge).

## Formatter / linter to run

- `google-java-format` (preferred) or the `spotless` Gradle/Maven plugin.
- `checkstyle`, `spotbugs`, `error-prone` if configured by the project.
- Run before commit: `./gradlew spotlessApply check` (or the project's equivalent).
