---
name: build-errors-java
description: >
  Resolución de errores de compilación Java: javac, Maven, Gradle, conflictos
  de dependencias, annotation processors y problemas de classpath. Cargar cuando
  un build Java falle o haya errores de compilación o de dependencias.
version: "1.0.0"
herramientasPermitidas: [Read, Bash, Grep]
exclusiones:
  - "No cargar para errores de lógica de la aplicación Java en ejecución (NullPointerException, IllegalArgumentException en runtime) — el build compila exitosamente; el error es de lógica de negocio."
  - "No cargar para fallos de tests unitarios (JUnit assertions incorrectas, Mockito stubs mal configurados) — si `mvn test-compile` pasa pero los tests fallan en assertions, no es un error de build."
  - "No cargar para diseñar la arquitectura Maven multi-módulo desde cero — si la pregunta es cómo organizar módulos padre-hijo en un nuevo proyecto, cargar `java-patrones` o `java-experto`."
  - "No cargar para errores de Spring Boot en contexto de arranque (ApplicationContext failed to load) que no son de compilación — si el JAR se construye pero `java -jar` falla, son errores de configuración de Spring, no de build."
evolvable: true  # default para skill estandar
---
# Build Errors Java — Diagnóstico y Solución

Los errores de build de Java pueden venir del compilador, del sistema de build
(Maven/Gradle) o de las dependencias. Este skill cubre los errores más frecuentes
con su causa exacta y la solución paso a paso.

## Cuándo NO cargar

- El build compila pero la aplicación falla en ejecución (NPE, ClassCastException) — no es un error de compilación; revisar la lógica directamente.
- Los tests JUnit fallan por assertions incorrectas aunque compilan — es un error de lógica de tests.
- La pregunta es cómo organizar el proyecto Maven multi-módulo — para diseño cargar `java-patrones`.

## Cuándo cargar este skill

Invoca `Skill("build-errors-java")` cuando:

- `mvn compile` o `gradle build` falle con errores
- Haya errores `cannot find symbol` o `package does not exist`
- Existan conflictos de versión entre dependencias
- Fallen los annotation processors (Lombok, MapStruct, etc.)
- Haya errores de classpath en runtime después de un build exitoso

## Conceptos clave

### Separacion build-time vs runtime

Algunos errores solo aparecen en runtime aunque el build compile correctamente.
Las dependencias con scope `provided` o `compileOnly` no se incluyen en el
artefacto final — si se necesitan en runtime, hay un ClassNotFoundException.

### Dependency convergence en Maven/Gradle

Cuando dos dependencias A y B requieren distintas versiones de C, el build
necesita una sola versión. Maven usa la versión más cercana al POM raíz.
Gradle usa la versión más alta. Ambos pueden introducir incompatibilidades.

## Errores de javac — causa y solución

### `error: cannot find symbol`

**Causa**: La clase, método o variable referenciada no existe en el classpath
en tiempo de compilación. Puede ser un typo, un import faltante, o una
dependencia no declarada.

**Diagnostico**:
```bash
# Ver el classpath completo que usa javac
mvn dependency:build-classpath -Dmdep.outputFile=classpath.txt
cat classpath.txt

# O con Gradle
./gradlew dependencies --configuration compileClasspath
```

**Soluciones**:
1. Verificar que el import está presente en el archivo Java
2. Verificar que la dependencia está en `pom.xml` / `build.gradle`
3. Si es una clase generada (Lombok, QueryDSL), ejecutar `mvn generate-sources` primero

### `error: package X does not exist`

**Causa**: El paquete no está en el classpath. Diferente a `cannot find symbol`
en que afecta al package entero, no a una clase específica.

**Solucion**:
```xml
<!-- Maven: agregar la dependencia faltante -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
```

### `error: incompatible types: X cannot be converted to Y`

**Causa**: Asignación o llamada con tipo incorrecto. Frecuente al mezclar
tipos genéricos o al usar APIs que cambiaron su tipo de retorno.

```java
// Ejemplo: List<Object> no es asignable a List<String>
List<String> nombres = new ArrayList<Object>(); // ERROR
List<String> nombres = new ArrayList<>();       // OK — inferencia de tipo
```

### `error: unreported exception X; must be caught or declared to be thrown`

**Causa**: Llamada a método que lanza checked exception sin catch ni declaración
en la firma del método.

```java
// MAL — IOException no manejada
public void leerArchivo(String ruta) {
    Files.readString(Path.of(ruta)); // throws IOException
}

// BIEN — declarar o capturar
public void leerArchivo(String ruta) throws IOException {
    String contenido = Files.readString(Path.of(ruta));
}
```

## Errores de Maven — causa y solución

### `Could not resolve dependencies` / `Artifact not found`

**Diagnostico**:
```bash
mvn dependency:resolve -U   # -U fuerza update de snapshots
mvn dependency:tree         # ver el arbol de dependencias
```

**Causas y soluciones**:
1. Repositorio no configurado: agregar en `pom.xml` o `settings.xml`
2. Credenciales de repositorio privado incorrectas en `~/.m2/settings.xml`
3. Artefacto realmente no existe: verificar en https://search.maven.org

### `Plugin execution not covered by lifecycle configuration` (Eclipse/m2e)

**Causa**: El plugin de Maven no tiene binding en m2e para Eclipse.
**Solución**: Agregar `<pluginManagement>` en el pom para ignorar en m2e:

```xml
<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.eclipse.m2e</groupId>
            <artifactId>lifecycle-mapping</artifactId>
            <version>1.0.0</version>
            <configuration>
                <lifecycleMappingMetadata>
                    <pluginExecutions>
                        <pluginExecution>
                            <pluginExecutionFilter>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-enforcer-plugin</artifactId>
                                <versionRange>[1.0,)</versionRange>
                                <goals><goal>enforce</goal></goals>
                            </pluginExecutionFilter>
                            <action><ignore /></action>
                        </pluginExecution>
                    </pluginExecutions>
                </lifecycleMappingMetadata>
            </configuration>
        </plugin>
    </plugins>
</pluginManagement>
```

### Conflictos de version — `NoSuchMethodError` en runtime

**Diagnostico**:
```bash
mvn dependency:tree -Dverbose -Dincludes=com.fasterxml.jackson.core
# Buscar lineas con "omitted for conflict"
```

**Solución con dependencyManagement**:
```xml
<dependencyManagement>
    <dependencies>
        <!-- Forzar versión única de Jackson en todo el proyecto -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.17.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>
```

## Errores de Gradle — causa y solución

### `Could not resolve com.example:lib:1.0`

**Diagnostico**:
```bash
./gradlew dependencies --configuration runtimeClasspath
./gradlew dependencyInsight --dependency lib --configuration runtimeClasspath
```

**Solucion**: Verificar `repositories {}` en `build.gradle`:
```kotlin
repositories {
    mavenCentral()
    maven { url = uri("https://repo.empresa.com/maven2") }
}
```

### `Execution failed for task ':compileJava'` — error de annotation processor

**Causa frecuente**: Lombok o MapStruct no configurados como annotation processor.

```kotlin
// build.gradle.kts — configuración correcta de Lombok
dependencies {
    compileOnly("org.projectlombok:lombok:1.18.32")
    annotationProcessor("org.projectlombok:lombok:1.18.32")
    testCompileOnly("org.projectlombok:lombok:1.18.32")
    testAnnotationProcessor("org.projectlombok:lombok:1.18.32")
}
```

### Dependency locking — `FAILED` en version diferente a la bloqueada

```bash
# Actualizar el lock file cuando se cambian dependencias intencionalmente
./gradlew dependencies --write-locks
```

## Errores de classpath en runtime

### `ClassNotFoundException` o `NoClassDefFoundError`

**Diferencia**:
- `ClassNotFoundException`: la clase no está en el classpath — falta una jar
- `NoClassDefFoundError`: la clase estaba en compilación pero no en runtime
  — dependencia con scope `provided` no incluida en el fat jar

**Solucion en Spring Boot**:
```xml
<!-- Cambiar scope de provided a compile si se necesita en el jar final -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <!-- Quitar: <scope>provided</scope> si el contenedor no lo provee -->
</dependency>
```

### Multi-module projects — `Module not found`

```bash
# Compilar el módulo padre primero para que los módulos hijo lo encuentren
mvn install -pl modulo-comun
mvn compile -pl modulo-api

# O compilar todo el reactor en orden
mvn compile --projects modulo-comun,modulo-api
```

## Gotchas / Errores comunes no obvios

- **Lombok `@Data` compila sin errores pero en runtime falla con `NoSuchMethodError` para los getters/setters**: el annotation processor de Lombok no está configurado en `annotationProcessor` de Gradle o en `<annotationProcessorPaths>` de Maven, solo en `compileOnly`. Causa: `compileOnly` incluye el JAR en el classpath de compilación pero no activa el processor, por lo que los métodos generados no existen. Solución: agregar Lombok tanto en `compileOnly` como en `annotationProcessor` (Gradle) o en `annotationProcessorPaths` del `maven-compiler-plugin` (Maven).
- **`mvn dependency:tree` no muestra conflicto pero en runtime hay `ClassNotFoundException`**: la dependencia conflictiva está marcada con `provided` en el POM hijo pero `compile` en el padre. Causa: Maven elige el scope más restrictivo en jerarquía de módulos y la clase no llega al fat JAR final. Solución: ejecutar `mvn dependency:tree -Dincludes=grupo:artefacto:*:*` para ver todas las ocurrencias del artefacto con sus scopes en el árbol, y unificar a `compile` en el módulo que genera el ejecutable.
- **Gradle Kotlin DSL (`build.gradle.kts`) reporta error de `Unresolved reference` en el bloque `dependencies`**: el IDE muestra el error pero `./gradlew build` compila bien. Causa: el IDE usa un análisis estático de Kotlin para el DSL que difiere del evaluador de Groovy/Kotlin de Gradle en runtime. Solución: ejecutar `./gradlew build --rerun-tasks` desde línea de comandos para confirmar si el error es real — si pasa, el error del IDE es un falso positivo del análisis estático; sincronizar el proyecto Gradle en el IDE.
- **`cannot find symbol` apunta a una clase generada por MapStruct que sí existe en `target/generated-sources`**: el directorio de fuentes generadas no está incluido en el source set del compilador. Causa: algunos builds con Maven no agregan automáticamente `target/generated-sources/annotations` al source path. Solución: agregar explícitamente `<generatedSourcesDirectory>` en la configuración del `maven-compiler-plugin` o verificar que `build-helper-maven-plugin` incluye el directorio generado.

## Checklist de diagnóstico

- [ ] `mvn dependency:tree` o `./gradlew dependencies` para ver el árbol completo
- [ ] Buscar "omitted for conflict" en el árbol de dependencias
- [ ] Verificar que annotation processors están en `annotationProcessor`, no solo en `compileOnly`
- [ ] `mvn compile -X` o `./gradlew compileJava --info` para log verbose
- [ ] Para errores de runtime: verificar diferencia de scope `compile` vs `provided`
- [ ] En builds multi-módulo: compilar dependencias en orden correcto

## Referencias

- [Maven Dependency Plugin](https://maven.apache.org/plugins/maven-dependency-plugin/)
- [Gradle Dependency Management](https://docs.gradle.org/current/userguide/dependency_management.html)
- [Lombok Setup](https://projectlombok.org/setup/gradle)

---
*Skill creado con swl:crear-skill el 2026-03-31. Versión 1.0.0.*
