Using Scala Code from Java

by Stephane Micheloud, August 2009

[Home]
[Back]

In this article we present several program samples combining Scala code with Java code.

Companion objects

A companion module (or companion object) of a Scala class is an object which has the same name as the class and is defined in the same scope and compilation unit. Conversely, the class is called the companion class of the module (see SLS 5.4).

// File companion.scala
class Companion {
  def hello() { println("Hello (class)") } // [1]
}
object Companion {
  def hallo() { println("Hallo (object)") } // [2]
  def hello() { println("Hello (object)") } // [3]
}

Calling a Scala method from Java is straightforward (cases [1] and [2]) unless it is defined both in a class and in its companion object (case [3]):

// File TestCompanion.java
public class TestCompanion {
    public static void main(String[] args) {
        new Companion().hello(); // [1]
        Companion.hallo();  // [2] (static)
        Companion$.MODULE$.hello();  // [3] (hidden static)
    }
}

Writing Java code for case [3] thus requires some knowledge of the compiler internals.

Note: Do not forget to add the standard Scala library to your classpath when invoking the javac/java command line tools.

~$ scalac companion.scala
~$ javac -cp $SCALA_HOME/lib/scala-library.jar:. TestCompanion.java
~$ java -cp $SCALA_HOME/lib/scala-library.jar:. TestCompanion
Hello (class)
Hallo (object)
Hello (object)

Member acessors

// File accessor.scala
package example
object Accessor {
  var size = 0
  def main(args: Array[String]) {
    size = 1
    println("size="+size)
    size_=(2)
    println("size="+size)
  }
}

// File TestAccessor.java
import static example.Accessor.*;
public class TestAcessor {
    public static void main(String[] args) {
        size_$eq(1);
        System.out.println("size="+size());
        size_$eq(2);
        System.out.println("size="+size());
    }
}

Function literals

// File anonfun.scala
package example
object Anonfun {
  var firstname = "John"
  def hello = (s: String) => s + firstname

  def main(args: Array[String]) {
    println(firstname)
    println(hello("Hello "))
    firstname = "Hans" // [2]
    println(hello("Hallo "))

    val ciao = hello
    println(ciao("Ciao "))
  }
}

// File TestAnonfun.java
import static example.Anonfun.*;
public class TestAnonfun {
    public static void main(String[] args) {
        System.out.println(firstname());
        System.out.println(hello().apply("Hello ")); // [1]
        firstname_$eq("Hans");
        System.out.println(hello().apply("Hallo "));

        scala.Function1<String, String> ciao = hello(); >// [2]
        System.out.println(ciao.apply("Ciao "));
    }
}

Note: Do not forget to add the standard Scala library to your classpath when invoking the javac/java command line tools.

~$ scalac anonfun.scala
~$ javac -cp $SCALA_HOME/lib/scala-library.jar:. TestAnonfun.java
~$ java -cp $SCALA_HOME/lib/scala-library.jar:. TestAnonfun
John
Hello John
Hallo Hans
Ciao Hans

Traits

A Scala trait with no method implementation is just an interface at the bytecode level and can thus be used in Java code like any other interface.

However, if a trait has method implementations (eg. method println(s: String) in the example below), then Java classes implementing that trait must provide concrete methods for abstract methods with no code and forwarder methods for abstract methods containing code.

// File trait.scala
trait Printable {
  def print(s: String)
  def println()
  def println(s: String) { print(s); println() }
}

Whenever a trait T provides method implementations the Scala compiler generates an abstract class T$class with static methods containing the implementation code.

// File TestTrait.java
class Hello implements Printable {
    public void print(String s) { System.out.println(s); }
    public void println() { System.out.println(); }
    public void println(String s) { Printable$class.println(this, s); }
}
public class TestTrait {
    public static void main(String[] args) {
        new Hello().println("Bob");
    }
}

Default arguments

Default arguments in Scala can be specified both for constructor and method parameters; their type must be assignment compatible with the given parameter type.

However you should better avoid them for methods and constructors you know they will be called from Java code (see pitfall example in the article Translating Java code to Scala).

// File defaultargs.scala
class Person(
  name: String,
  age: Int = -1,
  city: String = "unknown") {
  override def toString = name+" (age="+age+",city="+city+")"
  def setEmail(address: String = name+"@gmail.com") { /*..*/ }
}

object DefaultArgs extends App {
  val bob = new Person("Bob")
  bob.setEmail()
  println(bob)
  println(new Person("Bob", city="Lausanne"))
}

Specifying default arguments in Java requires to know both their declaration scope (constructor or method) and their position in the parameter list:

// File TestDefaultArgs.java
public class TestDefaultArgs {
    public static void main(String[] args) {
        Person bob =
            new Person("Bob", // [1]
                     Person.init$default$2(),
                     Person.init$default$3()));
        bob.setEmail(bob.setEmail$default$1()); // [2]
        System.out.println(
            new Person("Bob", // [3]
                       Person.init$default$2(),
                       "Lausanne"));
    }
}

Note: Since the Scala compiler doesn't generate Java annotations for preserving parameter names, you must add yourself a Java annotation in front of each constructor (resp. method) parameter (eg. @ScalaParameterName("name") in the example below) in order to be able to access their name from Java:

// File ScalaParameterName.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface ScalaParameterName {
    public String value();
}

class Person(
  @ScalaParameterName("name") name: String,
  @ScalaParameterName("age") age: Int = -1,
  @ScalaParameterName("city") city: String = "unknown") {
  override def toString = name+"(age="+age+",city="+city+")"
}

References

  1. The Scala Language Specification (SLS), Version 2.8
    Martin Odersky, November 2010

About the Author

Stephane's Picture
Stéphane Micheloud is a senior software engineer. He holds a Ph.D in computer science from EPFL and a M.Sc in computer science from ETHZ. At EPFL he worked on distributed programming and advanced compiler techniques and participated for over six years to the Scala project. Previously he was professor in computer science at HES-SO // Valais in Sierre, Switzerland.
[Top]

Other Articles