I have play web application with conf/application.conf (nothing unusual). Guice is used for dependency injection. How can property value be injected in class constructor? The code is below.
class MyController #Inject() (private val foo: Foo) extends Controller {
...
}
#ImplementedBy(classOf[FooImpl])
trait Foo {
def bar: String
}
class FooImpl extends Foo {
override val bar = current.configuration.getString("my.bar").get
...
}
In the current configuration FooImpl can't be tested without running application. I want to be able instantiate FooImpl in unit tests. The perfect solution [from my point of view] should look like that:
class FooImpl #Inject() (#Named("my.bar") override val bar: String) extends Foo {
...
}
Unfortunately, this code doesn't work, because Guice doesn't have 'my.bar' binding:
No implementation for java.lang.String annotated with #com.google.inject.name.Named(value=my.bar) was bound.
The only solution that I came up with is writing my own module, which iterates through configuration properties and binds them as named dependencies (a variation of the example from this doc). But I believe that a better approach exists.
I implemented that using Java. I hope you can use it as reference for your Scala implementation.
At first, I created a Module:
public class MainModule extends AbstractModule {
public final static String TIMEOUT_IN_MILLISECONDS_ANNOTATION = "timeout-promise";
private final Configuration configuration;
public MainModule(#SuppressWarnings("unused") Environment environment, Configuration configuration) {
this.configuration = configuration;
}
#Override
protected void configure() {
long timeoutInMilliseconds = configuration.getLong("application.promise.timeout.in.milliseconds", 0L);
bindConstant().annotatedWith(Names.named(TIMEOUT_IN_MILLISECONDS_ANNOTATION)).to(timeoutInMilliseconds);
}
}
After that, I just used the annotation on different places:
class Service {
#Inject
#Named(MainModule.TIMEOUT_IN_MILLISECONDS_ANNOTATION)
protected long timeoutInMilliseconds;
}
Hope this helps.
Some time ago i was developed small guice extention for simple injection configuration variables mapped on Enum
guice-config
I encountered the same problem after about a year, and this time come up with the following solution (very similar to the one proposed by #stranger-in-the-q and #droidman):
class InjectionModule extends AbstractModule {
override def configure(): Unit = {
val config: Config = TypesafeConfigReader.config
config.entrySet().asScala.foreach { entry =>
val path = entry.getKey
entry.getValue.valueType() match {
case ConfigValueType.NUMBER =>
bind(classOf[Int])
.annotatedWith(Names.named(path))
.toInstance(config.getInt(path))
case ConfigValueType.BOOLEAN =>
bind(classOf[Boolean])
.annotatedWith(Names.named(path))
.toInstance(config.getBoolean(path))
case ConfigValueType.STRING =>
bind(classOf[String])
.annotatedWith(Names.named(path))
.toInstance(config.getString(path))
case _ =>
}
}
}
}
Also, this approach can be extended by appending prefixes to system properties (which key-value pairs are part of the loaded config):
private def getPrefix(configValue: ConfigValue): String = {
val description = configValue.origin().description()
if (description.contains("system properties")) {
"sys."
} else {
""
}
}
In this case instead of writing Names.named(path) one should use Names.named(getPrefix(entry.getValue) + path).
To inject multiple properties from a play configuration you could do this way. Create a map out of Play configuration and pass it as Properties to Guice binder.
public class Module extends AbstractModule {
private Environment environment;
private Configuration configuration;
public Module(Environment environment,Configuration configuration){
this.environment = environment;
this.configuration = configuration;
}
#Override
public void configure() {
Configuration helloConf = configuration.getConfig("myconfig");
Map<String, Object> map = helloConf.asMap();
Properties properties = new Properties();
properties.putAll(map);
Names.bindProperties(binder(), properties);
}
}
Related
I have a 3rd party library that I am trying to inject the configuration into the constructor.
This is what I need to do:
class MyModule(configuration: Configuration) extends AbstractModule {
override def configure(): Unit = {
bind(classOf[TwitterApi])
.to(classOf[MyTwitterApi])
.asEagerSingleton
}
}
The constructor of MyTwitterApi doesn't take a Play.api.Configuration but a typesafe.config.Config
class MyTwitterApi(config: Config) ...
So I need to do pass configuration.underlying to my constructor, how is this possible using DI in this AbstractModule?
I need this instance to be a singleton also.
You can use provider to setup your module with eagerSingleton
import com.google.inject.{AbstractModule, Provider}
class MyModule(configuration: Configuration) extends AbstractModule {
override def configure(): Unit = {
val twitterApiProvider: Provider[TwitterApi] =
() => new MyTwitterApi(configuration.underlying)
bind(classOf[TwitterApi])
.toProvider(twitterApiProvider)
.asEagerSingleton
}
}
You can find a working example with sample classes at - https://scastie.scala-lang.org/sarveshseri/ujwvJJNnTpiWDqdkBJQoFw/2
I think you want something like this:
class MyModule(configuration: Configuration) extends AbstractModule {
override def configure(): Unit = {
val myTwitterApiInstance = new MyTwitterApi(configuration.underlying)
bind(classOf[TwitterApi])
.toInstance(myTwitterApiInstance)
}
}
Or another approach would be to provide a binding for Config but if your MyTwitterApi doesn't have #Inject annotation this won't help.
I want to use DI google guice which works perfectly fine in Java but doesnt work in case of scala. Here is my code:
Module:
class ConfigModule extends AbstractModule{
override def configure(): Unit = {
}
#Provides
#Named("config")
def getConfig(): Config = {
new Config
}
}
Config
class Config {
val config1: String = "Sample"
}
Service
class Service(#Named("config") config:Config) {
def read(): Unit = {
println("Reading")
}
}
Main Class
object SampleJob {
def main(args: Array[String]): Unit = {
val injector = Guice.createInjector(new ConfigModule)
val service = injector.getInstance(classOf[Service])
service.read()
}
}
Error:
1) Could not find a suitable constructor in com.job.Service. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
at com.job.Service.class(Service.scala:7)
while locating com.job.Service
Where am I mistaken?
UPDATE:
class Service(#Inject #Named("config") config:Config) {
def read(): Unit = {
println("Reading")
}
}
This also returns the same error
Could not find a suitable constructor in com.job.Service. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
at com.job.Service.class(Service.scala:8)
while locating com.job.Service
The error tells you what happened:
Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private
So you need to add #Inject annotation... on your constructor like in tutorial.
Instead of
class Service(#Inject #Named("config") config:Config) {
def read(): Unit = {
println("Reading")
}
}
it should be
class Service #Inject() (#Named("config") config:Config) {
def read(): Unit = {
println("Reading")
}
}
I'm using codingwell/scala-guice and trying to inject DAO-classes into constructors of other components/classes.
In the first attempt, I only used one DAO-class to see if it works:
class DaoModule extends AbstractModule with ScalaModule {
override def configure() {
val dao1 = new FirstDaoImpl
bind(new TypeLiteral[FirstDaoTrait] {}).toInstance(dao1)
}
}
The binding works as expected, it can be used for constructor injection.
In the second step, I wanted to add another DAO class to the module. However, that DAO-class depends on the first DAO:
class SecondDaoImpl #Inject()(firstDao: FirstDaoTrait) extends SecondDaoTrait
I'm not sure how to add the necessary binding to the existing module. Repeating the first step would result in this:
val dao2 = new SecondDaoImpl(???)
bind(new TypeLiteral[SecondDaoTrait] {}).toInstance(dao2)
But of course this class can only be instantiated by providing the first DAO (therefore the "???"). How can I do this?
Use bind and let scala-guice resolve the dependencies for you:
class DaoModule extends AbstractModule with ScalaModule {
override def configure() {
bind[FirstDaoTrait].to[FirstDaoImpl]
bind[SecondDaoTrait].to[SecondDaoImpl]
}
}
And now using the injector:
val injector = Guice.createInjector(new DaoModule())
val secondDao = injector.instance[SecondDaoTrait]
I've been following this article which describes how to achieve dependency injection in Scala via the Cake Pattern:
http://jonasboner.com/real-world-scala-dependency-injection-di/
I'm kind of new to Scala and I admit some of it went over my head, so far I've got the following working:
// Setup the component and interface
trait AccountRepositoryComponent {
val accountRepository: AccountRepositoryInterface
trait AccountRepositoryInterface {
def message: String
}
}
// An implementation
trait MyAccountRepositoryComponent extends AccountRepositoryComponent {
object AccountRepository extends AccountRepositoryInterface {
def message: String = "Hello"
}
}
// Object to configure which implementations to use and retrieve them
object ComponentRegistry extends MyAccountRepositoryComponent {
val accountRepository = AccountRepository
}
// Example service using the above
object AccountService {
val repo = ComponentRegistry.accountRepository
def say: String = repo.message
}
println(AccountService.say)
What I'm failing to understand is how I would now pass in a fake repository to Account Service, say to change the output to "Test" rather than "Hello"?
There are various ways this could be modified to achieve a workable result, depending on what counts as a workable result for your situation. I'll go through a simpler possibility here.
First, the ComponentRegistry needs to become a trait, so it can be mixed in to the AccountService:
// Trait to configure which component implementations to use and retrieve them
object ComponentRegistry extends MyAccountRepositoryComponent {
val accountRepository = AccountRepository
}
// Example service using the above
object AccountService extends ComponentRegistry {
def say: String = accountRepository.message
}
println(AccountService.say)
This should print "Hello" as before. To set up a test case, add the following:
// Test implementation
trait TestAccountRepositoryComponent extends AccountRepositoryComponent {
object AccountRepository extends AccountRepositoryInterface {
def message: String = "Test"
}
}
// trait to configure test component implementations
trait TestComponentRegistry extends TestAccountRepositoryComponent {
val accountRepository = AccountRepository
}
Now we can set up a service that uses the test components:
// Example service using the above
object AccountService extends TestComponentRegistry {
//val repo = ComponentRegistry.accountRepository
def say: String = accountRepository.message
}
println(AccountService.say)
This should print "Test".
Note that you would probably want your AccountService to define its functionality in terms of other mixins/traits, which would expect the appropriate components to be available (layered into the "cake"), but wouldn't know which implementation was in use. Eg:
trait CustomerApi {
self: AccountRepositoryComponent => // Expects an implementation of AccountRepositoryComponent to be mixed in
def say: String = accountRepository.message
}
Now the method say is implemented without knowing what version of AccountRepository it will interact with, but knowing one must be provided (checked at compile time). So we can write:
object AccountService extends CustomerApi with ComponentRegistry
object TestAccountService extends CustomerApi with TestComponentRegistry
Calling println(AccountService.say) will generate "Hello", while calling println(TestAccountService.say) will generate "Test".
This post provides a succinct example of that (followed by an interesting alternative).
I need a smart mechanism for component composition which allows mixed in traits to initialize after the composed component. The following throws a NullPointerException:
class Component {
def addListener(pf: PartialFunction[Any, Unit]) {}
}
trait DynamicComponent {
protected def component: Component
component.addListener {
case x =>
}
}
class Foo extends DynamicComponent {
protected val component = new Component
}
new Foo // -> NullPointerException
The following things are not options for me:
Using protected lazy val component; that would produce an avalange of dozens of vals needing to become lazy, something I do not want.
Putting addListener in a method, e.g. initDynamic(); because I will be mixing in many traits, and I don't want to remember to call half a dozen initFoo() methods.
Using DelayedInit. This doesn't work with traits, at least according to the scaladocs.
I could live with a single init() call, but only under the following conditions:
all mixed in traits can easily declare to be invoked in this one single call
it is a compile error to forget the init() statement.
You can delay the initialization of a trait by by using early definitions. (See section 5.1.6 of the scala language specification)
class Foo extends {
protected val component = new Component
} with DynamicComponent
It's even clunkier than your solution, but you can always require the creation of a val that must be set with the init() method. You could choose to not do it last and get an error at runtime, but at least you won't forget it entirely:
class Component {
def addListener(pf: PartialFunction[Any, Unit]) {
println("Added")
}
}
trait Dyn {
protected def component: Component
protected val initialized: Init
class Init private () {}
private object Init { def apply() = new Init() }
def init() = { component.addListener{ case x => }; Init() }
}
class Foo extends Dyn {
protected val component = new Component
protected val initialized = init()
}
No cheating!:
> class Bar extends Dyn { protected val component = new Component }
<console>:12: error: class Bar needs to be abstract, since value
initialized in trait Dyn of type Bar.this.Init is not defined
class Bar extends Dyn { protected val component = new Component }
The advantage this has is if you need multiple things to be in place before you initialize all of them cooperatively, or if your Component class is final so you can't mix in anything else.
AN idea could be to use the trick described here:
Cake pattern: how to get all objects of type UserService provided by components
All your components that should be initialized could be registered in some Seq[InitializableComponent]. And then you could initialize all registered components with a foreach.
No component will be forgotten in that Seq because they are registered automatically, but you can still forget to call the foreach anyway...
Here is one idea (I am happy to read about other suggestions):
class Component {
def addListener(pf: PartialFunction[Any, Unit]) {
println("Added")
}
}
trait DynamicComponentHost {
protected def component: Component with DynamicPeer
protected trait DynamicPeer {
_: Component =>
addListener {
case x =>
}
}
}
class Foo extends DynamicComponentHost {
protected val component = new Component with DynamicPeer
}
new Foo
So basically I am forcing the component to mix in a type that can only be provided by the mixed in trait. Reasonable? Looks a bit too complicated in my eyes.