injecting from a class, not a type
Is it possible to inject from a class at runtime, not a given type?. Use Case: I am getting the full class name from a remote site and want to create the corresponding instance by injection, not by reflection. All inject methods I found need a type with TypeTag, but it should be possible to just have the class and use the scaldi injection mechanism. I could not figure out, how to do it with the current code of scaldi.
Is it a finite list of possible class names? In that case you could create some bindings to Any that are identified by an identifier http://scaldi.org/learn/#identifiers . When the injection is needed, the identifier is chosen according to received according to the string with the class name.
Thanks for the quick answer. The list is finite as the class must exist on the other side of the network. Your solution seems possible, but the inject usage seems not natural, as I get back a list of Any and had to take the first one. More natural would be: def injectT:T = ... so I could use val myRootInstance:Object = inject(classLoadedLocallyFromRemotePath) and in the module simply bind [MyService] to (new ServiceImpl) without any identifiers. When the remote site sends "...IMyService" as the class path requested, I could load the class of this interface, and if existent, resolve the implementation by the injector. This class based inject could also be helpful in generic code, where the caller does not have the real type at hand, just the class.
Background: this is intended for a proxy use case, where client can request many different root services and work with proxies of them on a server.
It doesn't have to be Any, it may also be a trait Service that is extended by all classes that may be returned by remote service.
What I had in mind was a pattern matching (on the remote server's class name) that returns the injected class (that also extends Service)
val service = match(className){
case "TCP" => inject[Service] identified by 'tcp
case "UDP" => inject[Service] identified by 'udp
}
This may not be the most elegant code though, @OlegIlyenko may pass by with a better solution.
sorry, the markdown messed up my suggestion in my last comment. it used to be:
def inject[T](clazz:Class[T]):T = ...
where T could be Object in the most generic case.
Sorry for the late reply. Sure, you can do it like this:
val clazz = classOf[SomeDynamicClass]
val identifiers = TypeTagIdentifier(ReflectionHelper.classToType(clazz)) :: Nil
val res = injectWithDefault[SomeParentOfDynamicClass](injector, noBindingFound(identifiers))(identifiers)
This is a not very common use-case, so there is no dedicated inject method for this. On the other hand injectWithDefault (which is already available on Injectable) is pretty generic, so you can use it in conjunction with noBindingFound. You just need to provide it a custom list of identifies, like I have shown in the example above.