# Regla: Hooks de Desarrollo Java

Los hooks de desarrollo son verificaciones automáticas que atrapan problemas
antes de que lleguen al repositorio o al CI. Ejecutar manualmente es propenso
a olvidos — automatizar garantiza consistencia.

---

## Checkstyle: verificación de estilo antes de commit

Checkstyle verifica que el código sigue las convenciones definidas. Se integra
como plugin de Maven/Gradle y como pre-commit hook.

```xml
<!-- pom.xml -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-checkstyle-plugin</artifactId>
  <version>3.3.1</version>
  <configuration>
    <configLocation>google_checks.xml</configLocation>
    <failsOnError>true</failsOnError>
    <violationSeverity>warning</violationSeverity>
  </configuration>
  <executions>
    <execution>
      <id>validar-estilo</id>
      <phase>validate</phase>
      <goals><goal>check</goal></goals>
    </execution>
  </executions>
</plugin>
```

Pre-commit hook local (`.git/hooks/pre-commit`):

```bash
#!/bin/sh
# Verificar estilo Checkstyle antes de cada commit
mvn checkstyle:check -q 2>&1
if [ $? -ne 0 ]; then
    echo "ERROR: Checkstyle falló. Corregir estilo antes de hacer commit."
    echo "Ejecutar: mvn checkstyle:check para ver los errores."
    exit 1
fi
```

---

## Spotless: formato automático obligatorio

Spotless puede formatear en lugar de solo verificar. Integrar como hook de
formato automático antes de verificar estilo.

```xml
<!-- pom.xml — Spotless formatea con google-java-format -->
<plugin>
  <groupId>com.diffplug.spotless</groupId>
  <artifactId>spotless-maven-plugin</artifactId>
  <version>2.43.0</version>
  <configuration>
    <java>
      <googleJavaFormat>
        <version>1.19.2</version>
        <style>AOSP</style>
      </googleJavaFormat>
      <removeUnusedImports/>
      <trimTrailingWhitespace/>
    </java>
  </configuration>
  <executions>
    <execution>
      <phase>compile</phase>
      <goals><goal>check</goal></goals>
    </execution>
  </executions>
</plugin>
```

Aplicar formato manualmente antes de commit: `mvn spotless:apply`

---

## SpotBugs: análisis estático

SpotBugs detecta bugs comunes (null pointer potential, resource leaks, bad practices)
antes de que lleguen a producción.

```xml
<!-- pom.xml -->
<plugin>
  <groupId>com.github.spotbugs</groupId>
  <artifactId>spotbugs-maven-plugin</artifactId>
  <version>4.8.3.0</version>
  <configuration>
    <effort>Max</effort>
    <threshold>Medium</threshold>
    <failOnError>true</failOnError>
    <plugins>
      <!-- Detectar bugs de seguridad adicionales -->
      <plugin>
        <groupId>com.h3xstream.findsecbugs</groupId>
        <artifactId>findsecbugs-plugin</artifactId>
        <version>1.13.0</version>
      </plugin>
    </plugins>
  </configuration>
  <executions>
    <execution>
      <phase>verify</phase>
      <goals><goal>check</goal></goals>
    </execution>
  </executions>
</plugin>
```

---

## JaCoCo: cobertura mínima en CI

La cobertura se verifica en CI como gate bloqueante. Sin cobertura >= 80%,
el build falla y no se puede mergear.

```xml
<!-- pom.xml -->
<plugin>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
  <version>0.8.11</version>
  <executions>
    <execution>
      <id>prepare-agent</id>
      <goals><goal>prepare-agent</goal></goals>
    </execution>
    <execution>
      <id>report</id>
      <phase>test</phase>
      <goals><goal>report</goal></goals>
    </execution>
    <execution>
      <id>check</id>
      <phase>verify</phase>
      <goals><goal>check</goal></goals>
      <configuration>
        <rules>
          <rule>
            <element>BUNDLE</element>
            <limits>
              <limit>
                <counter>LINE</counter>
                <value>COVEREDRATIO</value>
                <minimum>0.80</minimum>
              </limit>
            </limits>
          </rule>
        </rules>
      </configuration>
    </execution>
  </executions>
</plugin>
```

---

## Detección de System.out.println en código no-test

`System.out.println` en código de producción es un antipatrón. El logger
configurado maneja niveles, formatos y destinos correctamente.

Hook en CI (o pre-commit) que detecta y bloquea:

```bash
#!/bin/sh
# Detectar System.out.println en código que no es test
ARCHIVOS_CON_PRINT=$(grep -r "System\.out\.println" src/main/ --include="*.java" -l)

if [ -n "$ARCHIVOS_CON_PRINT" ]; then
    echo "ERROR: System.out.println detectado en código de producción."
    echo "Usar SLF4J (log.info, log.debug, log.error) en su lugar."
    echo "Archivos afectados:"
    echo "$ARCHIVOS_CON_PRINT"
    exit 1
fi
```

En el `pom.xml` con Checkstyle, agregar la regla `RegexpSingleline`:

```xml
<module name="RegexpSingleline">
  <property name="format" value="System\.out\.println"/>
  <property name="message" value="Usar SLF4J en lugar de System.out.println"/>
</module>
```

---

## Verificación de @Deprecated sin javadoc de reemplazo

Métodos deprecados sin indicar el reemplazo confunden al equipo.

```java
// MAL — sin indicación de reemplazo
@Deprecated
public Factura crearFacturaLegacy(String datos) { ... }

// BIEN — documenta cuándo fue deprecado y qué usar en su lugar
/**
 * @deprecated Desde v2.3.0. Usar {@link FacturaService#crear(CrearFacturaRequest)} en su lugar.
 */
@Deprecated(since = "2.3.0", forRemoval = true)
public Factura crearFacturaLegacy(String datos) { ... }
```

Script de verificación en CI:

```bash
#!/bin/sh
# Detectar @Deprecated sin comentario de reemplazo
DEPRECATED_SIN_DOC=$(grep -B2 "@Deprecated" src/main/**/*.java | grep -v "@deprecated" | grep "@Deprecated" || true)

if [ -n "$DEPRECATED_SIN_DOC" ]; then
    echo "ADVERTENCIA: @Deprecated sin javadoc de reemplazo encontrado."
    echo "Agregar @deprecated en el javadoc indicando el reemplazo y la versión."
fi
```

---

## Pipeline CI completa de calidad

Orden de ejecución en el pipeline de CI (cada fase bloquea las siguientes):

```
1. mvn spotless:check          → Formato de código
2. mvn checkstyle:check        → Estilo y convenciones
3. mvn test                    → Tests unitarios
4. mvn spotbugs:check          → Análisis estático
5. mvn verify                  → Tests de integración + cobertura JaCoCo
6. mvn dependency-check:check  → Vulnerabilidades en dependencias
```

---

## Checklist de hooks Java antes de hacer commit

- [ ] `mvn spotless:check` pasa (o `mvn spotless:apply` aplicado)
- [ ] `mvn checkstyle:check` pasa sin errores
- [ ] Sin `System.out.println` en `src/main/`
- [ ] Métodos @Deprecated tienen javadoc con reemplazo y versión
- [ ] `mvn test` pasa localmente
- [ ] `mvn spotbugs:check` pasa sin bugs de severidad media o alta
