Apèndix C — Projectes Java amb Maven

Quan un programa creix més enllà d’un sol fitxer .java, necessitem organitzar-lo i gestionar-ne les dependències o biblioteques externes.

Aquest annex explica l’estructura estàndard d’un projecte Java i com Maven ens ho automatitza.

C.1 L’estructura estàndard d’un projecte Java

Un projecte Maven segueix una convenció de carpetes coneguda per tothom. Això vol dir que qualsevol persona (o eina) que obri el projecte sap immediatament on és cada cosa.

biblioteca/
├── pom.xml                                     ← Configuració del projecte
└── src/
    ├── main/
    │   ├── java/                               ← Codi font de l'aplicació
    │   │   └── cat/biblioteca/
    │   │       ├── App.java
    │   │       ├── model/Llibre.java
    │   │       └── dao/LlibreDAO.java
    │   └── resources/                          ← Fitxers no-codi (config, dades...)
    └── test/
        └── java/                               ← Codi de proves (tests)
NotaConvenció abans que configuració

Maven parteix del principi “convention over configuration”: si col·loques els fitxers on toca (src/main/java, src/test/java…), no cal configurar res.

Només et desvies de la convenció quan tens una necessitat especial.

Els noms de carpeta sota java/ reflecteixen el paquet (package) de les classes.

Per exemple, cat/biblioteca/model/Llibre.java conté una classe amb package cat.biblioteca.model;.

C.2 Què és Maven?

Maven és una eina de construcció (build tool) per a projectes Java. S’encarrega de tasques repetitives que faríem a mà:

flowchart LR
    A["Descarregar<br/>dependències"] --> B["Compilar<br/>el codi"]
    B --> C["Executar<br/>les proves"]
    C --> D["Empaquetar<br/>(.jar)"]

Sense Maven, hauries de baixar manualment cada biblioteca .jar, col·locar-la al lloc correcte, passar-la al compilador… i repetir-ho cada vegada.

Maven ho fa tot a partir d’un únic fitxer de configuració: el pom.xml.

ConsellEl gran avantatge: dependències automàtiques

Només has de declarar quina biblioteca vols (i quina versió). Maven la baixa d’un repositori central a Internet, junt amb tot el que aquesta biblioteca necessiti al seu torn (les dependències transitives), i les hi posa disponibles. Res de buscar .jar per la xarxa.

El POM (Project Object Model) és el cor del projecte. És un fitxer XML que descriu què és el projecte i de què depèn.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- Coordenades: identifiquen el projecte de manera única -->
    <groupId>cat.biblioteca</groupId>
    <artifactId>biblioteca</artifactId>
    <version>1.0.0</version>

    <!-- Propietats: versió de Java, codificació... -->
    <properties>
        <maven.compiler.release>21</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!-- Dependències: biblioteques externes -->
    <dependencies>
        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
            <version>3.46.0.0</version>
        </dependency>
    </dependencies>
</project>

Cada projecte (i cada biblioteca) s’identifica amb tres dades, les*coordenades. Igual que unes coordenades geogràfiques localitzen un punt del mapa, aquestes localitzen un artefacte de manera única al repositori.

Coordenada Què és Exemple
groupId L’organització o grup (com un domini a l’inrevés) org.xerial
artifactId El nom del projecte/biblioteca sqlite-jdbc
version La versió concreta 3.46.0.0


Quan afegeixes una dependència, escrius les coordenades d’aquesta biblioteca. Les trobaràs a mvnrepository.com o al lloc web de cada projecte.

C.3 El cicle de vida de construcció

Maven organitza la feina en fases que s’executen en ordre. Quan demanes una fase, s’executen totes les anteriors automàticament.

flowchart LR
    A["validate"] --> B["compile"]
    B --> C["test"]
    C --> D["package"]
    D --> E["verify"]
    E --> F["install"]

Fase Ordre mvn ... Què fa
compile mvn compile Compila el codi de src/main/java
test mvn test Compila i executa les proves de src/test/java
package mvn package Empaqueta el resultat en un .jar (a target/)
clean mvn clean Esborra la carpeta target/ (recomença de zero)
install mvn install Instal·la el .jar al repositori local per reutilitzar-lo
Consell

La combinació més habitual mentre desenvolupes és:

mvn clean package

Neteja, compila, passa les proves i genera el .jar, tot d’una tirada.

C.4 Executar el projecte amb Maven

El plugin exec-maven-plugin executa la classe main sense sortir de Maven:

mvn compile exec:java -Dexec.mainClass="cat.biblioteca.App"

Perquè sigui més còmode, pots fixar la classe principal al pom.xml:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <mainClass>cat.biblioteca.App</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

I aleshores n’hi ha prou amb:

mvn compile exec:java

Una altra opció és utilitzar Shade Plugin. Ens crea un únic .jar que porta el nostre codi i totes les biblioteques a dins.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.5.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals><goal>shade</goal></goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>cat.biblioteca.App</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

Després de mvn clean package, pots executar l’aplicació a qualsevol màquina amb Java:

java -jar target/biblioteca-1.0.0.jar
Notaexec vs shade
  • exec: còmode mentre desenvolupes (no genera cap fitxer per distribuir).
  • shade: per entregar l’aplicació acabada com un únic .jar que funciona a qualsevol lloc.

C.5 Errors típics

  • Fitxers fora de src/main/java → Maven no els compila. Respecta la convenció.
  • JAVA_HOME mal configurat → Maven no troba el JDK.
  • Versió de dependència inexistent → error en baixar; comprova-la a mvnrepository.com.
  • java -jar d’un .jar normal falla amb NoClassDefFoundError** → et falta el shade per incloure les dependències.
  • Editar el .jar de target/ a mà → target/ és generada; sempre es regenera amb mvn package.

C.6 Mini-exercicis

  1. Crea un projecte Maven amb l’estructura estàndard i una classe App que imprimeixi “Hola, Maven!”.
  2. Afegeix la dependència sqlite-jdbc al pom.xml i comprova amb mvn compile que es baixa.
  3. Configura el plugin exec i executa l’aplicació amb mvn compile exec:java.
  4. Genera un fat jar amb shade i executa’l amb java -jar.

C.7 Resum

  • Un projecte Java segueix l’estructura src/main/java, src/test/java, src/main/resources.
  • Maven automatitza baixar dependències, compilar, provar i empaquetar, tot des del pom.xml.
  • Les coordenades (groupId/artifactId/version) identifiquen projectes i dependències.
  • El cicle de vida (compiletestpackage) executa les fases en ordre.
  • Ús de exec per desenvolupar i shade per distribuir un .jar autònom.