Skip to content
Back to skills

Jvm

ASecurity

Java and Kotlin stack guide - Gradle (Kotlin DSL, version catalogs, wrapper) or Maven, JDK toolchains, Spring Boot (config, validation, transactions, JPA N+1), Kotlin null safety and coroutines, Android, JUnit 5, Mockito/MockK, Testcontainers, security and build-error playbook. Use for any Java/Kotlin code, Gradle/Maven build or failure. Триггеры - "джава", "котлин", "сборка упала".

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 13, 2026
ai-agentsrustgojavakotlinsqlexpressspringtestinggitapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned October 13, 2026

npx -y skills add dmminga1983/minga --skill jvm --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Jvm?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Jvm
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/dmminga1983-jvm/badge)](https://www.skillsdirectory.com/skills/dmminga1983-jvm)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: jvm
description: Java and Kotlin stack guide - Gradle (Kotlin DSL, version catalogs, wrapper) or Maven, JDK toolchains, Spring Boot (config, validation, transactions, JPA N+1), Kotlin null safety and coroutines, Android, JUnit 5, Mockito/MockK, Testcontainers, security and build-error playbook. Use for any Java/Kotlin code, Gradle/Maven build or failure. Триггеры - "джава", "котлин", "сборка упала".
paths: "**/*.java, **/*.kt, **/*.kts, **/pom.xml, **/build.gradle, **/build.gradle.kts, **/settings.gradle*, **/gradle.properties, gradle/libs.versions.toml, **/AndroidManifest.xml, **/application*.yml, **/application*.properties"
---

Reply in the user's language.

# Java and Kotlin (JVM)

Rule zero: **follow the project's existing conventions over these defaults.** Read before you write.

## 1. Detect the project

| Read | To learn |
|---|---|
| `gradlew` + `gradle/wrapper/gradle-wrapper.properties` | Gradle project; the pinned Gradle version. Always run `./gradlew`, never a global `gradle` |
| `settings.gradle(.kts)`, `build.gradle(.kts)`, `buildSrc/` or `build-logic/` | modules, plugins, convention plugins, Groovy vs Kotlin DSL |
| `gradle/libs.versions.toml` | version catalog — add dependencies here, reference as `libs.xxx` |
| `pom.xml` + `mvnw` / `.mvn/` | Maven project; parent POM (often `spring-boot-starter-parent`), `<properties>`, modules |
| toolchain config, `maven.compiler.release`, `.java-version`, `.sdkmanrc`, CI `setup-java` | target JDK |
| `kotlin(...)` plugins, `kotlin { jvmToolchain(...) }` | Kotlin version, `kotlin-spring`/`kotlin-jpa`, kapt vs KSP |
| `com.android.application` / `com.android.library` plugins | Android — read [android.md](android.md) |
| `src/main/resources/application*.yml/properties` | Spring Boot config and profiles |
| `src/test`, test dependencies | JUnit 4 vs 5, Mockito vs MockK, AssertJ/Kotest, Testcontainers |
| `.editorconfig`, Spotless, ktlint, detekt, Checkstyle, SpotBugs, Error Prone | formatter and linters to keep green |

If both Gradle and Maven files exist, CI decides which one is real.

## 2. Defaults for new code

- **JDK:** the current LTS that the project's frameworks support; set it with a **toolchain** (Gradle `java { toolchain { languageVersion = JavaLanguageVersion.of(N) } }` or `kotlin { jvmToolchain(N) }`; Maven `<maven.compiler.release>`), not with `sourceCompatibility` alone.
- **Build:** Gradle with Kotlin DSL and a version catalog, or Maven with the wrapper — whichever the project uses. Commit the wrapper scripts, the wrapper JAR and its properties; update with `./gradlew wrapper --gradle-version <v>` (check the current stable release).
- **Language:** Kotlin for new Android and new Kotlin services; modern Java (records, sealed types, pattern matching `switch`, text blocks, `var` for obvious local types) for Java codebases.
- **Spring Boot:** the current supported line; Jakarta EE namespace (`jakarta.*`), constructor injection, `@ConfigurationProperties` for config.
- **Tests:** JUnit 5 (Jupiter) + AssertJ (Java) or kotlin.test/Kotest assertions; Mockito (Java) or MockK (Kotlin); Testcontainers for real databases and brokers.
- **Format/lint:** whatever is configured (Spotless with google-java-format/ktlint, detekt). Do not reformat untouched files.
- **Dependencies:** let BOMs manage versions (Spring Boot BOM, Kotlin BOM, `platform(...)`); no hard-coded versions next to a BOM-managed artifact.

## 3. Idioms and design

1. **Constructor injection** with final fields (Java) or `val` constructor params (Kotlin). No field `@Autowired`. One public constructor needs no annotation.
2. **Immutability by default:** Java records / Kotlin `data class` for DTOs and value objects; `List.of`/`listOf`; `val` over `var`.
3. **Kotlin null safety:** avoid `!!`; use `?.`, `?:`, `requireNotNull(x) { "why" }`, `checkNotNull`. Annotate Java APIs (JSpecify/`@Nullable`) so Kotlin sees platform types correctly. `lateinit` only for framework-injected fields and test setup.
4. **Java nulls:** `Optional` as a return type only — never as a field or parameter. Validate inputs at boundaries (`Objects.requireNonNull`, Bean Validation).
5. **Model closed sets with `sealed`** (Kotlin `sealed interface`, Java `sealed` + records) and exhaustive `when`/`switch` without `else`/`default`.
6. **Kotlin idioms:** expression bodies, `when` over if-chains, extension functions for local helpers (not to hide behaviour), scope functions used sparingly (`let` for null checks, `apply` for builders), named and default arguments instead of overloads.
7. **Do not use `data class` for JPA entities** (equals/hashCode over lazy relations and mutable ids breaks Hibernate). Use the `kotlin-jpa` (no-arg) and `kotlin-spring` (all-open) compiler plugins.
8. **Coroutines and structured concurrency:** launch in a scope tied to a lifecycle (`coroutineScope`, `supervisorScope`, `viewModelScope`, a framework scope) — never `GlobalScope`. Switch threads with `withContext(Dispatchers.IO)` for blocking calls. Never swallow `CancellationException` (a bare `catch (e: Exception)` does — rethrow it). No `runBlocking` in request handlers or on the main thread.
9. **Flow:** cold by default; `stateIn`/`shareIn` with an explicit scope and `SharingStarted` policy; `flowOn` to change the upstream dispatcher; `catch` operators for upstream errors.
10. **Java concurrency:** prefer `ExecutorService`/`CompletableFuture` with explicit executors; on Java 21+, virtual threads for blocking I/O-heavy servers (avoid long `synchronized` blocks around blocking I/O on older JDKs, where they pin the carrier thread).
11. **Equality and hashing** consistent; `compareTo` consistent with `equals` for sorted collections.
12. **Resources:** try-with-resources (Java) / `use {}` (Kotlin) for streams, connections, files.
13. **Time:** `java.time` (`Instant`, `OffsetDateTime`, `ZoneId`), injected `Clock` for testability; never `java.util.Date` in new code.
14. **Money:** `BigDecimal` (constructed from strings), never `double`.

## 4. Errors and logging

- Throw specific exceptions; don't catch `Exception`/`Throwable` except at boundaries (controllers' advice, job runners, `main`). Never swallow an exception without logging or rethrowing with cause (`throw new XException("context", e)`).
- Checked exceptions (Java): wrap in a domain exception at layer boundaries rather than leaking `SQLException`/`IOException` upward.
- Kotlin: `Result`/`runCatching` catches `CancellationException` and `Error` too — avoid it in coroutine code or rethrow cancellation; prefer sealed result types for expected failures.
- Spring MVC: one `@RestControllerAdvice` mapping exceptions to responses (`ProblemDetail` / RFC 9457 support in Spring 6); never return stack traces to clients.
- Logging: SLF4J API (`private static final Logger log = LoggerFactory.getLogger(X.class)`; Kotlin a companion or top-level logger) with parameterised messages (`log.info("user {} logged in", id)`), not string concatenation. Structured/JSON logging in production; MDC for request IDs.
- Never log passwords, tokens, full request bodies, or personal data; check `toString()` of records/data classes that contain secrets.

## 5. Testing

- **Layout:** `src/test/java|kotlin` mirroring main packages; integration tests in a separate source set or tagged (`@Tag("integration")`) if the project does that.
- **JUnit 5:** `@Test`, `@ParameterizedTest` with `@ValueSource`/`@CsvSource`/`@MethodSource`, `@Nested`, `@TempDir`, `assertThrows`. Requires `useJUnitPlatform()` in Gradle `test` task.
- **Mocks:** Mockito (`@ExtendWith(MockitoExtension.class)`, `@Mock`, `when(...).thenReturn(...)`, `verify`). Kotlin: MockK (`mockk<T>()`, `every { }`, `coEvery { }` for suspend functions, `verify`/`coVerify`); in Spring tests use the Spring-integrated variants. Mock at boundaries, not value objects.
- **Spring slices:** `@WebMvcTest` (controllers + MockMvc), `@DataJpaTest` (JPA repositories), `@JsonTest`, `@RestClientTest`; `@SpringBootTest` only for full wiring. Mocks of beans: `@MockitoBean` on current Spring versions (older projects use `@MockBean`).
- **Testcontainers:** real PostgreSQL/Kafka/etc. with `@Testcontainers` + `@Container`; Spring Boot `@ServiceConnection` wires connection details automatically. Prefer this over H2 when SQL dialect matters.
- **Coroutines:** `kotlinx-coroutines-test` `runTest`, inject dispatchers; Flow with Turbine if present.
- **Commands:**
  - Gradle all: `./gradlew test` (or `check` for tests + linters); one class/method: `./gradlew test --tests 'com.example.FooTest'` / `--tests 'com.example.FooTest.bar*'`; one module: `./gradlew :service:test`
  - Maven all: `./mvnw test` (`verify` for integration tests via Failsafe); one test: `./mvnw -Dtest=FooTest#bar test`; one module: `./mvnw -pl service -am test`
  - Coverage: JaCoCo (`jacocoTestReport` task / `jacoco-maven-plugin`) or Kover for Kotlin.

## 6. Security pitfalls

- **SQL/JPQL/HQL injection:** never concatenate input into `createQuery`, `createNativeQuery`, `JdbcTemplate` SQL or `@Query` strings. Use named/positional parameters (`:name`, `?`), Spring Data derived queries, Criteria API, jOOQ. Sort fields from requests must be whitelisted.
- **Deserialisation:** no `ObjectInputStream.readObject` on untrusted data (use an `ObjectInputFilter` if unavoidable); no Jackson polymorphic typing by class name (`activateDefaultTyping`, `@JsonTypeInfo(use = Id.CLASS)`) for untrusted JSON — use `Id.NAME` with explicit subtypes; YAML from users via SnakeYAML `SafeConstructor`.
- **XML (XXE):** disable DTDs/external entities on `DocumentBuilderFactory`, `SAXParserFactory`, `XMLInputFactory`, `TransformerFactory`.
- **Expression injection:** never evaluate SpEL, OGNL, EL or templates built from user input.
- **Spring Security:** a `SecurityFilterChain` bean with `authorizeHttpRequests` denying by default (`anyRequest().authenticated()`); keep CSRF on for browser/cookie sessions (disable only for stateless token APIs, with a comment); method security (`@EnableMethodSecurity`, `@PreAuthorize`) for object-level checks; passwords via `PasswordEncoder` (BCrypt/Argon2 through `DelegatingPasswordEncoder`).
- **Actuator:** expose only what you need (`management.endpoints.web.exposure.include=health,info`); `env`, `configprops`, `heapdump`, `threaddump`, `loggers` leak secrets or allow changes — keep them off or behind authentication on a separate management port.
- **Mass assignment:** bind requests to DTOs, never directly to entities.
- **Validation:** `spring-boot-starter-validation`, `@Valid` on `@RequestBody`, `@Validated` on `@ConfigurationProperties` and services with constraint annotations.
- **Secrets:** environment variables, a secrets manager or Spring Cloud config with encryption — not `application.yml` in git. `.env`, `local.properties`, keystores stay git-ignored.
- **Other:** path traversal (normalise and check `Path.startsWith(base)`), SSRF in URL fetchers, open redirects, CORS with `allowCredentials` + wildcard origins, Java `Random` for tokens (use `SecureRandom`).
- **Dependency audit:** OWASP Dependency-Check (Gradle plugin `org.owasp.dependencycheck`, task `dependencyCheckAnalyze`; Maven `org.owasp:dependency-check-maven:check`), or the platform's Dependabot/Renovate alerts. Inspect the graph with `./gradlew dependencies` or `./mvnw dependency:tree`. Validate the Gradle wrapper JAR in CI.

## 7. Performance pitfalls

- **JPA N+1:** lazy associations loaded per row in a loop or during JSON serialisation. Fix with `JOIN FETCH`, `@EntityGraph`, batch fetching (`hibernate.default_batch_fetch_size`), or DTO projections. Turn on SQL logging or Hibernate statistics in tests to count queries.
- **Open Session in View:** Spring Boot enables `spring.jpa.open-in-view` by default (and warns); it hides N+1 and holds connections for the whole request. Set it to `false` in new services and fetch what you need in the transaction.
- **Transactions:** keep them short; no remote calls inside; `@Transactional(readOnly = true)` for reads.
- **Pagination:** `Pageable` with a stable sort; avoid `JOIN FETCH` with pagination over collections (Hibernate paginates in memory and warns).
- **Connection pool (HikariCP):** size to the database, not to thread count; watch for pool exhaustion from long transactions.
- **Allocation:** avoid boxing in hot loops, `String +=` in loops (`StringBuilder`), streams for tiny hot paths; reuse `ObjectMapper` (thread-safe once configured).
- **Coroutines:** no blocking calls on `Dispatchers.Default`; limit parallelism (`Dispatchers.IO.limitedParallelism(n)`, semaphores).
- **Measure:** JMH for micro-benchmarks, JFR + JDK Mission Control or async-profiler for production profiles; Gradle build performance with `--profile` or the configuration/build cache.

## 8. Build and run errors

Read the first error; rerun with `--stacktrace` (Gradle) or `-e` (Maven). Full playbook: [build-errors.md](build-errors.md).

| Symptom | Likely cause | Fix |
|---|---|---|
| `Could not resolve all files for configuration` / `Could not find group:artifact:version` | version does not exist, repository missing, offline/proxy, private repo credentials | check coordinates, `repositories {}`/`dependencyResolutionManagement`, credentials via env/`~/.gradle/gradle.properties` |
| `Unsupported class file major version NN` | a tool (Gradle, plugin, Kotlin compiler) runs on a JDK older than the bytecode, or Gradle too old for the JDK | align JDK with toolchains; upgrade Gradle/plugin |
| `invalid target release` / `release version NN not supported` | compiling with an older JDK than the target | install/select the right JDK, use toolchains |
| `Inconsistent JVM-target compatibility detected for tasks 'compileJava' and 'compileKotlin'` | Java and Kotlin targets differ | `kotlin { jvmToolchain(N) }` so both match |
| `NoSuchMethodError` / `ClassNotFoundException` / `NoClassDefFoundError` at runtime | dependency version conflict or missing runtime dependency | `dependencyInsight` / `dependency:tree`; align with a BOM; check `implementation` vs `compileOnly` |
| `package javax.persistence does not exist` after Boot 3 upgrade | Jakarta namespace | migrate imports to `jakarta.*` (OpenRewrite recipes help) |
| Lombok getters "cannot find symbol" | annotation processor not configured | Gradle: `compileOnly` + `annotationProcessor` (also for tests); MapStruct + Lombok needs `lombok-mapstruct-binding` |
| kapt/KSP errors, `[ksp] ... version mismatch` | KSP or kapt incompatible with the Kotlin version | align versions per KSP compatibility notes; migrate from kapt to KSP where the library supports it |
| `Failed to configure a DataSource: 'url' attribute is not specified` | DB starter present but no config/profile | set `spring.datasource.*`, activate the profile, or exclude auto-config for apps without DB |
| `NoSuchBeanDefinitionException` / `UnsatisfiedDependencyException` | bean not scanned, missing `@Component`/config, conditional not met | check package under `@SpringBootApplication`, profiles, `@ConditionalOn...` report (`--debug`) |
| `The dependencies of some of the beans form a cycle` | circular injection (prohibited by default) | redesign; extract a third bean; don't just enable circular references |
| `LazyInitializationException: could not initialize proxy - no Session` | lazy relation accessed outside a transaction | fetch in the query (`JOIN FETCH`/`@EntityGraph`) or map to DTO inside the transaction |

## 9. Review checklist

- [ ] Build, tests and linters pass with the wrapper (`./gradlew check` / `./mvnw verify`).
- [ ] Constructor injection; no field injection; no `!!` without a proven invariant.
- [ ] Queries parameterised; DTOs at the API boundary; `@Valid` on inputs.
- [ ] Transactions on service methods called from another bean (self-invocation bypasses the proxy); no remote calls inside them.
- [ ] No N+1 (query count checked); `open-in-view` considered.
- [ ] Coroutines in structured scopes; `CancellationException` not swallowed; no blocking on the wrong dispatcher.
- [ ] Spring Security deny-by-default; actuator exposure minimal; no secrets in config or logs.
- [ ] Versions from BOM/catalog; no new dependency without reason.

Full list: [review-checklist.md](review-checklist.md).

## 10. Frameworks

- **Spring Boot:** profiles via `application-<profile>.yml` and `spring.profiles.active`; typed config with `@ConfigurationProperties` + `@Validated`; `@Transactional` rolls back on unchecked exceptions only by default; schema via Flyway/Liquibase with `spring.jpa.hibernate.ddl-auto=validate` or `none` outside local dev.
- **Spring Data JPA:** derived queries for simple cases, `@Query` with parameters otherwise, projections for read models, `@Version` for optimistic locking.
- **Ktor / Micronaut / Quarkus:** follow the framework's DI and config model; the security and JPA advice above still applies.
- **Android:** Gradle/AGP, Compose, lifecycle, ViewModel, R8 — [android.md](android.md).

Details and examples: [frameworks.md](frameworks.md).

Files in this skill

  • SKILL.md16.7 KB
  • android.md8.1 KB
  • build-errors.md8.8 KB
  • frameworks.md8.1 KB
  • review-checklist.md4.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.