2010-03-12 17 views
4

Je démarre sur une application Scala qui utilise Hibernate (JPA) à l'arrière. Pour charger un objet, j'utilise cette ligne de code:Fonction de chargement d'objet générique pour scala

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

Inutile de dire, c'est un peu douloureux. J'ai écrit une classe d'aide qui ressemble à ceci:

import org.hibernate.Session 

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

Alors, maintenant, je peux le faire:

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

Voici la question: Comment puis-je écrire une méthode paramétrisé générique qui peut charger tout objet en utilisant ce même modèle? i.e.

val addr = dl load[Address](addr_id) 

(ou quelque chose dans ce sens.)

Je suis nouveau à Scala donc s'il vous plaît pardonnez ici c'est particulièrement hideux.

Répondre

5

Ici, il est:

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]; 
    } 
} 

EDIT - Ou, pour faire en sorte que toute erreur de coulée - à la suite de mise en veille prolongée retournant le mauvais objet - qui va se passer à l'intérieur load, comme ceci:

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)); 
    } 
} 

Sur Scala 2.8 vous pouvez également écrire comme ceci:

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

Vous pouvez combiner avec une session implicite et, comme l'a suggéré Chris:

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

Notez que vous ne pouvez pas combiner la notation de vue contextuel (A : Manifest) avec des paramètres implicites supplémentaires.

+0

@Daniel - votre distribution asInstanceOf n'est pas vraiment sûre J'ai peur. Considérons le cas de deux instructions 'val a = load [Adresse] (1)' et 'val b: Any = load [Adresse] (2)'. Dans le second cas, aucun cast de la classe 'Address' n'est en cours (ils sont effacés) et vous faites confiance à Hibernate pour vous renvoyer une instance du bon type (ce qui, pour être juste, le fera certainement). –

+0

@oxbow je vois. Votre argument étant qu'un 'Class.cast' provoquera une erreur d'exécution dans le' load', au lieu d'être laissé avec quelque chose qui pourrait causer des problèmes plus tard? –

+0

Oui - c'est exactement ça. Le seul "correct" cast en cours ici est en dehors de la méthode 'load' et inséré par le compilateur car le type de la référence' a' est Address. Si la méthode 'load' est appelée et assignée à un' Any', alors aucun CCE ne se produit et vous pouvez trouver que quelque chose se casse en bas de la ligne. –

3

Une méthode serait de faire bénéficier de la méthode java.lang.Class.cast afin de faire quelque chose comme:

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

Ensuite, l'utilisation est comme suit:

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

Ce n'est pas extrêmement différent de ce que vous avez déjà, mais pour accéder à l'instance class, vous devez le transmettre.

Je suis assez confiant que vous ne pouvez pas en toute sécurité faire ce que vous voulez avec Manifests parce qu'ils ne peuvent pas fournir les Class[Address] à paramétrisé compilation dont vous avez besoin pour que la distribution au travail (ils ne peuvent fournir l'effacement de Class[_]). Je ne vois pas d'autre mécanisme pour faire un casting d'une Manifest

Vous pouvez bien sûr utiliser asInstanceOf[A] au lieu de cast mais cela est effacé à la compilation de isInstanceOf[Object] et est donc inutile en termes de vérification de type compilation (et donc déconseillé).

+0

Intéressant. Cela rend les choses un peu plus ordonnées ... mais vous venez de me parler de quelques nouvelles constructions de Scala. J'apprécie cela. –

+1

Hah! Je vais te prouver le contraire! ;-) –

+0

En passant ... 'asInstanceOf [A]' est effacé? Cela n'a aucun sens. En outre, l'effacement a lieu au moment de l'exécution et non lors de la compilation. D'un autre côté, il ne m'est jamais arrivé d'utiliser un 'Class [A]' pour faire un casting à 'A'. Intéressant. –