Recently I was wondering whether it was possible to use JPA (Java Persistence API) with Scala. So I did some fiddling around and found out that it is quite easy with Scala (but that’s not a surprise).

I used the following libraries in this example:
– Hibernate 3.5.6.Final (JPA2 implementation)
– Hsqldb 1.8.0.7
– Spring 3.0.5
– Scala 2.8.1

Scala code

First I created an entity class “Customer” with a first and a last name and of course an id.

package nl.paulhildebrand.jpa

import javax.persistence._
import scala.reflect.BeanProperty

@Entity
@Table(name = "customer")
class Customer(f: String, l: String) {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @BeanProperty
    var id: Int = _

    @BeanProperty
    var firstName: String = f

    @BeanProperty
    var lastName: String = l

    def this() = this (null, null)

    override def toString = id + " = " + firstName + " " + lastName
}

Because it is an example I kept the entity “Customer” simple. Nice to notice is the @BeanProperty annotation. It dynamically adds a getter and a setter for the given variable. This keeps the code clean and the JPA implementation working. The rest is similar to a Java implementation.

To access the database I created a DAO. But first I needed to define the interface for it. In scala an interface is called a Trait.

package nl.paulhildebrand.jpa

trait CustomerDao {
    def save(customer: Customer): Unit

    def find(id: Int): Option[Customer]

    def getAll: List[Customer]

    def getByLastName(lastName : String): List[Customer]
}

As you can see it has some simple method to save and find customers. Lets have a look at the implementation of the trait.

package nl.paulhildebrand.jpa

import org.springframework.beans.factory.annotation._
import org.springframework.stereotype._
import org.springframework.transaction.annotation.{Propagation, Transactional}
import javax.persistence._
import scala.collection.JavaConversions._

@Repository("customerDao")
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
class CustomerDaoImpl extends CustomerDao {

    @Autowired
    var entityManager: EntityManager = _

    def save(customer: Customer): Unit = customer.id match {
        case 0 => entityManager.persist(customer)
        case _ => entityManager.merge(customer)
    }

    def find(id: Int): Option[Customer] = {
        Option(entityManager.find(classOf[Customer], id))
    }

    def getAll: List[Customer] = {
        entityManager.createQuery("From Customer", classOf[Customer]).getResultList.toList
    }

    def getByLastName(lastName : String): List[Customer] = {
        entityManager.createQuery("From Customer Where lastName = :lastName", classOf[Customer]).setParameter("lastName", lastName).getResultList.toList
    }
}

This is a quite standard DAO implementation but the real magic is in the implicit conversions of the java collections to scala collections. This can be achieved by adding “import scala.collection.JavaConversions._”. Now methods as toList are available on the collections. Keep in mind this is an example, doing “getAll” on a large dataset is not recommended.

Configuration

When using JPA you need a file called META-INF/persistence.xml. The one below is an example for JPA2.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="JpaScala" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
    </persistence-unit>

</persistence>

To wire all the code and libraries together I use the Spring Framework. The application-context below defines the following:
– Transaction manager
– JPA2 Entity manager
– Data source (Hypersonic memory database)
– Context scanner so it is able to find the spring annotated classes.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
	        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
			http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        ">

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <context:component-scan base-package="nl.paulhildebrand"/>

    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource"
          p:driverClassName="org.hsqldb.jdbcDriver" p:url="jdbc:hsqldb:mem:JpaScala"
          p:username="sa" p:password=""/>

    <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="JpaScala"/>
        <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        </property>

        <property name="dataSource" ref="dataSource"/>
        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
                <entry key="hibernate.connection.charSet" value="UTF-8"/>
                <entry key="hibernate.hbm2ddl.auto" value="create"/>
                <entry key="hibernate.show.sql" value="true"/>
            </map>
        </property>
    </bean>

    <bean id="entityManager"
          class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

Try it out

The code below adds 5 customers to the database and shows them using various methods on the CustomerDao.

val ctx = new ClassPathXmlApplicationContext("application-context.xml")
val dao: CustomerDao = ctx.getBean(classOf[CustomerDao])

dao.save(new Customer("Paul", "Hildebrand"))
dao.save(new Customer("Floor", "Hildebrand"))
dao.save(new Customer("Storm", "Hildebrand"))
dao.save(new Customer("Jan", "Jansen"))
dao.save(new Customer("Peter", "Jansen"))

println(dao.getAll)
println(dao.getByLastName("Jansen"))
println(dao.getByLastName("Hildebrand"))

dao.find(3) match {
    case Some(x) => println(x)
    case None => println("No customer found with id 3")
}

Thoughts
With this example you should be able to write a simple JPA application using Scala. I have not yet tried to use things like case classes or many to one relations using Scala collections. You might also be able to improve the code using annotations in constructor arguments so that some “vars” can be replaced by “vals”.

For the dependency injection I used the Spring Framework because I use that a lot, but a framework like Guice works just as good.

This code might not work with Scala 2.7.x because of possible nested annotations.

Source code:
You can download the source code here.

For SBT users:
– unpack JpaScala.tar.gz
– start SBT in the root directory of JpaScala
– create new project
– do “update”
– do “run JpaScala”

If you have some improvements, please let me know. I am still quite new in the Scala world but I am learning fast.