Easy Pojos in Scala

A significant part of the lines of code in any enterprise Java application are devoted to plain old java objects (pojos) that carry data. Although they are simple, they represent a non-trivial effort in development and testing. And they make an application resistant to change because often a small change requires alteration of code in several places. Pojos written in Scala are so simple that the value of mixing Scala into Java development becomes worth the extra startup effort.

Java Example

Let’s illustrate this by considering an example pojo containing three fields; real-world applications often have large numbers of pojos and they often have large numbers of fields, but in this example we’ll keep it simple. This JavaBean style will be very familiar to most Java programmers.

public class PersonJ {
    private String name;
    private int age;
    private boolean male;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public boolean isMale() {
        return male;
    }

    public void setMale(boolean male) {
        this.male = male;
    }
}

Java has a widely-accepted encapsulation convention: it is considered bad form to expose publicly-accessible fields. We don’t like having public fields because we lose the option to change them later and use setters/getters instead. So the three fields are private and each has a getter and a setter. Had we written it with public fields, they would be referenced without parentheses, e.g. person.name. With getters, we have a getXxx name and empty parentheses, i.e. person.getName(). So it’s clear that converting from one form to the other is not a trivial amount of effort, not within PersonJ itself, but more importantly it’s difficult everywhere its fields are accessed.

Hence the need for the encapsulation convention that ensures the methods are there from the start in case we ever need them.

In the example, there are only three fields, but look how much code is needed. Even with IDE support, it represents a lot of work. We’re used to it, but that doesn’t mean it’s right and proper. It should become clear why later on.

Of course, we want all our code to be well tested, so we’ll need a corresponding test class. Here’s one in JUnit4 form.

import static org.junit.Assert.*;
import org.junit.Test;

public class PersonJTest {

    @Test
    public void testName() {
        final PersonJ p = new PersonJ();
        assertNull(p.getName());
        p.setName("John Smith");
        assertEquals("John Smith", p.getName());
    }

    @Test
    public void testAge() {
        final PersonJ p = new PersonJ();
        assertEquals(0, p.getAge());
        p.setAge(35);
        assertEquals(35, p.getAge());
    }

    @Test
    public void testMale() {
        final PersonJ a = new PersonJ();
        assertFalse(a.isMale());
        a.setMale(true);
        assertTrue(a.isMale());
        a.setMale(false);
        assertFalse(a.isMale());
    }
}

Scala Version

Compared with PersonJ above, the equivalent pojo in Scala is evidently very simple.

class Person1 {
    var name: String = _
    var age: Int = _
    var male: Boolean = _
}

The simplicity is important: if we’d had to write a pojo with a hundred fields, say, then there would be a big saving by using Scala. But first, we’d better justify why this is so different from the Java version yet is still acceptable.

In Scala, everything is public unless marked protected or private. The var keyword introduces mutable fields; the type of each field comes after its name, instead of before (for good reasons outside the scope of this article). These var fields are public because nothing says otherwise. The other syntactic requirement is the ‘= _’ default initialisation, which is not optional in Scala (Java’s fields are initialised to null if not explicitly initialised). Finally, note that semicolons are optional at the end of each line, so I left them off.

It looks like the Scala code above breaks the encapsulation convention: there are three fields, all variable and publicly accessible. In Java, we don’t like having public fields because we lose the option to change them later and use setters/getters instead (as discussed above). But in Scala, this is not a problem.

This works because Scala has a uniform access principle: a public variable can be replaced with a getter of the same name and a corresponding setter. Conversely, a getter/setter pair with simple behaviour can be replaced with an equivalent public variable. Scala guarantees that the two forms are equivalent.

So if Scala allows public fields to be converted to getters/setters (and vice versa) painlessly, it can painlessly abandon Java’s convention on encapsulation. And therefore the pojo is reduced to the three fields alone.

Testing Scala Pojos

The simple Person1 class raises an interesting question: how are we going to test it? The basics are so simple that they are simply correct by construction - and we assume the compiler gets it right, which it does of course. So all we’re left with is to confirm that the data model matches the requirement. Wow! That’s an eye opener.

Having said that, there’s that 100% code coverage target to aim for, so let’s have a go at writing a Scala test for Person1.

Person1Test, below, uses JUnit4 in a very similar way to PersonJTest. This needs no further explanation except to remark that there exist other Scala test frameworks that offer higher-level specification- or behaviour-based testing, instead of JUnit4’s procedural approach.

import org.junit.Assert._;
import org.junit.Test;

class Person1Test {

    @Test
    def testName() = {
        val p = new Person1()
        assertNull(p.name)
        p.name = "John Smith"
        assertEquals("John Smith", p.name)
    }

    @Test
    def testAge() = {
        val p = new Person1()
        assertEquals(0, p.age)
        p.age = 35
        assertEquals(35, p.age)
    }

    @Test
    def testMale() {
        val p = new Person1()
        assertFalse(p.male)
        p.male = true
        assertTrue(p.male)
        p.male = false
        assertFalse(p.male)
    }
}

A Verbose Scala Version

If we really wanted, we could change the three fields in Person1 to be private in the JavaBean style. There would be no benefit until the methods needed extra behaviour, but to illustrate how this is done, consider the following verbose version.

Note that the three getters (each starting with the def keyword) are grouped together in the middle and the three setters at the end, to help make the difference clear. The getters have the same names that we had originally used for fields, so the private fields themselves have slightly altered names - they are not allowed to have the same name. Because the getters have supplanted the original fields, any code elsewhere that uses this class doesn’t need any alteration:

  • This is the principle of uniform access put into practice.
class Person2 {
    private[this] var mName: String = _
    private[this] var mAge: Int = _
    private[this] var mMale: Boolean = _

    // getters

    def name: String = {
        mName
    }

    def age: Int = {
        mAge
    }

    def male: Boolean = {
        mMale
    }

    // setters

    def name_= (s: String) = {
        mName = s
    }

    def age_= (a: Int) = {
        mAge = a
    }

    def male_= (m: Boolean) = {
        mMale = m
    }
}

Remember that this behaves identically to the first Scala Person1, earlier. It looks quite similar to the original JavaBean PersonJ class, which is not surprising considering it’s essentially the same apart from the method names.

If you’re new to Scala, you might be surprised by the lack of the return keyword - instead, the getters are functions that return their last expression; although this is simple, it does need to be stated.

The setters have special names that associate them with their corresponding getters. The name ends with _= and this hints that the fields can be set using assignment. So it is possible for example to set the name field using either person.name_=("John") or person.name = "John", both of which mean the same.

As for testing, Person1Test can be copied as Person2Test, changing the instances to being of Person2 instead. Otherwise the test code is the same, so doesn’t need to be listed here.

Going on a Diet

Actually the Person2 version above is unusually verbose for Scala, which has strong conventions for eliminating unnecessary fluff and clutter. So below there’s a third Scala version, Person3, also with getters and setters but with minimal stuff in the way. Note that

  • the getters have been slimmed down, not needing return type nor braces.
  • the setters are shown as one-liners, which is what they are in this case. They don’t strictly need the braces either, but they would be harder to read without them.
class Person3 {

    private[this] var mName: String = _
    private[this] var mAge: Int = _
    private[this] var mMale: Boolean = _

    // getters

    def name = mName
    def age = mAge
    def male = mMale

    // setters

    def name_= (s: String) = { mName = s }
    def age_= (a: Int) = { mAge = a }
    def male_= (m: Boolean) = { mMale = m }
}

Using javap, a quick inspection of the compiled class files from the Person1, Person2 and Person3 reveals something remarkable: they’re almost identical! It’s helpful to know that the vars in Person1 are actually compiled to setter/getter pairs just like those in Person2 and Person3. This makes it easy to understand how inheritance works in Scala in terms of the overriding of vars in subclasses. It also makes it easy to get and set Scala vars from Java classes simply by calling the automatically-created accessors.

Conclusions

Scala has a principle of uniform access that ensures that it is easy to convert a class between using public variables and the equivalent form using getters and setters. It doesn’t matter to the client code which way it’s done. So pojos can therefore often be written extremely succinctly in Scala, compared to equivalent Java pojos.

Instead of writing and testing unnecessary lines of code, we can spend our time thinking about meaning and requirements. That’s surely a good way forward.

Next Steps

Is it really that easy to mix Scala and Java? We’ll discuss that important issue in a later article.

Having made mutable pojos short and clear, Scala goes further. Although mutable pojos are the essence of the JavaBean conventions and therefore the essence of enterprise Java middleware, immutable pojos are sometimes (often even) to be preferred. Scala makes immutable pojos easy. We’ll come back to this in a later article.

 
comments powered by Disqus