2010-03-12 104 views
4

我开始使用后端使用Hibernate(JPA)的Scala应用程序。为了加载一个对象,我使用下面这行代码:scala的通用对象加载函数

val addr = s.load(classOf[Address], addr_id).asInstanceOf[Address]; 

不用说,这有点痛苦。我写了一个辅助类,它是这样的:

import org.hibernate.Session 

class DataLoader(s: Session) { 
    def loadAddress(id: Long): Address = { 
    return s.load(classOf[Address], id).asInstanceOf[Address]; 
    } 
    ... 
} 

所以,现在我可以这样做:

val dl = new DataLoader(s) 
val addr = dl loadAddress(addr_id) 

这里的问题:我如何写一个可以加载任何一个通用的参数化方法使用相同模式的对象?即

val addr = dl load[Address](addr_id) 

(或类似的规定。)

我是新来斯卡拉所以请原谅这里任何东西,是特别可怕的。

回答

5

这就是:

import org.hibernate.Session 
class DataLoader(s: Session) { 
    def load[A](id: Long)(implicit m: Manifest[A]): A = { 
    return s.load(m.erasure, id).asInstanceOf[A]; 
    } 
} 

编辑 - 或者,以确保任何铸造错误 - 因为休眠返回错了对象的结果 - 会发生内部load,就像这样:

import org.hibernate.Session 
class DataLoader(s: Session) { 
    def load[A](id: Long)(implicit m: Manifest[A]): A = { 
    return m.erasure.asInstanceOf[Class[A]].cast(s.load(m.erasure, id)); 
    } 
} 

斯卡拉2。8,你也可以写这样的:

import org.hibernate.Session 
class DataLoader(s: Session) { 
    def load[A : Manifest](id: Long): A = { 
    return s.load(manifest[A].erasure, id).asInstanceOf[A]; 
    } 
} 

你可以用一个隐含的会议结合起来,以及通过Chris的建议:

def load[A](id: Long)(implicit m: Manifest[A], s: org.hibernate.Session): A = { 
    return s.load(m.erasure, id).asInstanceOf[A]; 
} 

请注意,您不能结合上下文视图符号( A : Manifest)以及其他隐式参数。

+0

@丹尼尔 - 你的asInstance演员阵容恐怕不是很安全。考虑两个语句'val a = load [Address](1)'和'val b:Any = load [Address](2)''的情况。在第二种情况下,实际上不会发生对Address类的强制转换(它们被擦除),并且您相信Hibernate会实际返回一个正确类型的实例(公平地说,它肯定会)。 – 2010-03-13 14:05:46

+0

@oxbow我明白了。你的观点是,'Class.cast'会在'load'内引起运行时错误,而不是留下一些可能会在以后引起麻烦的事情? – 2010-03-13 21:22:49

+0

是的 - 就是这样。在这里进行的唯一“正确”转换是在load方法之外,并由编译器插入,因为引用“a”的类型是Address。如果调用'load'方法并将其分配给'Any',那么不会发生CCE,并且您可能会发现某行发生了什么事情。 – 2010-03-14 12:35:36

3

一种方法是做利用java.lang.Class.cast方法,以做类似:

def load[A](clazz: Class[A], id: Long)(implicit s: Session) : A 
     = clazz.cast(s.load(clazz, id)) 

然后用法如下:

implicit val s = ...//get hibernate session 
val addr = load(classOf[Address], 1) 

这不是从什么巨大的差别你已经为了访问class实例,你需要通过它。

我很自信不能安全你想Manifests什么,因为他们不能在编译时,你才能需要剧组工作提供参数化Class[Address](他们只能提供擦除Class[_])。我没有看到任何其他机构做从Manifest

铸造当然你也可以使用asInstanceOf[A]代替cast但是这被在编译时擦除isInstanceOf[Object],因此没用在编译时类型检查的条款(因此是不可取的)。

+0

有趣。这会让事情变得更加整洁......但是,您刚刚教会了我几个新的Scala构造。感谢。 – 2010-03-12 15:57:21

+1

哈!我会证明你错了! ;-) – 2010-03-12 17:49:01

+0

顺便说一下...'asInstanceOf [A]'被擦除?这没有任何意义。此外,删除发生在运行时,而不是编译时。另一方面,我从来没有想过使用'Class [A]'来投射到'A'。有趣。 – 2010-03-12 18:02:52