2017-06-16 2 views
0

J'utilise Play 2.5 avec l'injection de dépendance de Guice.Comment lier la classe avec Google Guice en utilisant un FQDN Chaîne

bind normal fonctionne comme:

bind(classOf[SomeClass]).to(classOf[DefaultClass]) 

maintenant je dois seulement être en mesure de lier une classe où le nom de classe a été spécifié dans la configuration.

J'ai essayé quelque chose comme:

val className = config.getString("someClass.className") 
val x: Class[_] = Class.forName(className) 
bind(classOf[SomeClass]).to(classOf[x]) 

Mais les types sont mauvais.

Il doit être fait par Guice, puisque le SomeClass a un argument qui doit être injecté, sinon je l'aurais utilisé quelque chose comme

val className = config.getString("someClass.className") 
val x = Class.forName(className).newInstance().asInstanceOf[SomeClass] 
bind(classOf[SomeClass]).toInstance(x) 

Est-ce que quelqu'un a une idée sur la façon de lier via Guice ?

+0

Tu ne peux pas jeter être le bon type générique? Je ne sais pas Scala, mais en Java 'Class clazz = (Classe ) Class.forName (className); bind (SomeClass.class) .to (clazz); ' –

Répondre

0

Je pense que vous cherchez quelque chose comme ça ...

lazy val injector = (new GuiceApplicationBuilder).injector() 
def inject[T : ClassTag]: T = { 
    injector.instanceOf[T] 
} 

C'est la version la plus simple, mais ne gère pas d'arguments. Vous devez créer une classe, puis l'appeler inject[SomeDep].

Je n'ai pas trouvé un bon moyen d'injection à la volée, la seule façon de vraiment le faire via @inject à la classe la plus invoquée. Nous utilisons uniquement l'injection pour les tests unitaires actuellement.

+0

Il ne cherche pas à injecter à la volée mais à configurer une liaison qui peut être spécifiée lors de l'exécution. –

0

Merci pour la réponse, mais j'ai finalement réussi à l'utiliser en utilisant la réflexion de Scala.

object Reflection { 
    import scala.reflect.api 
    import reflect.runtime.universe._ 
    import reflect.ClassTag 

    def classTagToClass[T: reflect.ClassTag]: Class[T] = { 
    def ctag = implicitly[reflect.ClassTag[T]] 
    ctag.runtimeClass.asInstanceOf[Class[T]] 
    } 

    def typeToClassTag[T: TypeTag]: ClassTag[T] = { 
    ClassTag[T](typeTag[T].mirror.runtimeClass(typeTag[T].tpe)) 
    } 

    def stringToTypeTag[A](name: String): TypeTag[A] = { 
    val c = Class.forName(name) // obtain java.lang.Class object from a string 
    val mirror = runtimeMirror(c.getClassLoader) // obtain runtime mirror 
    val sym = mirror.staticClass(name) // obtain class symbol for `c` 
    val tpe = sym.selfType // obtain type object for `c` 
    // create a type tag which contains above type object 
    TypeTag(mirror, new api.TypeCreator { 
     def apply[U <: api.Universe with Singleton](m: api.Mirror[U]): U#Type = 
     if (m eq mirror) { 
      tpe.asInstanceOf[U#Type] 
     } 
     else { 
      throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.") 
     } 
    }) 
    } 
} 

en utilisant l'objet ci-dessus, vous pouvez lier une classe utilisant FQDN de la manière suivante:

configuration.getString("config.className") 
.map(className => 
    bind(classOf[AbstractClass]).to(classTagToClass(typeToClassTag(stringToTypeTag[AbstractClass](className)))) 
).getOrElse(bind(classOf[AbstractClass]).to(classOf[AbstractClassImpl]))