Scala - Java - interoperability example using the Spring framework's JdbcTemplate

This Scala example illustrates how nice Scala code can interact with Java code including thirt part libraries such as the latest release of the Spring framework and an old JDBC driver for CSV files. The reason that a CSV driver is used is to make it easier to test for anyone, without having to learn a particular database server and populate it with data. To be able to "configure the database" (to try experimenting with the source code below), all you need to do is to put a file in the following path (or change one line in the Java code, where this path is hardcoded):
C:\temp\txtFilesFolder\persons.csv
with the following content (for example):

Name,Age
Tomas,37
Niclas,32
Henrik,27

Then, when you will execute the Java main class (interacting with Scala code), you should get the following output:

-----------------------------
Finding some persons with the implementation class PersonRepositoryImplementedWithJava
Name: Tomas , Age: 37 , Tomas is 37 years old
Name: Niclas , Age: 32 , Niclas is 32 years old
Name: Henrik , Age: 27 , Henrik is 27 years old
-----------------------------
Finding some persons with the implementation class PersonRepositoryImplementedWithScala
Name: Tomas , Age: 37 , Tomas is 37 years old
Name: Niclas , Age: 32 , Niclas is 32 years old
Name: Henrik , Age: 27 , Henrik is 27 years old
-----------------------------

The Java/Scala code is possible to execute from within the free version of IntelliJ IDEA, the so called Community Edition

The Java interface below defines a small Repository interface for a very simple Person entity. Please note that the Person entity, used in the Java interface will be implemented further down as a Scala class.

package springFromScala;
import java.util.Collection;
public interface PersonRepository { // Java interface
    Collection<Person> findAll(); // Person is a Scala class (see further down)
}

The Java implementation of the interface:

package springFromScala;
// The code is tested with jarfiles in "Spring Framework 3.0.0.RELEASE" 
// downloaded 2010-01-20 from  http://www.springsource.org/download
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public final class PersonRepositoryImplementedWithJava implements PersonRepository {
    private final JdbcTemplate jdbcTemplate;
    public PersonRepositoryImplementedWithJava(final String connectionString) {
        jdbcTemplate = new JdbcTemplate(new DriverManagerDataSource(connectionString));
    }
    public Collection<Person> findAll() {
        final List<Person> persons = new ArrayList<Person>();
        jdbcTemplate.query(
            "select Name,Age from persons",
            new RowCallbackHandler() {
                public void processRow(ResultSet rs) throws SQLException {
                    persons.add(new Person(rs.getString("Name"), rs.getInt("Age")));
                }
            }
        );
        return Collections.unmodifiableCollection(persons);
    }
}

Below is a Scala implementation of the same interface:

package springFromScala;
import org.springframework.jdbc.core.{RowCallbackHandler, JdbcTemplate}
import org.springframework.jdbc.datasource.DriverManagerDataSource
import java.sql.ResultSet
class PersonRepositoryImplementedWithScala(connectionString: String) extends PersonRepository {
  val jdbcTemplate = new JdbcTemplate(new DriverManagerDataSource(connectionString))
  def findAll: java.util.Collection[Person] = {
    val persons = new java.util.ArrayList[Person]
    jdbcTemplate.query("select Name,Age from persons", new RowCallbackHandler {
      def processRow(rs: ResultSet) = {
        persons.add(new Person(rs.getString("Name"), rs.getInt("Age")))
      }
    })
    return persons
  }
}

Below is the Person class, implemented with Scala, which was used by both above implementations (and also in the Java interface method signature):

package springFromScala;
import reflect.BeanProperty
class Person(@BeanProperty val name: String, @BeanProperty val age: Int) {
  override def toString: String = {
    return "Name: " + name + " , Age: " + age 
  }  
}

Finally, a main class is shown below, which will query the data from the textfile with one Java implementation, and one Java implementation (but both of them use the Spring framework, as you have seen above)

package springFromScala;
import org.relique.jdbc.csv.CsvDriver; // "csvjdbc.jar" downloaded from http://csvjdbc.sourceforge.net/
public final class JavaMainClass {

    private static void findPersonsAndPrintThemToConsole(final PersonRepository personRepository) {
        System.out.println("Finding some persons with the implementation class " + personRepository.getClass().getSimpleName());
        final Iterable<Person> persons = personRepository.findAll();
        for (Person person : persons) {
            // When you look in the Scala Person class above, it does not seem to have any getters methods,
            // but they are actually provided, thanks to the '@BeanProperty'
            // in the primary constructor (i.e. at the class declaration)
            printToConsole(person.toString() + " , " + person.getName() + " is " + person.getAge() + " years old");
        }
    }

    public static void main(String[] args) {
        printSomeHyphensToConsole();

        findPersonsAndPrintThemToConsole(new PersonRepositoryImplementedWithJava(getConnectionString()));

        printSomeHyphensToConsole();

        findPersonsAndPrintThemToConsole(new PersonRepositoryImplementedWithScala(getConnectionString()));

        printSomeHyphensToConsole();
    }

    private static void printSomeHyphensToConsole() {
        printToConsole("-----------------------------");
    }    
    private static void printToConsole(final String outputString) {
        System.out.println(outputString);
    }

    private static String connectionString = null;
    private static String getConnectionString() {
        if(connectionString == null) {
            try {
                Class.forName(CsvDriver.class.getName());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            connectionString = "jdbc:relique:csv:" + "c:/temp/txtFilesFolder";
        }
        return connectionString;
    }
   
}
/ Tomas Johansson, Stockholm, Sweden, 2010-01-20