Sep 132011
 

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:

GroupId: org.scala-tools.archetypes
ArtifactId: scala-archetype-simple
Version: 1.3

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 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 a number of problems:

  1. The versions are obsolete and do not match the desired Scala platform, which is 2.8.1.
  2. The configuration of the maven-surefire-plugin ignores samples.MapSpec and disables the NetBeans IDE to pick-up the test results.
  3. The class samples.MapSpec in the file samples.scalatest.scala misses the annotation @RunWith(classOf[JUnitRunner]).

After fixing these issues, the pom.xml 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!

Sorry, the comment form is closed at this time.