Java Collection
JPA’s One to Many and Many to Many relations require an attribute of type java.util.Collection
like it is shown in the next example. This will be normally a List
interface and a ArrayList
implementation.
... @OneToMany public Collection organisations = new ArrayList() ...
Unfortunately the Scala Library has a different interface concept that we cannot use directly as java.util.Collection
replacements. Nevertheless it should be possible to tweak EclipseLink or OpenJPA to use Scala’s collections directly. But this would not allow to use the JPA libraries out of the box.
Reusing the Java Collection in Scala
A direct replacement of the Java class and its Collection would look like this:
import java.{util => ju} ... @OneToMany @BeanProperty var organisations:ju.Collection[Organisation] = new ju.ArrayList[Organisation]() ...
The annotation @BeanProperty
will take care of creating the corresponding getter and setter methods for collection organisations.
But in Scala we want to use Scala’s capabilities.
Property Access with JavaConversion Implicits
The Collection library supports the conversion from Java to Scala collections and vice versa by some implicit conversions defined in the JavaConversions
package.
To use them I prefixed the Java collection with j__
, which means ignore it. For accessing a Scala pendant I created two property access methods for property organisation. The implicit conversions will convert a Java List
from and to a Scala mutable.Buffer
.
import java.{util => ju} import scala.collection.JavaConversions._ import collection.mutable.Buffer ... @OneToMany @BeanProperty var j__organisations:ju.List[Organisation] = new ju.ArrayList[Organisation]() def organisations_= (c:Buffer[Organisation]) = j__organisations = c def organisations:Buffer[Organisation] = j__organisations ...
As you see j__organisations
uses two type modifiers List
and ArrayList
. Scala’s property declaration has some as well Buffer[Organisation]
. They usually are the same anywhere in an application (obviously except type Organisation).
How to get rid of these type declarations?
Externalized Collection Type and Creation
Object CollectionUtil
provides a factory method for creation of the Java collection and provides the type of collection for defining a entity property. So we have one place for refining Java’s collection type.
object CollectionUtil { def :+[T]:ju.List[T] = new ju.ArrayList[T] } import CollectionUtil._ ... @OneToMany @BeanProperty var j__organisations = :+[Organisation] ...
Delegating Implicits and Additional Types
This type declaration can be done for the Scala collection as well. Together with a delegation of the required implicits the code looks like this:
import java.{util => ju} import scala.collection.{JavaConversions => conv} import collection.{mutable => cm} object CollectionUtil { /** * type of the used Scala Collection */ type SC[T] = cm.Buffer[T] /** * create new instance of the Java Collection * List will be implicitly converted to Buffer by JavaConversion * and vice versa */ def :+[T]: ju.List[T] = new ju.ArrayList[T] /** * just to limit the implicit conversions and the * required imports */ implicit def asList[A](b: cm.Buffer[A]): ju.List[A] = conv.asList[A](b) implicit def asBuffer[A](l: ju.List[A]): cm.Buffer[A] = conv.asBuffer[A](l) } import CollectionUtil._ ... @OneToMany @BeanProperty var j__organisations = :+[Organisation] def organisations_=(c: SC[Organisation]) = j__organisations = c def organisations: SC[Organisation] = j__organisations ...
Example Usage Code
withTrxAndCommit { val oa = new EntityWithScalaCollections OrganisationIdList.foreach { id => val org = find[Organisation](id).get oa.organisations + org } persistAndFlush(oa) oa.getId }