Build a mixed Scala 2.8/Java application from scratch with Maven

In this tutorial I will show you how to build an application by Maven that consists of Java and Scala source files. The project automatically uses the latest Scala 2.8-Snapshot until it’s released (Maven will look for the latest version of the Scala language each time you build it).
We will setup the project to use cross-compiling, so the java-classes can access Scala-classes and vice versa.

The good thing about maven projects is that you don’t need an IDE to start a project, thus remaining independent from certain IDE-features. In my next article, i will show how to configure eclipse to open the maven project. But for now i’ll show how to create the project from command line only.

If you’re impatient and just want to see the resulting pom.xml, you can also download the complete source:
Complete maven project

I’m using the following libraries/tools:

  • Java 1.6.0.18 (32 Bit)
  • Maven 2.2.1

You don’t need the scala-compiler/library, as maven will automatically download the needed files. I’m assuming that you already set up all necessary environment variables (M2_HOME, JAVA_HOME, M2_REPO) and path-variables (if not, google around – it’s easy).
To startup the project, we are creating a simple scala-archetyped-maven application, which creates a minimal pom.xml to start with. Before switching to eclipse, we will setup the project on the command line. On the CL, type

mvn archetype:generate

From the archetype list, Choose 30: internal -> scala-archetype-simple (A simple scala project). Choose your groupId for the app and an artifactId, the remaining questions can be answered by just clicking enter, using the default values. My settings:

Define value for groupId: : de.mackaz
Define value for artifactId: : tutorial1
Define value for version:  1.0-SNAPSHOT: :
Define value for package:  de.mackaz: :
Confirm properties configuration:
groupId: de.mackaz
artifactId: tutorial1
version: 1.0-SNAPSHOT
package: de.mackaz
Y: :

Now maven creates a subfolder named like the artifactId (in my case scalajavatut).
Switch to that folder and compile the project by typing

mvn compile

Maven will download all necessary libraries, and you should see a “BUILD SUCCESSFUL” in the end.

Now we’ll change the scala language version, as the archetype is built on 2.7.7. Open the pom.xml with your favourite text editor, change the line

<scala.version>2.7.0</scala.version>

to

<scala.version>2.8.0-SNAPSHOT</scala.version>

We also need to add the Scala snapshot-repository, where Scala 2.8 is located. Add this to your pom.xml:

<repositories>
   (...)
   <!-- Scala 2.8 Latest -->
   <repository>
      <id>scala-tools.org.snapshots</id>
      <name>Scala Tools Maven2 Repository</name>
      <url>http://scala-tools.org/repo-snapshots</url>
      <snapshots />
   </repository>
</repositories>

Now we will change the maven-scala-plugin to enable java/scala crosscompiling. In your pom.xml, find the maven-scala-plugin, located in build/plugins/plugin. Replace the current settings with the following snippet.

<plugin>
  <groupId>org.scala-tools</groupId>
  <artifactId>maven-scala-plugin</artifactId>
  <version>2.13.1</version>
  <executions>
    <execution>
      <id>compile</id>
      <goals><goal>compile</goal></goals>
      <phase>compile</phase>
    </execution>
    <execution>
      <id>test-compile</id>
      <goals><goal>testCompile</goal></goals>
      <phase>test-compile</phase>
    </execution>
    <execution>
      <phase>process-resources</phase>
      <goals><goal>compile</goal></goals>
    </execution>
  </executions>
  <configuration>
    <scalaVersion>${scala.version}</scalaVersion>
    <args>
      <arg>-target:jvm-1.5</arg>
      <!-- to support mix java/scala only -->
      <arg>-make:transitivenocp</arg>
      <arg>-dependencyfile</arg>
      <arg>${project.build.directory}/.scala_dependencies</arg>
    </args>
  </configuration>
</plugin>

Now we can remove the following lines just below <build>, as the compiler already knows where to find the source files (especially because we can’t define multiple source directories in this way, but we need that when we later add a java-src-folder):

<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>

The simple scala maven archetype also created a behavior driven test using the Scala Specs library. Because we’re using Scala 2.8, we need the specs library version that’s build against Scala 2.8, so we need to change the version of the Scala Specs Dependency, currently 1.2.5, to the corresponding version. During the time of writing, the current version is 1.6.1-2.8.0.Beta1-RC1. It should look like this:

<!-- Specs (Behavior Driven Testing through JUnit) -->
<dependency>
 <groupId>org.scala-tools.testing</groupId>
 <artifactId>specs</artifactId>
 <version>1.6.1-2.8.0.Beta1-RC1</version>
 <scope>test</scope>
</dependency>

Now try to re-compile the project by running

mvn clean compile

which should result in “BUILD SUCCESSFUL” again. You can also run the junit/specs-tests now with the command

mvn test

resulting in 2 – hopefully ;) – successful tests.

To test the scala-java “communication”, it would be nice to start the scala-app from the command line by a maven task. Therefore you need to tell maven which class is the main-class. In my case, maven generated an App.scala in the package de.mackaz, so my main class is de.mackaz.App.
Add the following launcher to the configuration-section of the maven-scala-plugin (build/plugins/plugin/maven-scala-plugin), just before the args-settings

(...)
<configuration>
   <scalaVersion>${scala.version}</scalaVersion>
   <launchers>
      <launcher>
         <id>myLauncher</id>
         <mainClass>de.mackaz.App</mainClass>
      </launcher>
   </launchers>
   (...)
</configuration>

Now you can run your app with the command

mvn scala:run

which should result in a “Hello world” on your console (unless you changed the generated App.scala).

Now that the project successfully compiles and the tests run through, we can add a java class to test cross-compiling.
In the folder ${artifactId}/src/main, where the scala sources recide, we add a directory namend java, which contains all our java sources. There we add a java class, my class is called HelloScala.java. Now my project directory looks like this:

+-scalajavatut/
  +-pom.xml
  +-src/
  | +-main/
  | | +-java/
  | | | +-de/
  | | |   +-mackaz/
  | | |     +-HelloScala.java
  | | +-scala/
  | |   +-de/
  | |     +-mackaz/
  | |       +-App.scala
  | +-test/
  |   +-scala/
  |     +-de/
  |       +-mackaz/
  |         +-AppTest.scala
  |         +-MySpec.scala

To show how nice scala and java communicate, i altered the maven-generated App.scala, which now looks like this:
Artikel

package de.mackaz

object App {
  // call java class
  def main(args: Array[String]) = HelloScala.helloScala

  def helloJava():String = "Hello from Scala!"
}

My java file (HelloScala.java) looks like this:

package de.mackaz;

public class HelloScala {
  public static void helloScala() {
    System.out.println("Hello from Java");
    // call scala class
    System.out.println("Scala says: " + App.helloJava());
  }
}

Now your can run the project by typing

mvn scala:run

and at the end of the output you should see

[INFO] launcher 'myLauncher' selected => de.mackaz.App
Hello from Java
Scala says: Hello from Scala!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7 seconds
[INFO] Finished at: Wed Mar 24 18:14:22 CET 2010
[INFO] Final Memory: 14M/33M
[INFO] ------------------------------------------------------------------------

And that’s it! With this maven project, you are ready to build a large java/scala application, where you are free to mix scala and java.
In the next article, i will show you how to setup eclipse to open this project.

[EDIT]
If you liked (or disliked!) the tutorial, feel free to leave a comment. Questions are also welcome. Thank you!

This entry was posted in General and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

11 Comments

  1. Posted 25. March 2010 at 22:37 | Permalink

    Can’t say Thank you enough ! I’ve been fighting a lot with Specs these last weeks to get it to work instead of getting the error “should is not part of String …”.

    The Java/Scala integration too is most welcome !

    Cheers.

  2. Posted 27. March 2010 at 03:50 | Permalink

    Fantastic! It worked like a charm! Java/Scala integration is a evolution to java language.
    Thanks!

  3. David Bernard
    Posted 5. April 2010 at 13:51 | Permalink

    you could remove
    ${scala.version}
    from the configuration, as the plugin retreive the scala-version from the dependency. you have to explicitly provide it if you’re in a parent project where you configure the plugin and don’t have dependency to scala-library (or if the detection failed).

    If your java code doesn’t depend of the scala code the default configuration is enough (as java code is compiled before scala code by default)

    settings src/main/scala is to help IDE know where is the source code for single directory source code.

    Thanks for your article.

    /davidB (lead of maven-scala-plugin)

  4. Soma
    Posted 5. April 2010 at 15:02 | Permalink

    Thanks for the walk-through

  5. Pawan
    Posted 13. April 2010 at 12:19 | Permalink

    Great post man…I have used this information to mix and match earlier developed T5 java code and new features developed in scala…great going. Looking forward for more such helpful articles.

  6. Pawan
    Posted 13. April 2010 at 12:23 | Permalink

    2.8.0-SNAPSHOT version was not working but 2.8.0.Beta1 worked. Any specific reason for this?

  7. ingo
    Posted 13. April 2010 at 12:50 | Permalink

    @Pawan: what exactly was not working?
    Maybe there was a “bad” snapshot in the repo the time you tried – in my example maven always downloads the latest nightly build, which is NOT a stable build. So there can be some issues from time to time.

    I’m currently waiting for the first Scala 2.8-Release Candidate, as i heard it’ll be released during in a few days. It’ll surely fix some issues like this.

  8. manojo
    Posted 1. June 2010 at 16:04 | Permalink

    Hi,

    thanks for the tutorial. I do have some issues however with the following error message :

    “annotations are not supported in -source 1.3 (use -source 5 or higher to enable annotations)”. I have tried specifying the and to 1.5, but in vain. Would you know what I could do ?

    Cheers,
    manojo

  9. ingo
    Posted 1. June 2010 at 17:12 | Permalink

    http://lmgtfy.com/?q=annotations+are+not+supported+source+1.3

    I guess the first result is the solution to your problem ;)

  10. manojo
    Posted 1. June 2010 at 22:56 | Permalink

    Wouldn’t have asked before trying :-) . Have a project not using Scala working perfectly fine with Java 1.6, so I thought that something in the pom.xml could be changed.

  11. Tomas Herman
    Posted 17. June 2010 at 18:26 | Permalink

    <3 thanks for this tutorial, i was trying to get scala work in intellij maven plugin for like 3 hours and i wasnt able to google out that thingy

2 Trackbacks

  1. [...] writeCode « Build a mixed Scala 2.8/Java application from scratch with Maven [...]

  2. [...] Scala + Java + Maven – no problem [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>