maven

gestione automatizzata di progetti java

Maven oltre che essere una parola Yiddish che significa "accumulatore di conoscenza" è un programma il cui scopo è quello solitamente definito come build automation cioè automatizzare le fasi di sviluppo del software (compilare, fare test, costruire pacchetti...). È nato come risposta all'esigenza di gestire uno dei progetti della fondazione Apache: il progetto era composto da diversi sottoprogetti ciascuno con una configurazione leggermente diversa dagli altri (il che crea ovviamente problemi quando uno sviluppatore deve spostarsi da un progetto all'altro), quel che si voleva fare era creare una via standard per gestire le fasi di vita di un progetto e al contempo ottenere una sua chiara descrizione e un modo facile per condividere file JAR generati tra diversi progetti.

Maven ora è lo strumento più usato per gestire progetti di ogni dimensione basati su Java.

A cosa serve

In breve a semplificare il lavoro di un gruppo di sviluppatori software consentendo di:

...e tante altre cose

Per portare a termine tutti i suoi compiti maven legge le impostazioni del progetto tramite il file pom.xml presente nella cartella principale del progetto stesso.

Creare un progetto

In un sistema attuale esistono molte opzioni per utilizzare Maven, ne vediamo due come esempio: installarlo nel sistema o utilizzare un IDE che gestisce i progetti Maven. Non è detto però che serva creare un nuovo progetto per usarlo: magari è possibile che il progetto venga fornito già fatto

Installarlo

La via più ovvia è di scaricarlo prima e poi scompattarlo e mettendo la sua cartella "bin" nel path. In alternativa se si ha a disposizione un ambiente tipo Unix (Linux, macOS, gitBash ...) si può installare SdkMan e poi far installare a lui Maven.

Una volta installato maven un comando tipo mvn archetype:generate -DgroupId=it.edu.esempi -DartifactId=hello -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false provvederà a creare una nuova cartella contenente il progetto.

Eclipse

In Eclipse è possibile creare un nuovo progetto Maven direttamente dall'IDE. Dal pannello che si apre dal menu /File/new/Other selezionare "Maven project" nel gruppo Maven, al primo tentativo per semplicità conviene spuntare "Create a simple project (skip archetype selection)", altrimenti al passo successivo Eclipse chiederà di selezionare un modello (Archetipo) in base al quale creare il progetto.

Se si dovesse modificare in futuro il file pom.xml poi bisogna farci clik con il tasto destro e selezionare "Maven/Update project..."

Cartelle

Un progetto viene generato a partire da un modello chiamato da Maven archetype e in base a questo vengono create alcune directory in posizioni standard, questo è uno degli obiettivi di Maven: organizzare un progetto (quindi le sue cartelle) in una maniera prefissata in modo da potersi muovere tra progetti diversi con facilità. Se i file stanno nella cartelle giuste non serve configurare nulla, Maven li troverà da solo.

Non tutti i progetti contengono tutte le cartelle possibili, troveremo però sempre una cartella src con dentro i sorgenti organizzati per tipologia (ad esempio i programmi di test, i file principali, le risorse...) e una cartella target creata all'occorrenza (ad esempio quando si compila) in cui verra generato l'output (le classi compilate ed altro).

Un esempio di progetto

Se si crea un semplice progetto spuntando "Create a simple project" in Eclipse si ottiene una cosa del genere:

progetto maven in eclipse

src/main/java
questa è la cartella in cui si trovano tutti i sorgenti Java del nostro progetto
src/main/resources
immagini, fogli di stile e tutto quanto fa parte del nostro progetto ma non è una classe java
src/test/java
in un progetto c'è bisogno di classi di test che dovranno essere inserite qui, queste classi non vanno caricate nel sistema in produzione
src/test/resources
tutto ciò che serve per i test e non è una classe java
JRE System Library
questa non è una cartella (non esiste su disco)mma la versione di java che stiamo utilizzando nel progetto... purtroppo una vecchissima ma la modificheremo
src
questa è la cartella che contiene in realtà le prime 4 cartelle elencate sopra
target
questa è la cartella in cui lavora Maven: ci mette i file compilati e tutto quello che produce come i pacchetti (niente di complicato! sono dei file "war" o "jar" che in pratica contengono il software compilato e gli altri file come le immagini che gli servono per funzionare)
pom.xml
file di configurazione di Maven, descritto nella prossima sezione

pom.xml

Questo è il file che definisce tutte le impostazioni del progetto, scritto in XML, può contenere tantissime informazioni, adesso ci concentriamo su quelle principali guardando un file di esempio:

<?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>

  <!-- informazioni sul progetto -->
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1.2.1</version>
  <name>my-app</name>
  <url>http://www.example.com</url>

  <!-- proprietà -->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>

  <!-- dipendenze -->
  <dependencies>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.13.3</version>
    </dependency>
  </dependencies>

</project>

Vediamo qui sotto parte per parte quali informazioni stiamo fornendo a Maven con questo file.

Informazioni sul progetto

Sono in pratica quelle che descrivono il progetto al resto del mondo:

goupId
segue le regole dei pacchetti di java, identifica il progetto
artifactId
è il nome del singolo file jar, del pacchetto che stiamo creando
version
la vesrione attuale del progetto, il tipico numero di versione che usa il punto
name
il nome del progetto
url
il sito web del progetto

Proprietà

Niente di più di proprietà generali... le due che sono presenti nell'esempio sono molto importanti.

project.build.sourceEncoding è la codifica dei file sorgente: è importante, dobbiamo saperla e dirla a Maven perché ad esempio le accentate potrebbero fare una brutta fine altrimenti. Usualmente è UTF-8 ma in alcuni ambienti meglio essere sicuri: da verificare in base all'editor che si usa.

maven.compiler.release la versione di Java che stiamo utilizzando, di nuovo molto importante! Magari a noi serve una particolare caratteristica disponibile soltanto da una certa versione di Java in poi ma non è detto che si possa liberamente scegliere perché magari il server su cui verrà caricato il nostro progetto supporta fino al massimo una certa versione e non oltre. In genere è più facile scaricare la stessa versione del server sul client piuttosto che viceversa.

Dipendenze

In questa sezione si specificano tutti i componenti software di cui il progetto ha bisogno: sarà poi compito di maven gestirli. Per soddidfare le dipendenze di un progetto Maven cerca i componenti nel repository locale, cioè una cartella nel nostro computer (.m2 nella home dell'utente) e se non li trova lì li scarica dal suo repository centrale.

Di ogni componente possiamo specificare diversi parametri, vediamo i principali:

groupId
questo è il gruppo a cui appartiene l'artefatto
artifactId
l'identificativo dell'artefatto, insieme a groupId e version sono in pratica le coordinate della dipendenza
version
è la versione specifica che ci interessa, questo paramentro può essere specificato in diversi modi, il più semplice dei quali è il solito sistema di numeri separati da punto
scope
"quando serve questa dipendenza?", se non viene specificato viene sottinteso compile che in pratica vuol dire che la dipendenza serve sempre, altrimenti è possibile specificare quando serve (ad esempio "soltanto per i test").

In genere per trovare "le coordinate" di un pacchetto è possibile cercare su Maven Central Repository se non si hanno i dati a disposizione.

Gestire un progetto maven

Per gestire da linea di comando un progetto Maven si usa la solita sintassi mvn <comando> [eventuali parametri], il bello è che i comandi sono spesso dei plugin che se non abbiamo scaricato localmente vengono scaricati al volo (ovviamente con tutte le dipendenze del caso) senza che si faccia nulla.

Proviamo a vedere alcuni esempi: mvn clean rimuove tutti i file generati in fase di compilazione/test, mvn package crea un pacchetto (solitamente un file jar) nella cartella target del progetto che poi può essere inviato a chi deve usare il programma, mvn dependency:tree visualizza l'albero delle dipendenze del progetto...

Un esempio: valutare espressioni

Un mio programma tra le altre cose legge degli input che sono delle espressioni come ad esempio 3+2*8/(2+2) e ha bisogno di calcolarne il risultato.

Trovare una libreria

Potrei anche lavorare un pochino di tempo e scrivere un bel pezzo di software che valuta qualsiasi espressione ma... non è facile e magari c'è chi lo ha già fatto e cercando un pochino on line trovo una libreria: javaluator. Sono convinto che ne esistano altre ma questa sembra andar bene e ha pure una licenza che mi consente di utilizzarla!

Visto che ho trovato la libreria creo il progetto con Eclipse e tra le dipendenze presenti nel file pom.xml inserisco questa:

  <dependency>
    <groupId>com.fathzer</groupId>
    <artifactId>javaluator</artifactId>
    <version>3.0.3</version>
  </dependency>

Dopo aver salvato chiedo ad eclipse di aggiornare il progetto (click destro sul pom.xml...) e creo una classe nel cui metodo main scrivo:

String espressione = "3+2*8/(2+2)";
DoubleEvaluator valutatore = new DoubleEvaluator();
double risultato = valutatore.evaluate(espressione);
System.out.println(risultato);

Funziona! Potrei andare avanti scrivendo il mio programma che tratta sequenze di numeri non solo espressioni... devo spesso calcolare massimi/minimi e fare diverse operazioni di questo genere con i numeri: anziché riscrivere tutto da capo utilizzo un'altra libreria chiamata "Commons Lang" semplicemente aggiungedo una ulteriore dipendenza nella sezione <dependencies> del mio pom.xml che a questoi punto diventerà

<dependencies>
  <dependency>
    <groupId>com.fathzer</groupId>
    <artifactId>javaluator</artifactId>
    <version>3.0.3</version>
  </dependency>
  <dependency>
    <groupId>org.netbeans.external</groupId>
    <artifactId>org-apache-commons-lang3</artifactId>
    <version>RELEASE130</version>
  </dependency>
</dependencies>

Questa ultima ha un numero di versione un tantino strano ma pazienza. Posso inserire tutte le dipendenze che voglio, meno facile è trovare quale libreria fa al caso nostro: bisogna informarsi!

In caso di proxy

Maven fa accesso alla rete per scaricare il software, se il nostro computer deve usare un proxy dobbiamo indicarlo in uno specifico file di configurazione, questo file se usiamo eclipse possiamo chiamarlo come vogliamo e salvarlo dove vogliamo. Soltanto per esempio poniamo di chiamarlo "maven-setting.xml" e di salvarlo sulla scrivania:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
  <proxies>
    <proxy>
      <id>proxy-http</id>
      <active>true</active>
      <protocol>http</protocol>
      <host>10.1.1.254</host>
      <port>3128</port>
    </proxy>
    <proxy>
      <id>proxy-https</id>
      <active>true</active>
      <protocol>https</protocol>
      <host>10.1.1.254</host>
      <port>3128</port>
    </proxy>
  </proxies>
</settings>

Ovviamente come host e come porta vanno inseriti quelli della nostra rete.

Una volta salvato il file bisogna indicarlo ad Eclipse:

  1. aprire le preferenze di Eclipse
  2. aprire il gruppo "Maven"
  3. fare click su "User settings"
  4. fare click sul pulsante "browse" alla destra della casella "User Settings"