DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Alexey has posted 28 posts at DZone. View Full User Profile

Mapping Of Scala's Option In Hibernate

01.27.2010
| 8023 views |
  • submit to reddit
        Define your user types like this:

package example

import scala.{Array => A}
import org.hibernate._
import org.hibernate.usertype._
import org.hibernate.`type`._
import java.sql._
import java.io._

class StringOptionUserType extends OptionUserType { def nullableType = Hibernate.STRING }

class IntOptionUserType extends OptionUserType { 
    def nullableType = Hibernate.INTEGER 
    
    override def nullSafeGet(resultSet: ResultSet, names: A[String], owner: Object) = {
        val x = nullableType.nullSafeGet(resultSet, names(0)).asInstanceOf[Integer]
        if (x == null) None else Some(x.intValue)
    }

    override def nullSafeSet(preparedStatement: PreparedStatement, value: Object, index: Int) =
        nullableType.nullSafeSet(
            preparedStatement, 
            value.asInstanceOf[Option[Int]].map(new Integer(_)).getOrElse(null), 
            index)
}

abstract class OptionUserType extends UserType {

    def nullableType: NullableType

    def returnedClass = classOf[Option[_]]
    

    def sqlTypes = A(nullableType.sqlType)

    def nullSafeGet(resultSet: ResultSet, names: A[String], owner: Object) = {
        val x = nullableType.nullSafeGet(resultSet, names(0))
        if (x == null) None else Some(x)
    }

    def nullSafeSet(preparedStatement: PreparedStatement, value: Object, index: Int) =
        nullableType.nullSafeSet(preparedStatement, value.asInstanceOf[Option[_]].getOrElse(null), index)

    def isMutable = false

    def equals(x: Object, y: Object) = x.equals(y)

    def hashCode(x: Object) = x.hashCode

    def deepCopy(value: Object) = value

    def replace(original: Object, target: Object, owner: Object) = original

    def disassemble(value: Object) = value.asInstanceOf[Serializable]

    def assemble(cached: Serializable, owner: Object) = cached
}


Refer it like this:

package example

import java.io.Serializable
import javax.persistence._
import scala.reflect.{BeanProperty => P}
import org.hibernate.annotations.Type

@Entity
class Person extends Serializable {

    @Id @GeneratedValue
    @P var personId: Integer = _
    @P var firstName: String = _
    @Type { val `type` = "example.StringOptionUserType" }
    @P var lastName: Option[String] = None
    @Type { val `type` = "example.IntOptionUserType" }
    @P var age: Option[Int] = None
}


Note: Scala 2.8+ uses different syntax for annotations: @Type(`type`="..."). Symbol ` is required here because type is reserved word.    

Comments

Alexey Tarasevich replied on Wed, 2010/01/06 - 6:52pm

Here you can see how to use "immutable" scala objects with Hibernate: val Name = "Freddy" connect { (manager, tx) => val person = new Person(id=null, name=Name); tx { () => manager.persist(person) } var result = manager .createQuery("SELECT p FROM Person p WHERE p.name = :name") .setParameter("name", Name) .getSingleResult .asInstanceOf[Person] tx { () => manager.merge(result.copy(firstName=another)) } } Entity object can be defined in the following way. Hibernate will use default constructor to create instance of the class and will initialize implicit fields. import javax.persistence._ import java.io.Serializable @Entity class Person ( @Id @GeneratedValue val id: Integer, val name: String ) extends Serializable { def this() = this(id = null) } The previous snippet uses the helper function: def connect(body: (EntityManager, (() => Unit) => Unit) => Unit) { val factory = Persistence.createEntityManagerFactory("yourunitname"); val manager = factory.createEntityManager body(manager, { tx => manager.getTransaction().begin(); tx() manager.getTransaction().commit() }) manager.close(); factory.close(); }