In ZIO we provide the Environment with initiating Traits:
program.provide(
new Console.Live with MyComponent {}
)
What I wanted to do is to inject MyComponent dynamically from a configuration file - analog Guice Modules.
The whole scenario is described in this Blog.
I can inject a dependency and then create the Environment like:
program.provide(
new Console.Live with Components.Live {
def compsService: Components.Service[Console] = service
}
)
Where service is injected.
This works but has one big disadvantage: We have to define the environment for all Service implementations. So for example if one of them wants to use Random, it is not possible, as we only provide Console.
Is there an alternative to this?
As an idea to solve this problem you could check this concept. Maybe sometimes i'll write library but i feel like it's enough to get idea.
https://gist.github.com/holinov/50fbf349fcb9f6e6c2b89ce319c20bba
If you could wrap injector creation in RIO[Config, Injector] and injection in RIO[Injector, Service] it could fit your needs
Related
In typical first example about using the reader monad for dependency injection we have:
this like the classic https://github.com/hermannhueck/composing-functions/blob/master/src/main/scala/demo/Demo08bDbReader.scala
Generally at the core of it is the idea of returning a function that takes as parameter the very thing we want to inject e.g.
trait UserService {
def getUserbyId(id: String): UserRepo => User
}
I have seen several baby example here and there and they all work proper for the purpose of explaining the main idea.
However i am having a hard time translating that for a real world example where you actually have a Repo that actually connect to a DB.
Indeed, in that scenario, the Account Repo itself depend on something else which is either a DB Connection or an Emvconfig from which the DB connection is created.
This also means that every method of the UserRepo will depend on that DB connection or EnvConfig. If a constructor injection is not used for that repo, then all the methods of the UserRepo will need it too which can escalate back to to whatever Service that call the UserRepo.
Am I missing something here ? I must be otherwise i do not understand the all buzz around it.
Can someone explain what i am missing here ?
I am new to dagger and I am searching for how can we implement functionality like spring profiles in dagger-2.x. I want different beans for my devo and prod environments, but I am using dagger framework with Java.
#Provides
#Singleton
public void providesDaggerCoffeeShopClient(Stage stage) {
DaggerCoffeeShop.builder()
.dripCoffeeModule(new DripCoffeeModule())
.qualifier(stage)
.build();
}
Here, I want to skip this bean creation if stage is "Devo". Any help will be appreciated.
Well. I have met this question 2 days ago. And since performed research about this matter. I was looking for a solution that would allow me to be able to run application with different profiles passed as a system property on the application run like:
java -Denv=local-dev-env -jar java-app.jar
The only appropriate solution I was able to find is to follow the oficial documentation testing guide:
https://dagger.dev/dev-guide/testing
and devide my one module into different modules, in particular I had to separate and substitute data base dependency when I want to run my app locally avoiding connection to real DB and executing any command against real DB.
And when I run my app I perform check on system property like:
public boolean isLocalDevEnv() {
return Environments.LOCAL_DEV.envName.equals(System.getProperty("env", Environments.PRODUCTION.envName));
}
and if the system property DOES NOT contain the property I am looking for, then I
create the PRODUCTION instance of my component (that is configured to use production modules):
DaggerMyAppComponent.create()
Which approximately looks like:
#Component(modules = {MyAppModule.class, DaoModule.class})
#Singleton
public interface MyAppComponent {...}
otherwise, I create loca-dev-env version of the component that uses the version of the module that produces mock of Dao that would be creating real connection to real Data Base otherwise:
DaggerMyAppLocalDevEnvComponent.create()
Which approximately looks like:
#Component(modules = {MyAppModule.class, DaoMockModule.class})
#Singleton
public interface MyAppLocalDevEnvComponent {...}
Hope it was clear, so just think of Spring Profiles for dagger 2 from the perspective of system properties and programmatic decision making. This approach definitely requires ALOT of boilerplate code in comparison to Spring's Profiles implementation, but it is the only viable approach I was able to come up with.
Hope it helps.
This might be a special use case that I am dealing with here. Here is what my simple C# NUnit test that uses Moq looks like
Mock<ISomeRepository> mockR = new Mock<ISomeRepository>();
mockR.Setup(x => x.GetSomething).Returns(new Something(a=1,b=2);
--use the mocked repository here
Now later in this same unit test or another test case I want to invoke the real implementation of the method GetSomething() on this mockR object.
Is there a way to do that? My repository is Singleton at its heart. So even if I create a new object, the GetSomething method still returns the same Moq'd object.
That would largely depend on your implementation of that GetSomething, which is something you're not showing here ;). Also, I'm not sure that's even a valid setup, shouldn't there be a .Setup(..).Returns(..) there?
Mocks are used to represent dependencies of a class allowing that class to be tested without using their actual dependencies. Or you can do tests which involve the actual dependencies.
But using a mocked dependency and the real dependency within the same unit test sounds like you're not clear what your test is testing.
If it's another test case, it shouldn't be a problem either. Each test should not impact another, so if you set up the class under test separately that should be fine, even with a singleton.
I'm assuming that you're injecting the singleton dependency. If not, do that.
In the silhouette implementation example found here, how in the template is the implicit 'env' value (of type Environment[User, CachedCookieAuthenticator]) used in line 28 of /app/controllers/SignUpController.scala, for example, defined using Guice?
I guess I do not understand how provideEnvironment in app/utils/di/SilhouetteModule.scala is used to "inject" the Silhouette Enviroment into SignUpController (for example) via the "injector" created in line 24 of app/Global.scala. I don't see provideEnvironment being used anywhere in the play-silhouette-slick-seed example, so I can't seem to figure out what values are given to its arguments (such as userService, authenticatorService etc).
This example of silhouette module use Guice for scala Dependency Injection framework. All bindings are configured in util.di.SilhouetteModule.scala file. There is another example where Dependency Injection is replaced by Cake pattern. look at this
[edited]In short:
If you look at the Global.scala file, you'll find the guice configuration. Guice is forced to create every controller. Every view is dependend on controllers and will be managed by guice too.
The SilhouetteModule.scala file, as was mentioned above, is for configuration Silhouette module. There are few methods annotated with #Provides. If you look at the Guice documentation. Such method is called by Guice every time it needs class type the method returns, for instance: each time guice need to inject Environment[User, CachedCookieAuthenticator] it call def provideEnvironment method because this method return such type.
Typesafe Config documentation and library examples make a point that type safety can be achieved by making a configuration object or nested objects with getter methods mapped to Config.getType(key) methods.
If I wrap config calls in something like this:
class MyConfig (cfg:Config) {
val language = cfg.getString("app.language")
val database = new {
val url = cfg.getString("db.url")
val port = cfg.getInt("db.port")
...
}
}
I can do decent looking calls like config.database.url. Neat. (That dot looks so much greater than underscore)
What I don't quite get is how to allow modifying properties and saving them - quoting documentation, config is immutable. My attempts so far turned into either a gross spaghetti (closures with var config) or horrendous boilerplate (modifying a plain object and creating a new config from it to save), so I turned here for help.
I'd appreciate if someone showed me a good pattern for programmatically modifiable configuration using Typesafe Config.
It is possible that Typesafe Config just isn't a right tool for the job. I have little use for it's powerful merging and inheritance capabilities, instead I mostly need a simple, concise, unicode-friendly and type-safe way to load and store properties. I already do have one, a reflection-based java lib working with annotated POJOs. Doesn't seem to be a lot of variety with configuration libraries in Scala. I may have been too eager to throw away my trusty java tools.