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!
11 Comments
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.
Fantastic! It worked like a charm! Java/Scala integration is a evolution to java language.
Thanks!
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)
Thanks for the walk-through
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.
2.8.0-SNAPSHOT version was not working but 2.8.0.Beta1 worked. Any specific reason for this?
@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.
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
http://lmgtfy.com/?q=annotations+are+not+supported+source+1.3
I guess the first result is the solution to your problem
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.
<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
[...] writeCode « Build a mixed Scala 2.8/Java application from scratch with Maven [...]
[...] Scala + Java + Maven – no problem [...]