I’m sick of Java’s low abstraction level which implies lots of coding overhead/boilerplate, so I’ve just started looking at Scala. While the language is definitely appealing, setting up my tool chain was not such a pleasant ride because the information I needed was dispersed across many web pages and well hidden between obsoleted or misleading information. This post shows what I did to succeed so you can use it as a guide line.
The first thing I had to learn the hard way is the different approach to compatibility: In the Java ecosystem, everybody seems to care a lot about binary compatibility, so I am accustomed to add the latest version of any component to my tool set and there are hardly any problems with that. That’s certainly a good thing.
In the Scala ecosystem however, things are a bit different: The language is still evolving fast and while being very powerful, it doesn’t seem to be so mature yet that compatibility is maintained across releases. Here are some examples:
- The Scala plugin for NetBeans works fine with Scala 2.8.1, but fails to do code completion for Scala 2.9.1.
- Releases of specs, a Behavior-Driven-Design framework, need to match a particular Scala release. Otherwise you’ll see error messages when compiling code.
So my usual habit of just adding the latest version of any component to my tool set clearly doesn’t work here, but after some exploration, I figured out the following procedure.
Setup Scala 2.8.1
You can download Scala 2.8.1 at http://www.scala-lang.org/node/165. For Windows, get the ZIP file, for Unix/Linux/Mac OS X, get any other archive file. Extract the archive file to any installation directory you like.
Once you’ve extracted the archive file, make sure to set the environment variable SCALA_HOME
to the installation
directory and setup the environment variable PATH
to include $SCALA_HOME/bin
on Unix/Linux/Mac OS X or
%SCALA_HOME%bin
on Windows.
The first benefit of this is that the NetBeans Scala plugin will discover the Scala platform and so you don’t need to set it up by using the NetBeans Scala Platform Manager. For me, the manager dialog didn’t properly recognize the Scala platform, so it was the only choice I had anyway.
The second benefit is that now you can do…
sbaz install scala-devel-docs
… in order to get a local copy of the Scala API documentation.
Once installed, you’ll find it in $SCALA_HOME/doc/scala-devel-docs
.
Setup NetBeans with Scala 2.8.* Plugin
You can download NetBeans 7.0.1 at http://netbeans.org/downloads/index.html
or check for updates within the IDE (menu Help -> Check For Updates
).
Follow the standard install procedure.
You can download the Scala 2.8.* plugin for NetBeans at
http://plugins.netbeans.org/plugin/36598/nbscala-2-8-x.
Extract the ZIP file anywhere and run the Plugins Manager (menu Tools -> Plugins
).
Select the tab Downloaded
and click on Add Plugins...
.
Navigate to the directory with the extracted NBM files and select all NBM files at once.
Once returned to the Plugins Manager, click on Install
and follow the standard procedure.
If you don’t want to use Maven, that’s it.
Now you can use the Ant based project templates that ship with the Scala plugin by selecting
File -> New Project... -> Scala -> ...
Setup Maven Archetype
To my delight, Scala is a first class citizen of the Maven ecosystem. There’s a maven-scala-plugin to run the compiler and the Scala library can get added like any other dependency. This allows to gradually introduce Scala into any existing Java project and to build a mixed Java/Scala application or library outside an IDE, and even without a need to install a Scala SDK!
To start a new Scala project with Maven, there’s a Maven archetype with the following coordinates:
<dependency>
<groupId>org.scala-tools.archetypes</groupId>
<artifactId>scala-archetype-simple</artifactId>
<version>1.3</version>
</dependency>
Within NetBeans, you can use File -> New Project... -> Maven -> Project from Archetype
in order to select an
archetype.
For me, none of the catalogs had the latest version (latest was 1.2), so I had to click Add...
in order to install the
archetype manually.
Once added, you can select this archetype and follow the standard procedure to create a new Scala project.
When you do this, you may get a pom.xml
file which looks like this:
<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/maven-v4_0_0.xsd>
<modelVersion>4.0.0</modelVersion>
<groupId>de.schlichtherle</groupId>
<artifactId>mavenproject1</artifactId>
<version>1.0-SNAPSHOT</version>
<name>${project.artifactId}</name>
<description>My wonderfull scala app</description>
<inceptionYear>2010</inceptionYear>
<licenses>
<license>
<name>My License</name>
<url>http://....</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
<maven.compiler.source>1.5</maven.compiler.source>
<maven.compiler.target>1.5</maven.compiler.target>
<encoding>UTF-8</encoding>
<scala.version>2.8.0</scala.version>
</properties>
<!--
<repositories>
<repository>
<id>scala-tools.org</id>
<name>Scala-Tools Maven2 Repository</name>
<url>http://scala-tools.org/repo-releases</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>scala-tools.org</id>
<name>Scala-Tools Maven2 Repository</name>
<url>http://scala-tools.org/repo-releases</url>
</pluginRepository>
</pluginRepositories>
-->
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.scala-tools.testing</groupId>
<artifactId>specs_${scala.version}</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.15.0</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<args>
<arg>-make:transitive</arg>
<arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.6</version>
<configuration>
<useFile>false</useFile>
<disableXmlReport>true</disableXmlReport>
<!-- If you have classpath issue like NoDefClassError,... -->
<!-- useManifestOnlyJar>false</useManifestOnlyJar -->
<includes>
<include>**/*Test.*</include>
<include>**/*Suite.*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
This will work, although there are some issues:
- The versions are obsolete and do not match the desired Scala platform, which is 2.8.1.
- The configuration of the maven-surefire-plugin ignores
samples.MapSpec
and disables the NetBeans IDE to pick-up the test results. - The class
samples.MapSpec
in the filesamples.scalatest.scala
misses the annotation@RunWith(classOf[JUnitRunner])
.
After fixing these issues, the pom.xml
file should look like this:
<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/maven-v4_0_0.xsd>
<modelVersion>4.0.0</modelVersion>
<groupId>de.schlichtherle</groupId>
<artifactId>mavenproject2</artifactId>
<version>1.0-SNAPSHOT</version>
<name>${project.artifactId}</name>
<properties>
<maven.compiler.source>1.5</maven.compiler.source>
<maven.compiler.target>1.5</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<scala.version>2.8.1</scala.version>
</properties>
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.scala-tools.testing</groupId>
<artifactId>specs_${scala.version}</artifactId>
<version>1.6.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.15.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<args>
<arg>-make:transitive</arg>
<arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<includes>
<include>**/*Spec.*</include>
<include>**/*Suite.*</include>
<include>**/*Test.*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
That’s it!