Scala and Maven
Chapter 3
3.1 Introduction
Scala., haven't used it yet? Not surprised, few have, but everyone seems to be all atwitter about how amazing and transformative it is, so maybe you should take a look? If you are interested in Scala and you already use Maven, you are in luck. The Scala community has spent a great deal of effort making sure that the Maven integration is first-class. This chapter will introduce you to Scala by way of Maven.
3.2. Running an Inline Scala Script in a Maven Build
3.2.1. Task
You need to execute an inline Scala script as a part of your Maven build.
3.2.2. Action
Configure the script goal of the maven-scala-plugin, and pass a Scala script to the script configuration parameter.
Example 3.1. Executing an Inline Scala Script with the Maven Scala Plugin
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mcookbook</groupId>
<artifactId>scala-script</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>scala-script</name>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.scalaforge</groupId>
<artifactId>scalax</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.10.1</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>script</goal>
</goals>
<configuration>
<keepGeneratedScript>true</keepGeneratedScript>
<script>
>!--[CDATA[ import java.io.{File, PrintWriter, FileWriter}; import scalax.io.FileExtras; import scala.collection.mutable.HashSet; val outputDir = project.getBuild().getOutputDirectory(); val depsFile = new FileExtras( new File( outputDir, "deps.txt" ) ) val pw = depsFile.printWriter val depSet = new HashSet[String] for( d >- project.getDependencies() ) { depSet += d.getGroupId + ":" + d.getArtifactId + ":" + d.getVersion } pw.writeLines( depSet.toSeq ) ]]--> </script>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>scala-tools</id>
<url>http://scala-tools.org/repo-releases/</url>
</repository>
</repositories>
</project>
If you run mvn package, the script goal will be executed during the prepare-package phase.
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building scala-script
[INFO] task-segment: [package]
[INFO] ------------------------------------------------------------------------
...
[INFO] [scala:script {execution: scala-magic}]
[INFO] Checking for multiple versions of scala
...
[INFO] BUILD SUCCESSFUL
After this script executes, there will be a file named deps.txt in ${basedir}/target/classes containing a list of the project's direct dependencies.
org.apache.maven:maven-model:2.2.0
org.scala-tools:maven-scala-plugin:2.10.1
org.scala-lang:scala-library:2.7.3
3.2.3. Detail
Example 3.1, “Executing an Inline Scala Script with the Maven Scala Plugin” includes the scala-tools repository and the dependency on version 0.1 of scalax to gain access to the FileExtras class which is used to augment the methods available on a File object. The FileHelper wraps the File object, and adds the method writeLines() which is used to write a Sequence of String objects. This Sequence of String objects is stored in a HashSet which is populated in a for loop that loops over all of the project's dependencies.
The other piece of configuration in this example is the keepGeneratedScript option. This option tells the Maven Scala plugin to retain the temporary Scala source which is generated by the plugin. The Scala plugin takes the inline Scala source code and creates a temporary script in ${basedir}/target/.scalaScriptGen/embeddedScript_1.scala. If keepGeneratedScript is set to false, the Maven Scala plugin will delete this file when it is finished executing the script. If keepGeneratedScript is set to true, the Scala plugin will retain this source file. Let's take a look at the embeddedScript_1.scala file:
class embeddedScript_1(project:org.scala_tools.maven.model.MavenProjectAdapter,log:org .apache.maven.plugin.logging.Log) {
import java.io.{File, PrintWriter, FileWriter};
import scalax.io.FileExtras;
import scala.collection.mutable.HashSet;
val outputDir = project.getBuild().getOutputDirectory();
val depsFile = new FileExtras( new File( outputDir, "deps.txt" ) )
val pw = depsFile.printWriter
val depSet = new HashSet[String]
for( d <- project.getDependencies() ) {
depSet += d.getGroupId + ":" + d.getArtifactId + ":" + d.getVersion
}
pw.writeLines( depSet.toSeq )
}
Notice that the class includes to argument project:org.scala_tools.maven.model.MavenProjectAdapter and log:org.apache.maven.plugin.logging.Log. The project argument gives you access to the Maven project object model and the log argument gives you access to the logging facilities of Maven. The project and log objects are only available when the Maven Scala plugin is available on the classpath, this is why you see the Maven Scala plugin declared both as a dependency of the project under dependencies in Example 3.1, “Executing an Inline Scala Script with the Maven Scala Plugin” and as a plugin.
3.3. Running an External Scala Script in a Maven Build
3.3.1. Task
You need to execute an external Scala script as a part of your Maven build.
3.3.2. Action
Similar to Example 3.1, “Executing an Inline Scala Script with the Maven Scala Plugin”, configure the script goal of the Maven Scala plugin and specify a Scala script in the scriptFile configuration parameter.
Example 3.2. Configuring the Maven Scala Plugn Script Goal to Execute an External Script
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mcookbook</groupId>
<artifactId>scala-script-ex</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>scala-script-ex</name>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.scalaforge</groupId>
<artifactId>scalax</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.10.1</version>
<executions>
<execution>
<id>scala-magic</id>
<phase>prepare-package</phase>
<goals>
<goal>script</goal>
</goals>
<configuration>
<keepGeneratedScript>true</keepGeneratedScript>
<scriptFile>${basedir}/src/main/scala/CreateDeps.scala</scriptFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>scala-tools</id>
<url>http://scala-tools.org/repo-releases/</url>
</repository>
</repositories>
</project>
The script that this build will execute is the same Scala script that was executed in Example 3.1, “Executing an Inline Scala Script with the Maven Scala Plugin”. In this example, the script is stored in an external file in ${basedir]/src/main/scala, and in Example 3.1, “Executing an Inline Scala Script with the Maven Scala Plugin”, the script was listed inline in the project's POM.
Example 3.3. The CreateDeps.scala Script
import scalax.io.FileExtras;
import scala.collection.mutable.HashSet;
val outputDir = project.getBuild().getOutputDirectory();
val depsFile = new FileExtras( new File( outputDir, "deps.txt" ) );
val pw = depsFile.printWriter;
val depSet = new HashSet[String];
for( d <- project.getDependencies() ) {
depSet += d.getGroupId + ":" + d.getArtifactId + ":" + d.getVersion;
}
pw.writeLines( depSet.toSeq );
Just like the example in Section 3.2, “Running an Inline Scala Script in a Maven Build”, this script creates a file named deps.txt in ${basedir}/target/classes which contains a list of the project's dependencies.
org.apache.maven:maven-model:2.2.0
org.scala-tools:maven-scala-plugin:2.10.1
org.scala-lang:scala-library:2.7.3
3.3.3. Detail
There is very little difference between the example from Section 3.2, “Running an Inline Scala Script in a Maven Build” and the example in this section other than the location of the Scala script. If you look in ${basedir}/target/.scalaScriptGen you can see that the Scala plugin creates a file named CreateDeps_1.scala that contains a class named CreateDeps_1.