Integrating Scala components in a Java application

Scala is starting to be really popular, and there are many reasons why you might like to use it in your current projects. At akquinet we’re now using Scala inside Java applications to reduce the amount of written code and to benefit from Scala’s flexibility. However, integrating Java and Scala in the same application requires some tricks. Using Java classes in Scala is pretty straightforward; however, using Scala classes in Java is not.

Scala has several language features which cannot be directly mapped to Java, for example function types and traits. Here we will describe how these language features are compiled to Java byte code and how to access them from Java afterwards.

Unit and Any

Functions in Scala using the data types Unit or Any can be used in Java with the types void and Object respectively.

Scala special characters

Scala’s syntax is more relaxed than Java’s with regard to special characters. Consider for example the following code snippet where Scala mimicks properties:

class ScalaPerson(var _name: String) {
  def name = _name
  def name_= (value: String) {
    _name = value
  }
}

This class has two methods. The first method is called “name” and returns the value of the field _name. The second method is called “name_=” and takes one parameter to set the value of the field _name.
Unfortunately “=” is not a valid character for names in Java because it is used for assignments. Therefore the following Java code will cause a syntax error:

ScalaPerson sPerson = new ScalaPerson("Alice");
sPerson.name_=("Bob"); // this does not work

So how can you use the name_= method in Java? The Scala compiler takes care of this for us by replacing all special characters with valid characters. For example, the name_= method will be compiled to name_$eq which is a valid Java name. So coming back to our example, the following code will work:

ScalaPerson sPerson = new ScalaPerson("Alice");
sPerson.name_$eq("Bob"); // this works

Traits

Another useful language feature of Scala is traits. Traits correspond to Java interfaces but may have partial implementations. For example,
consider the following Scala trait:

trait ProgrammerTrait {
  def writingCode: Unit = {
    println("Hello World")
  }

  def debugging: Unit
}

Any Scala class using this trait must implement the method debugging, but will be able to call the method writingCode without implementing it itself, as it is inherited.
However, Java does not know traits but only understands either implements (for interfaces without an implementation) or extends (for a
super class, but may only extend one of these).

The Scala compiler translates a trait to a simple interface without implementation details, so the following Java interface should more or less produce the same bytecode as the Scala trait:

interface ProgrammerTrait {
  void writingCode();

  void debugging();
}

However in addition to this interface, the Scala compiler also creates a static method for each method the trait implements. The class containing these methods is called ProgrammerTrait$class. Back in Java, we need to do the following to correctly implement ProgrammerTrait:

public class JavaProgrammer implements ProgrammerTrait {
    public void coding() {
        ProgrammerTrait$class.coding(this);
    }

    public void debugging() {
        System.out.println("Looking for bugs");
    }
}

Function as Parameter

Scala also allows function types as parameters:

object StringFun {
  def echo = (s:String) => s
  def world = (s: String) => s + "world"

  def changeString(s: String, fun: String => String) = fun(s)
}

The changeString method applies the method given as the second argument to the first argument and returns the result. In Java, a call to changeString would look like this:

String hello = "Hello";
String changed1 = StringFun.changeString(hello, new StringFun$$anonfun$echo$1());
String changed2 = StringFun.changeString(hello, new StringFun$$anonfun$world$1());
System.out.println(changed1); // prints "Hello"
System.out.println(changed2); // Prints "Helloworld"

If you are wondering, the type of the second parameter is Function1. Function1 is a Scala trait that could potentially be implemented by a Java class. Scala has a function trait for several counts of parameters (up to over 20 parameters in the trait Function22).

Scala classes and objects

Another feature of Scala is the distinction between class and object. Classes in Scala correspond to their Java counterparts while objects are the Scala version of singletons. Methods and fields defined in objects can be accessed like static methods in Java.

A Scala class can have a corresponding object with the same name. Such an object is called a companion object to the class. Aside from providing a place for static methods, companion objects have full access to all fields and methods defined in its corresponding class.

For example, assume there is a companion object for our ScalaPerson class:

object ScalaPerson {
  def birthday = "01.01.1970"
  def name = "Alice"
}

The class ScalaPerson has three members: _name (private field), name_= (setter) and name (getter). The companion object has the members name (getter) and birthday (new method).
The methods of the object can be accessed directly, like static methods in Java, e.g. ScalaPerson.birthday().
However methods that exist in both the class and its companion object — in this case name (getter) — are accessed differently:

ScalaPerson sPerson = new ScalaPerson("Bob");
System.out.println(sPerson.name()); // prints Bob
System.out.println(ScalaPerson$.MODULE$.name()); // prints Alice
System.out.println(ScalaPerson.birthday()); // prints 01.01.1970
sPerson.birthday(); // syntax error because birthday is not a method of the class ScalaPerson

The getter name is part of both the Scala class and the Scala object. The one belonging to the companion object can be accessed via a static method in the class ScalaPerson$.MODULE$ and the one defined in an instance of class ScalaPerson as per usual via nameofinstance.name(). Methods which are only defined on the companion object (in this case birthday) are accessed directly via ScalaPerson.birthday().

Conclusion

This blog post has presented some of the tricks that will allow Java components to call Scala components. At akquinet, we’re now integrating Scala components into our Java applications. This integration allows us to benefit from Scala features without having to modify the Java components. You should now be ready to do the same.

3 thoughts on “Integrating Scala components in a Java application

  1. Hello everyone,

    i used the code on a Scala project, in eclipse and gave me this error:
    Description Resource Path Location Type
    Syntax error on token “name”, Identifier expected after this token AbstractAlgorithm.java /ScalaInterceptors/src/jecoli/algorithm/components/algorithm line 134 Java Problem

    Any ideia what is causing it?

    i am using this:

    package jecoli.algorithm.components.algorithm

    object ScalaPerson {
    def birthday = “01.01.1970”
    def name = “Alice”
    }

    and then i am calling in a java class, AbstractAlgorithm:
    ScalaPerson$.MODULE$.name();

    and gives that error…

  2. Good article, covering some fairly obscure but important aspects of Scala/Java integration.

    It should be noted that a trait that contains any val or var field definitions is more complicated. A trait never has its own instance, so it falls to the implementing class to define each trait instance field, its accessor method, and (if a var) its mutator method. For example, if we have:
    var x: Int = _
    in the trait, each implementing Java class will need:
    private int x;
    public int x() { return x; }
    public void x_$eq(int x) { this.x = x; }
    This applies to non-public fields defined within the Trait, too, but the method names become ickier [that’s a technical term].

    By the way, the trait has the expected accessor and mutator methods for each field declared in the interface and implemented within the trait’s “static class.” The trait’s static class simply forwards those calls to the methods in the implementing class:
    public static int x(ThisTrait self) { return self.x(); }
    public static void x_$eq(ThisTrait self, int val) { self.x_$eq(val); }

    Having fields in traits is a problem for pure Scala coding, too, because it means that the binary compatibility that we’re accustomed to doesn’t apply. If one or more fields in a trait changes, all implementing classes must be located and recompiled in order to properly implement the field(s).

    Nonetheless, the Cake Pattern does use a public val field within the trait. It’s just one field, and the field’s name and type match the name of the trait, so it’s not expected to vary with later releases.

    Typo: the Java code example at the end of the Traits section refers to the method name “coding” instead of “writingCode”.

Comments are closed.