The way hibernate implements lazy loading is that a proxy object facilitates the loading of them. This is well know and is documented here:

http://community.jboss.org/wiki/ProxyVisitorPattern

Unfortunately this means that pattern matching on classes may now work. For instance, if the following were hibernate entities:

trait PaymentSource
class CreditCard extends PaymentSource
class Check extends PaymentSource
class User {
  val paymentSources = List[PaymentSource]
}

Doing a patter match as such would not work if the loaded object is a proxy:

user.paymentSources.map( _ match {
  case _:CreditCard => "Credit Card"
  case _:Check => "Check"
})

In Java, the work around is to use a visitor pattern.  Here it is implemented in scala:

trait PaymentSource {
  def accept[T](visitor: PsVisitor[T]) : T
}

class CreditCard extends PaymentSource{
  override def accept[T](visitor: PsVisitor[T]) = {
    visitor.visit(this)
  }
}

class Check extends PaymentSource{
  override def accept[T](visitor: PsVisitor[T]) = {
    visitor.visit(this)
  }
}

trait PsVisitor[T] {
  def visit(cc: CreditCard) : T
  def visit(ck: Check) : T
}

Although this works consistently, the syntax is not quite as nice.

  user.paymentSources.map( _.accept(new PsVisitor[Unit]() {
        def visit(cc: CreditCard) = println("CreditCard")
        def visit(ck: Check) = println("Check")
   })

A solution to this is to add simple wrapper classes for each concrete class and a simple visitor implementation to do the actual wrapping

object PsFilter {
  def apply(ps: PaymentSource) = {
    ps.accept(new PsVisitor[PsResult] {
      def visit(cc: CreditCard) = CreditCardResult(cc)
      def visit(ck: Check) = CheckResult(ck)
    })
  }
}

sealed trait PsResult
case class CreditCardResult(cc: CreditCard) extends PsResult
case class CheckResult(cc: Check) extends PsResult

And now we can pattern match again

user.paymentSources.map(PsFilter(_) match {
      case CreditCardResult(cc) => "CreditCard"
      case CheckResult(ck) => "Check"
})

Source for this can be found at Git Hub: https://github.com/OleTraveler/HibernateInheritance

 

Tagged with:  

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>