Scala mit Maven kompilieren
Um Scala- und Java-Code gleichzeitig mit Maven zu kompilieren, verwende ich das scala-maven-plugin, in dessen Dokumentation sich bereits für die meisten Fäll sehr gute Beispiele finden. Die Ordnerstruktur muss dabei wie folgt aussehen:
demo
├── pom.xml
└── src
├── main
│ ├── java
│ └── scala
└── test
├── java
└── scala
Ganz am Anfang der pom.xml
muss direkt in den properties
die Eigenschaft project.build.sourceEncoding
auf UTF-8
gesetzt werden, um seltsame Warnungen bzgl. des Encodings zu vermeiden.
In der Konfiguration des scala-maven-plugins
kann als Argument -feature
angegeben werden, damit Scala detailliere Warnungen ausgibt und nicht nur etwas wenig hilfreich mitteilt, dass Warnungen vorhanden sind. Ebenfalls in dieser Konfiguration kann als recompileMode
der Wert incremental
angegeben werden, was bei mir allerdings nie so ganz den gewünschten Effekt hat, da zwar durchaus Scala-Klassen inkrementell kompiliert werden, nach meinem subjektiven Eindruck am Ende aber doch immer alle Scala-Klassen kompiliert werden.
Im maven-compiler-plugin
muss die Java-Version auf 1.7 (oder 1.6) gesetzt werden, damit Maven gegen die korrekte Java-Version kompiliert.
Als Abhängigkeit muss auf jeden Fall die scala-library
angegeben werden. An der Version der scala-library
erkennt das scala-maven-plugin
auch direkt, gegen welche Scala-Version der Code kompiliert werden soll. In den meisten Fällen ist es darüber hinaus sinnvoll junit
als Abhängigkeit für den scope
test
anzugeben.
<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>
<!-- options of the project -->
<groupId>de.mlte.maven</groupId>
<artifactId>simple-demo</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>simple-demo</name>
<!-- set encoding of this project to UTF-8 to avoid warnings -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- set up build process of this project -->
<build>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.1.6</version>
<!--
The scala plugin detects the version of the scala library in the dependents and
uses that version to compile the scala code
-->
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- enable detailed feature warnings of the scala compiler by setting its command line parameter -feature -->
<args>
<arg>-feature</arg>
</args>
<!-- enable incremental compilation mode for faster compiling -->
<recompileMode>incremental</recompileMode>
<!-- use zink server as scalac provider -->
<!-- <useZincServer>true</useZincServer> -->
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<!-- set the version of the java compile (source) and the target JVM -->
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<!-- set up dependencies of this project -->
<dependencies>
<!-- scala-library is needed to run scala code in JVM -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.10.3</version>
</dependency>
<!-- junit is needed, because our test cases use JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Darüber hinaus kann das maven-dependency-plugin verwendet werden, damit beim Kommando mvn package
alle Abhängigkeiten als jar
-Dateien in den Ordner target/lib
kopiert werden. Bei Verwendung der Maven-Eclipse-Integration M2Eführt dieses Plugin allerdings zu Problemen, da es von M2E nicht korrekt erkannt wird. Um die entsprechenden Warnungen zu unterdrücken, kann im pluginManagement
das Plugin lifecycle-mapping
hinzugefügt werden, in dessen pluginExecutionFilter
das Ziel copy-dependencies
des maven-dependency-plugin
vom Import in das Eclipse-Projekt ausgeschlossen werden kann.
Ebenfalls sehr nützlich ist das maven-assembly-plugin, mit dem eine jar
-Datei erzeugt werden kann, in der alle verwendeten Abhängigkeiten eingebunden sind. Auf diese Weise muss nur eine Datei weitergegeben werden, die dann mit java -jar
gestartet werden kann, auch wenn es sich um ein Scala-Projekt handelt. Der Nachteil liegt natürlich in der Dateigröße dieser jar
-Datei, die dann die scala-library
und alle weiteren Abhängigkeiten enthält. Damit das alles so funktioniert, muss in der configuration
dieses Plugins die mainClass
für das manifest
des archive
also der jar
-Datei angegeben werden. Statt mvn package
wird die jar-with-dependencies
dann über mvn assembly:single
erzeugt.
<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>
<!-- options of the project -->
<groupId>de.mlte.maven</groupId>
<artifactId>demo</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>demo</name>
<!-- set encoding of this project to UTF-8 to avoid warnings -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- set up build process of this project -->
<build>
<pluginManagement>
<plugins>
<!-- ignore/execute plugin execution in m2e -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<!-- ignore maven-dependency-plugin's copy-dependency goal -->
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<versionRange>[1.0.0,)</versionRange>
<goals>
<goal>copy-dependencies</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.1.6</version>
<!--
The scala plugin detects the version of the scala library in the dependents and
uses that version to compile the scala code
-->
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- enable detailed feature warnings of the scala compiler by setting its command line parameter -feature -->
<args>
<arg>-feature</arg>
</args>
<!-- enable incremental compilation mode for faster compiling -->
<recompileMode>incremental</recompileMode>
<!-- use zink server as scalac provider -->
<!-- <useZincServer>true</useZincServer> -->
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<!-- set the version of the java compile (source) and the target JVM -->
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- mvn assembly:single generates a single .jar file containing all dependencies.-->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>de.mlte.maven.demo.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
<!-- set up dependencies of this project -->
<dependencies>
<!-- scala-library is needed to run scala code in JVM -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.10.3</version>
</dependency>
<!-- junit is needed, because our test cases use JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>