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:
- eseguire i test del progetto automaticamente
- compilare tutte le classi del programma
- scaricare le dipendenze di un progetto (cioè delle librerie scritte da altri sviluppatori che servono per i compiti più disparati come ad esempio trasformare un oggetto Java in JSON e viceversa, queste librerie possono avere dipendenze a loro volta... pensa a tutto Maven che per default per recuperare le librerie usa un archivio centrale in cui sono memorizzati più di 260000 file jar (librerie in diverse versioni)
- impacchettare il programma in un singolo file, solitamente un JAR, che può poi essere caricato su un server web o dato ad un cliente ad esempio (o usato come libreria da un altro programma)
...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:
- 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
eversion
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:
- aprire le preferenze di Eclipse
- aprire il gruppo "Maven"
- fare click su "User settings"
- fare click sul pulsante "browse" alla destra della casella "User Settings"