Java — app simples / CLI / worker¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-06-19
O arquétipo Java puro (sem framework) — uma ferramenta, um job, um cliente de API de linha de comando. Para servidor/API a stack é Micronaut (Stack da casa); aqui está o como de um app Java que não é servidor.
Organização do código¶
package-by-feature (default da casa, §Stack): cada funcionalidade é um
pacote de topo que carrega suas camadas; o compartilhado em comum/core. Anti-padrão
a evitar: feature-first ingênuo vira "core monolítico + features anêmicas" — a regra é
pipeline genérico no kernel + uma estratégia (interface) para o que varia. Base
package: br.com.xadm.<cliente>.<app>.
Build — Gradle (Kotlin DSL)¶
- Gradle wrapper versionado (
./gradlew, nunca Maven); Java via SDKMAN. - Pin de dependências; gate único
./gradlew check(compila + checkstyle + testes). No agente/local,./gradlew test --quiet --console=plain(saída enxuta, sem progresso — higiene de saída). - Checkstyle: copie
checkstyle.xml suppressions.xmldo central paraconfig/checkstyle/— fonte única, não copie de outro app. Amarre nocheck:
plugins { checkstyle }
checkstyle { toolVersion = "10.x"; configDirectory.set(file("config/checkstyle")) }
- Nome do jar:
<app>-<versão>.jar(shadow/fat jar quando distribuído). A versão vem doproject.version, nunca um literal — ver versionamento.
Logging — Logback por arquétipo¶
A regra STDOUT = dados/contrato; STDERR + arquivo = logs é só do CLI/worker cujo
stdout é consumido por outro processo: ali um logback.xml que loga no console (stdout)
corrompe a saída. Servidor é o oposto: loga em stdout (o Docker/Coolify
captura) — está certo, e o /health/contrato é HTTP, não o stdout. Tenha logback.xml
por arquétipo: servidor → stdout; CLI/worker → stderr + arquivo. Não copie o logback
de um arquétipo para o outro.
Tipos¶
BigDecimal para valores monetários/fiscais — nunca double/float.
CLI (picocli)¶
- picocli para parsing; o
--versionlê de umIVersionProviderque carrega a versão do manifesto (project.version), nunca@Command(version = "...")literal (mente e drifta — ver versionamento). - Exceção → exit code:
0ok ·1parcial ·2config/auth ·3externo ·4ocupado/lock (execução concorrente serializada por lock; nada feito; seguro repetir — o agendador trata como "tente depois", não como erro). Esta lista é o contrato canônico de exit code da casa: o app não inventa código — desfecho novo entra por feedback §6. O app documenta seu comportamento de saída no runbook deoperacao/, referenciando esta lista. - Sem flags ⇒ valida a config + imprime o help (não falha calado).
- Log de observabilidade por requisição (envio → resposta → processado); segredo nunca logado.
Testes¶
- JUnit 5. Cliente de API REST: piso = unit (normalização/mapeamento) + integração com mock HTTP (WireMock) sobre fixtures anonimizadas.
- Convenção de fixtures (golden-master datada, receita de captura, anonimização) e Testcontainers: Testes e fixtures (Micronaut) — vale para app Java simples também.
- Gate e níveis de teste: CI, gates e testes.
- Não desabilite teste por OS (
@DisabledOnOs(OS.WINDOWS)): ele fica invisível ao pré-flight do release (que roda no Windows), passa verde nochecklocal e só falha na CI Linux, pós-tag. Prefira cross-OS; se for genuinamente Linux-only, rode o gate no containerci-javaou confirme a CI verde antes de taggar — gate cego pré-flight×CI.