Innhold
Introduksjon
Maven er et av de mest benyttede byggesystemer for Java. Et byggesystem sørger for at prosjektet kompilerer, testes og pakkes/leveres i henhold til prosjektets spesifikasjoner. Det finnes mange byggesystemer (Make, Ant, Gradle med flere). Det som i hovedsak skiller disse systemene, er om de baserer seg på konfigurasjon eller konvensjon:
- konfigurasjon - du som utvikler må beskrive hele prosjektet ditt for byggesystemet; hvor kildekoden din ligger på harddisken, hvor eksterne biblioteker ligger, hvor ferdig kompilert og pakket kode skal plasseres osv.
- konvensjon - byggesystemet forutsetter en bestemt mappe-struktur i prosjektet ditt, samt har sin egen måte å håndtere avhengigheter til eksterne biblioteker. Du trenger da kun å spesifisere i prosjektet det som er utover konvensjonen.
Maven baserer seg på konvensjon og ikke konfigurasjon. Et nyere byggesystem, Gradle baserer seg på de samme konvensjonene som Maven.
På denne siden og undersidene gir vi deg noen tips og forslag til ulike oppsett ved bruk av Maven.
Installere Maven
Maven følger ofte med moderne IDE'er som intelliJ og Netbeans. Da kan du uten videre opprette prosjekter basert på Maven direkte fra IDE'en din.
Ønsker du i tillegg å kjøre Maven fra kommandolinja/terminalvinduet, må du installere Maven på din datamaskin.
Det er flere måter å installere Maven på:
- Standard metode (og den mest manuelle), er som beskrevet på Maven sin hjemmeside, eller som oppsummert her hos Baeldung.
- Eller ved å bruke pakkeverktøy (Ubuntu Linux og MacOS):
- MacOSX: Installer Homebrew, og bruk deretter Homebrew til å installere Maven.
- Ubuntu: Installer Homebrew på Linux, eller velg annet pakke-verktøy.
Prosjektfilen pom.xml
Introduksjon
Prosjektfilen i Maven kalles Project Object Model (POM) i form av filen pom.xml. Denne filen skal ligge på roten av prosjektmappen din.
Alle Maven-prosjekter skal være unikt identifiserbare gjennom prosjektkoordinatene groupID:artifactID:version der:
- groupID - er en unik ID som regel for bedriften eller organisasjonen som eier prosjektet. Her benyttes som regel domene-navnet til organisasjonen, men i omvendt rekkefølge. Eksempel: Dersom du utvikler et program for Institutt for IKT og Realfag (IIR) ved fakultet for Informasjonsteknologi og elektroteknikk (IE), vil vi kanskje bruke "no.ntnu.ie.iir" som goupID.
- artifactID - er som regel navnet på applikasjonen du lager, skrevet i ett ord, med kun små bokstaver. Dersom produktnavnet består av flere ord, benyttes bindestrek. Eksempel: "wargames", "card-game", "smart-city-support-tool" osv.
- version - ALLE prosjekter/produkter SKAL ha versjonsnummer. Her har Maven sin egen "beste praksis" som bør følges.
En pom fil kan etterhvert bli ganske omfattende i store prosjekter. Det er definert en standard for selve strukturen og rekkefølgen innholdet i en pom-fil skal følge. Den finner du her: https://maven.apache.org/developers/conventions/code.html#pom-code-convention. Øvrige "beste praksis" i Maven-verden finner du her: https://maven.apache.org/developers/conventions/code.html.
Eksempel på en minimum POM-fil
Her er eksempel på en minimum POM-fil, som kan benyttes som utgangspunkt for et hvert Maven prosjekt:
<project>
<!-- model version is always 4.0.0 for Maven 3.x POMs -->
<modelVersion>4.0.0</modelVersion>
<!--
project coordinates, i.e. a group of values which uniquely identify this project
NB! YOU have to set your own values here.
-->
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- Some project variables -->
<properties>
<!--
Set version of Java used by the source code and to produce the output for.
If not set, the default version 1.6 is used.
The current LTS (Long Time Support) version is 25 (in dec 2025).
After version 9: do not use "source" and "target", but use "release" instead.
-->
<maven.compiler.release>25</maven.compiler.release>
<!--
A Java source-file is a "plain text file", but since there is no such thing as a
"standard plain text file" (since there are several text-encodings out there), we
need to telle the Java-compiler what the coding format is for your Java-files.
The standard is the UTF-8 encoding.
-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
Dette er alt du trenger for å kompilere og pakke et Java prosjekt som ikke benytter eksterne biblioteker (JAR-filer).
I de påfølgende avsnittene tar vi for oss ulike tillegg til POM-filen for å håndtere- og konfigurere oppgaver som testing, inkludere avhengige biblioteker, generere JavaDoc med mer.
Avhengigheter (dependencies)
I litt større prosjekter, benytter vi kode som ikke befinner seg i standard utviklingspakken til Java (JDK). Slik kode refererer vi da som regel til som eksterne biblioteker og i Java kommer disse som oftest i form av en eller flere JAR-filer.
Definere avhengigheter (dependencies) i pom.xml
Vi definerer avhengigheter (dependencies) i pom.xml-filen som følger:
<dependencies> ..... <dependency> <groupId>the.company</groupId> <artifactId>the-artifact</artifactId> <version>1.2.3</version> </dependency> .... </dependencies>
Maven sørger selv for å finne den rette JAR-filen fra Maven Central Repository, og laste den ned til ditt lokale Maven repository (i den skjulte mappen ".m2" under din bruker).
Laste ned Javadoc og kildekode til biblioteker
Det kan være nyttig å laste ned Javadoc for the bibliotek som vi har lagt til under dependencies, slik at vi får tilgang til dokumentasjon i IDE'en. Dette kan gjøres på flere måter (som bl.a. beskrevet her: https://www.baeldung.com/maven-download-sources-javadoc).
En enkel måte er å skrive følgende Maven-kommando i terminalvinduet fra roten i projsektet:
mvn dependency:sources dependency:resolve -Dclassifier=javadoc
JavaDoc - automatisk generere
For å automatisk generere JavaDoc fra prosjektet, må vi legge til en plugin. Hele Maven er egentlig et rammeverk for plugins, der hver plugin utfører en bestemt oppgave.
JavaDoc-plugin heter Apache Maven Javadoc Plugin. En plugin kan enten stå på egne ben, og kjøres manuelt (f.eks. mvn javadoc:javadoc vil generere JavaDoc for prosjektet uavhengig av bygg-syklusen), eller vi kan "koble på" en plugin til bygg-livssyklusen.
Her er et eksempel der JavaDoc-plugin er påkoblet livssyklusen package.
<build>
.....
<plugins>
....
<plugin>
<!-- As everything else in Maven, a Plugin is also uniquely identified by its coordinates -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.1</version>
<!-- configure how to execute this plugin -->
<executions>
<execution>
<!--
connect the execution of the plugin to the Maven lifecycle phase "package"
so that JavaDoc is generated every time you run "mvn package"
-->
<phase>package</phase>
<id>attach-javadocs</id>
<!--
set which of the goals in the plugin to execute. The JavaDoc plugin
has a total of 16 goals to choose from. See: https://maven.apache.org/plugins/maven-javadoc-plugin/
The most common once being either "javadoc" or "jar"
-->
<goals>
<goal>javadoc</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- generate javadoc only for public classes and members -->
<show>public</show>
<!-- Omits the HELP link in the navigation bars at the top and bottom of each page of output. -->
<nohelp>true</nohelp>
</configuration>
</plugin>
.....
</plugins>
......
</build>
Legg merke til notasjonen over:
<build>
.....
<plugins>
....
<plugin>
</plugin>
.....
</plugins>
......
</build>
En POM-fil har en <build>-seksjon der vi legger inn diverse innstillinger og plugins som tilhører byggingen av prosjektet. Denne seksjonen kan inneholde mye, blant annet en samling av plugins. Notasjonen "......" indikerer at det kan være ting foran (altså mellom <build> og <plugins>. Når du skal legge inn koden over i din POM.xml fil, og denne ikke inneholder hverken <build> eller <plugins> fra før, kopierer du alt, og fjerner ".....". Dersom pom.xml-filen din allerede inneholder en <build>-seksjon, kopierer du bare fra <plugins> til </plugins> og limer inn, osv.
JavaDoc-plugin kan også legges til i en seksjon som kalles reporting (<reporting>). Da vil JavaDoc bli generert når vi velger å bygge web-sidene for prosjektet (det som kalles site). Mer om det siden.
NB! Dersom koden din er mangelfull i forhold til JavaDoc (mangler javaDoc på public metoder, ufullstendig JavaDoc osv), vil du få WARNINGS med lenke til hvor i koden JavaDoc mangler.
Vellykket generering av JavaDoc skal gi følgende melding i terminal-vinduet/bygg-vinduet:
Selve JavaDoc'en for prosjektet finner du under mappen "target→site":
Enhetstesting med JUnit 4 og/eller JUnit5
For detaljer og anbefalinger (beste praksis) for å implementere enhetstester, se Enhetstesting (JUnit5).
Klassene som utgjør JUnit-rammeverket er ikke inkludert i JDK'en. Da må vi fortelle prosjektet vårt at prosjektet vårt avhenger av (depends on) en ekstern artifakt. Og som alt annet i Maven, så er også disse eksterne bibliotekene unikt definert ved sine koordinater (groupID og artifactID).
JUnit finnes i dag hovedsakelig i 2 versjoner; JUnit4 og JUnit 5. I de påfølgende avsnittene skal vi se hvordan vi setter opp våre Maven-prosjekt for begge versjonene.
Men først to ord om Surefire.
Surefire plugin
Det er en egen plugin som er ansvarlig for å håndtere test-fasen i Maven livssyklusen. Dette er maven-surefire-plugin fra org.apache.maven. Default versjonen som kommer med Maven er v2.12.4.
Surefire-plugin'en er selve test-riggen for å håndtere test-fasen, men ikke selve test-motoren (engine). Surefire støtter flere test-motorer som JUnit, TestNG, POJO med flere. Så skal vi få kjørt testene våre, må vi legge til en avhengighet (dependency) til den test-motoren vi ønsker å bruke i vårt prosjekt.
Vi bruker som regel JUnit, og da enten i versjon 4 eller 5.
JUnit 4
Default versjonen av Surefire-plugin støtter JUnit4. Det er derfor tilstrekkelig å legge til avhengighet til JUnit4-motoren i <dependencies>-seksjonen i pom-filen som følger:
<dependencies> ... <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> ... </dependencies>
JUnit 5
Med JUnit 5 må vi bruke en nyere versjon av Surefire enn den som medfølger Maven by default. Siste versjon av Surefire (pr des 2022) er versjon 3.0.0-M7. Vi må derfor både definere den nyere versjonen av Surefire og legge til avhengighet (dependency) til JUnit5 i pom-filen vår:
<dependencies> ... <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.9.2</version> <scope>test</scope> </dependency> ... </dependencies> <build> ... <plugins> ... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.5.2</version> </plugin> ... </plugins> ... </build>
Kjørbar JAR-fil
Når du bygger et Java-prosjekt med Maven (livssyklusen "package" eller senere) pakker Maven alle de kompilerte .class-filene i en JAR-fil. En JAR-fil er egentlig en ZIP-fil, som du kan pakke ut med standard unzip (må da endre filendingen fra .jar til .zip).
Det er mulig å kjøre programmet ditt ved å dobbeltklikke på JAR-filen fra filutforskeren din, forutsatt at:
- Applikasjonen din har et grafisk brukergrensesnitt (f.eks. ved bruka v Swing eller JavaFX)
- JAR-filen inneholder en fil kalt MANIFEST.MF. Denne filen skal minimum inneholde det fulle navnet til klassen som inneholder main()-metoden, slik at Java kjøresystemet vet hvilken main()-metode som skal kalles for å starte programmet ditt.
Maven plugin'en som har ansvaret for å pakke JAR-filen heter maven-jar-plugin. Denne modulen kan automatisk opprette MANIFEST.MF-filen for deg, og pakke den inn i JAR-filen, men da må vi fortelle hvilken klasse main() ligger i. Dette gjør vi på følgende måte:
<build>
....
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<!-- add the full name to your class containing the main()-method -->
<mainClass>no.ntnu.idatx2001.calculator.Calculator</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
...
</plugins>
...
</build>
Plugin validation issues WARNING
Dette er en Warning i forhold til den fremtidige v4.0 av Maven som er like rundt hjørnet. Advarselen sier at det kan være plugins som ikke vil fungere under Maven v4.0. Denne advarselen er slått av i v3.9.4 og senere av Maven. Jetbrains har per våren 2023 v3.9.2:
Løsning: Endre prosjektet til å bruke Maven installert på maskinen din (dersom den versjonen er nyere). Du sjekker versjon med å skrive mvn --version i kommando-vinduet/terminal:
Gå til Settings i IntelliJ:
..og i feltet "Maven home path:", velger du versjonen som er installert på maskinen (ser annerledes ut i Windows).
Problemer med å kjøre mvn javafx:run via terminalen på Mac
mvn javafx:run
Assertion failure in -[_NSTrackingAreaAKViewHelper removeTrackingRect:], _NSTrackingAreaAKManager.m:1602 2023-03-14 15:34:44.725 java[19104:296342] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '0x0 is an invalid NSTrackingRectTag. Common possible reasons for this are: 1. already removed this trackingRectTag, 2. Truncated the NSTrackingRectTag to 32bit at some point.'
Åpne en terminal og kjør
/usr/libexec/java_home -V. Kommandoen lister opp alle Java-versjonene du har installert.Hvis lista ikke viser en oppføring for versjon 21 må du først .
cd ~ echo "export JAVA_HOME=$(/usr/libexec/java_home -v 21)" > .mavenrc
mvn javafx:run
Nyttige ressurser relatert til Maven
Her er noen nyttige ressurser og tutorials relatert til Maven:
- En god introduksjon til hvordan lage en JAR-fil fra Maven prosjekt som kan kjøres fra kommmandolinja med java -jar...osv: https://www.sohamkamani.com/java/cli-app-with-maven/





