Java Guice Named Bindings with Objects provided from other modules - java

Heres my current setup
Class file
public class ToyAdapter {
private final ToyClient toyClient;
private final Retryer retryer;
#Inject
public APIAdapter(final ToyClient toyClient,
#Named("toyRetryer") final Retryer retryer) {
this.toyClient = toyClient;
this.retryer = retryer;
}
Guice file
I have several guice modules, but this one pertains to the above class
public class ToyModule extends AbstractModule {
#Override
protected void configure() {
bind(ToyAdapter.class).in(Singleton.class);
bind(Retryer.class).annotatedWith(Names.named("toyRetryer")).toInstance(getToyRetryer());
}
#Provides
#Singleton
public ToyClient getToyClient(...){
...
}
private Retryer getToyRetryer() {#Takes no arguments
return RetryerBuilder...build();
}
}
So far this works great! However, now my retryer requires a LogPublisher object provided in another module.
I'm trying
public class ToyModule extends AbstractModule {
LogPublisher logPublisher;
#Override
protected void configure() {
requestInjection(logPublisher);
bind(ToyAdapter.class).in(Singleton.class);
bind(Retryer.class).annotatedWith(Names.named("toyRetryer")).toInstance(getToyRetryer());
}
private Retryer getToyRetryer() {
return RetryerBuilder.withLogPublisher(logPublisher).build();
}
}
LogPublisher is provided in another guice module which has alot of other objects that depend on LogPublisher so I'd rather not just merge everything into one giant guice module.
#Provides
#Singleton
public LogPublisher getLogPublisher() {...}
Is this the proper way to do this? I'm getting Java findBugs errors saying unwritten field so I'm thinking I'm doing it wrong.

Declare your Retryer with help of #Provides/#Named annotations.
#Provides
#Singleton
#Named("toyRetryer")
public Retryer getToyRetryer(LogPublisher logPublisher) {
return RetryerBuilder.withLogPublisher(logPublisher).build();
}

Related

Passing constructors for outer dependency into Guice implementation

I have a Job, which should read data from deep storage. I am using Guice DI for my project.
There is a deep store already written and coming as an outer dependencie. I am struggling with instantiating the client in Guice
Here is the code
JobModule
public class JobModule extends AbstractModule {
private Config config;
JobModule(Config config) {
this.config = config;
}
#Override
protected void configure() {
bind(Reader.class).to(DeepStoreReader.class);
}
#Provides
#Named("config")
Config provideConfig() {
return this.config;
}
}
Reader Interface
public interface Reader {
List<String> getData(String path);
}
DeepStoreReader
public class DeepStoreReader implements Reader {
private final DeepStoreClient deepStoreClient;
DeepStoreReader(#Named("config") Config config) {
this.deepStoreClient = new DeepStoreClient(config);
}
#Override
public List<String> getData(String path) {
return this.deepStoreClient.getData(path);
}
}
The issue is I don't want to instantiate DeepStoreClient inside the DeepStoreReader constructor, because it becomes difficult to test DeepStoreReader, since I won't be able to mock DeepStoreClient
What is the preferred way to instantiate a client in such cases? DeepStoreClient is not a Guice module/implementation and is coming as an outer published dependency
PS: I am new to DI and learning Guice
What you want is constructor injection, e.g.:
#Inject
public DeepStoreReader(DeepStoreClient deepStoreClient) {
this.deepStoreClient = deepStoreClient;
}
Guice will take care of instantiating the DeepStoreClient for you.
EDIT:
If DeepStoreClient itself has dependencies, you can also annotate that constructor:
#Inject
public DeepStoreClient(#Named("config") Config config) {
// ... 8< ...
}

Dagger + MVP - Problems injecting Presenter in Model

I'm having problems with the dagger dependency cycle, and despite looking for hours, I can not find the solution. I think it's my idea of architecture. What could be wrong? I'm using Dagger 2.11.
Following the codes
Inicio.java
public class Inicio extends BaseFragment implements InicioMvpView {
#Inject
InicioMvpPresenter inicioPresenter;
#Inject
MainMvpPresenter<MainMvpView> mainPresenter;
//...
InicioComponent.java
#Subcomponent(modules = {InicioModule.class})
public interface InicioComponent extends AndroidInjector<Inicio> {
#Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<Inicio> {
}
}
InicioModel.java
public class InicioModel implements InicioMvpModel{
#Inject
InicioMvpPresenter inicioPresenter;
#Inject
public InicioModel() {
}
#Override
public void recuperarAgendamentos() {
//...
inicioPresenter.atualizarListaAgendamentos(agendamentos);
}
}
InicioModule.java
#Module
public class InicioModule {
#Provides
InicioMvpView provideInicioView(Inicio inicioFragment){
return inicioFragment;
}
#Provides
InicioMvpPresenter provideInicioPresenter(
InicioPresenter presenter) {
return presenter;
}
#Provides
InicioMvpModel provideInicioModel(InicioModel inicioModel) {
return inicioModel;
}
}
InicioPresenter.java
public class InicioPresenter implements InicioMvpPresenter{
#Inject
InicioMvpModel inicioModel;
#Inject
InicioMvpView inicioMvpView;
#Inject
public InicioPresenter() {
}
#Override
public void recuperarAgendamentos(Bundle savedInstanceState) {
//..
}
}
Your problem is that you trying to solve a ciclic dependency with Dagger and Dagger doesn't solve this problem.
This can be corrected in your architecture. Just pass a callback to your model instead of passing the Presenter to the Model.
This this:
public class InicioModel implements InicioMvpModel{
#Inject
public InicioModel() {
}
#Override
public void recuperarAgendamentos(Presenter inicioPresenter) {
//...
inicioPresenter.atualizarListaAgendamentos(agendamentos);
}
}
That's it. Just pass the presenter as a parameter in your methods in your model. This makes the communication less coupled.
You can also take a look for RxJava, it removes the need to pass the presenter in the method. Link: https://github.com/ReactiveX/RxJava
There is also a good implementation to follow for MVP by Antonio Leiva:
https://github.com/antoniolg/androidmvp

How to Mock an injected object that is not declared in Module?

For a dagger2 module
#Module
public class MyModule {
#Provides #Singleton public RestService provideRestService() {
return new RestService();
}
#Provides #Singleton public MyPrinter provideMyPrinter() {
return new MyPrinter();
}
}
We could have the test module as Test
public class TestModule extends MyModule {
#Override public MyPrinter provideMyPrinter() {
return Mockito.mock(MyPrinter.class);
}
#Override public RestService provideRestService() {
return Mockito.mock(RestService.class);
}
}
However if for a class as below that is not declared in the dagger module...
public class MainService {
#Inject MyPrinter myPrinter;
#Inject public MainService(RestService restService) {
this.restService = restService;
}
}
How do I create a mock of MainService as above.
Note, I'm not planning to perform test for MainService as per share in https://medium.com/#fabioCollini/android-testing-using-dagger-2-mockito-and-a-custom-junit-rule-c8487ed01b56#.9aky15kke, but instead, my MainService is used in another normal class that I wanted to test. e.g.
public class MyClassDoingSomething() {
#Inject MainService mainService;
public MyClassDoingSomething() {
//...
}
// ...
public void myPublicFunction() {
// This function uses mainService
}
}
This is definitely not answering your question, but in my honest opinion it is related, it's helpful and too big for a comment.
I'm often facing this question and I end always doing "Constructor dependency injection". What this means is that I no longer do field injection by annotating the field with #Inject but pass the dependencies in the constructor like so:
public class MyClassDoingSomething implements DoSomethig {
private final Service mainService;
#Inject
public MyClassDoingSomething(Service mainService) {
this.mainService = mainService;
}
}
Notice how the constructor now receives the parameter and sets the field to it and is also annotated with #Inject? I also like to make these classes implement an interface (also for MyService) - Amongst several other benefits I find it makes the dagger module easier to write:
#Module
public class DoSomethingModule {
#Provides #Singleton public RestService provideRestService() {
return new RestService();
}
#Provides #Singleton public MyPrinter provideMyPrinter() {
return new MyPrinter();
}
#Provides #Singleton public Service provideMyPrinter(MyService service) {
return service;
}
#Provides #Singleton public DoSomethig provideMyPrinter(MyClassDoingSomething something) {
return something;
}
}
(This assumes that MyService implements or extends Service)
By now it seems you already know that dagger is able to figure out the dependency graph by itself and build all the objects for you. So what about unit testing the class MyClassDoingSomething? I don't even use dagger here. I simply provide the dependencies manually:
public class MyClassDoingSomethingTest {
#Mock
Service service;
private MyClassDoingSomething something;
#Before
public void setUp() throws Exception {
MockitoAnnotations.init(this);
something = new MyClassDoingSomething(service);
}
// ...
}
As you see, the dependency is passed through the constructor manually.
Obviously this doesn't work if you're coding something that doesn't have a constructor that can be invoked by you. Classical examples are android activities, fragments or views. There are ways to achieve that, but personally I still think you can somehow overcome this without dagger. If you are unit testing a view that has a field #Inject MyPresenter myPresenter, usually this field will have package access that works fine in the tests:
public class MyViewTest {
#Mock MyPresenter presenter;
private MyView view;
#Before
public void setUp() throws Exception {
MockitoAnnotations.init(this);
view.myPresenter = presenter;
}
}
Note that this only works if both MyViewTest and MyView are in the same package (which often is the case in android projects).
At the end of the day if you still want to use dagger for the tests, you can always create "test" modules and components that can inject by declaring methods in the component like:
#Inject
public interface MyTestComponent {
void inject(MyClassDoingSomething something);
}
I find this approach ok-ish, but throughout my development years I prefer the first approach. This also has reported issues with Robolectric that some setup in the build.gradle file is required to actually make the dagger-compiler run for the tests so the classes are actually generated.

Modern Akka DI with Guice

Java 8, Guice 4.0 and Akka 2.3.9 here. I am trying to figure out how to annotate my actor classes with JSR330-style #Inject annotations, and then wire them all up via Guice.
But literally every single article I have read (some examples below) either uses Scala code examples, a criminally-old version of Guice, or a criminally-old version of Akka:
Let It Crash
Scala-Guice
So, given the following Guice module:
public interface MyService {
void doSomething();
}
public class MyServiceImpl implements MyService {
#Override
public void doSomething() {
System.out.println("Something has been done!");
}
}
public class MyActorSystemModule extends AbstractModule {
#Override
public void configure() {
bind(MyService.class).to(MyServiceImpl.class);
}
}
And given the FizzActor that gets injected with a MyService:
public class FizzActor extends UntypedActor {
private final MyService myService;
#Inject
public FizzActor(MyService myService) {
super();
this.myService = myService;
}
#Override
public void onReceive(Object message) {
// .. Do fizz stuff inside here.
}
}
Then I ask: How do I rig up MyActorSystemModule to create instances of FizzActor and properly inject them with Java (not Scala!)?
Please note: FizzActor is not the only actor in my actor system!
Use Creator to create ActorRefs in provider methods of your guice module. To distinguish between the different ActorRefs, which are untyped, use annotations on your provider methods and injection points as you would any guice system. For example,
In your guice module:
#Override
protected void configure() {
bind(ActorSystem.class).toInstance(ActorSystem.apply());
bind(FizzService.class).toInstance(new FizzServiceImpl());
}
#Provides #Singleton #Named("fizzActor")
ActorRef serviceActorRef(final ActorSystem system, final FizzService fizzService) {
return system.actorOf(Props.create(new Creator<Actor>() {
#Override
public Actor create() throws Exception {
return new FizzActor(fizzService);
}
}));
}
Then to use the actor service, inject a specific ActorRef:
class ClientOfFizzActor {
#Inject
ClientOfFizzActor(#Named("fizzActor") ActorRef fizzActorRef) {..}
}
It looks cleaner if the Props.create(..) clause is a static factory method in your actor class.
Unless you are trying to bind UntypedActor to FizzActor, then you can just inject it into other classes as is:
class SomeOtherClass {
#Inject
public SomeOtherClass(FizzActor fizzActor) {
//do stuff
}
}
If you're trying to bind it to the interface, you'll need to specifically do that in the module:
public class MyActorSystemModule extends AbstractModule {
#Override
public void configure() {
bind(MyService.class).to(MyServiceImpl.class);
bind(UntypedActor.class).to(FizzActor.class);
}
}
Edit:
What about using #Named to distinguish the UntypedActor, e.g.:
class SomeOtherClass {
#Inject
public SomeOtherClass(#Named("fizzActor")UntypedActor fizzActor, #Named("fooActor") UntypedActor fooActor) {
//do stuff
}
}
Then in your module you could do the akka lookups:
public class MyActorSystemModule extends AbstractModule {
ActorSystem system = ActorSystem.create("MySystem");
#Override
public void configure() {
bind(MyService.class).to(MyServiceImpl.class);
}
#Provides
#Named("fizzActor")
public UntypedActor getFizzActor() {
return system.actorOf(Props.create(FizzActor.class), "fizzActor");
}
#Provides
#Named("fooActor")
public UntypedActor getFooActor() {
return system.actorOf(Props.create(FooActor.class), "fooActor");
}
}
Use an akka Creator:
public class GuiceCreator<T> implements Creator<T> {
Class<T> clz;
Module module;
/*Constructor*/
public T create() {
Injector injector = Guice.createInjector(this.module);
return injector.getInstance(this.clz);
}
}
Then use Props.create with your shiny new guice-based creator.
Disclaimer: I don't actually know Akka, the mentioned information comes from browsing the documentation and JavaDoc.
In case anyone found this question, you need to use IndirectActorProducer, I referred to the Spring example and changed it to use Guice instead.
/**
* An actor producer that lets Guice create the Actor instances.
*/
public class GuiceActorProducer implements IndirectActorProducer {
final String actorBeanName;
final Injector injector;
final Class<? extends Actor> actorClass;
public GuiceActorProducer(Injector injector, String actorBeanName, Class<? extends Actor> actorClass) {
this.actorBeanName = actorBeanName;
this.injector = injector;
this.actorClass = actorClass;
}
#Override
public Actor produce() {
return injector.getInstance(Key.get(Actor.class, Names.named(actorBeanName)));
}
#Override
public Class<? extends Actor> actorClass() {
return actorClass;
}
}
In the module
public class BookingModule extends AbstractModule {
#Override
protected void configure() {
// Raw actor class, meant to be used by GuiceActorProducer.
// Do not use this directly
bind(Actor.class).annotatedWith(
Names.named(BookingActor.ACTOR_BEAN_NAME)).to(
BookingActor.class);
}
#Singleton
#Provides
#Named(BookingActor.ACTOR_ROUTER_BEAN_NAME)
ActorRef systemActorRouter(Injector injector, ActorSystem actorSystem) {
Props props = Props.create(GuiceActorProducer.class, injector, BookingActor.ACTOR_BEAN_NAME, actorClass);
actorSystem.actorOf(props.withRouter(new RoundRobinPool(DEFAULT_ROUTER_SIZE)), BookingActor.ACTOR_ROUTER_BEAN_NAME);
}
}
So I have been playing around with Akka and Guice recently alot and I feel that those two don't play too well together.
What I suggest is you take a similar approach what Play is doing.
Kutschkem's answer comes closest to that.
use the ActorCreator interface
make sure you have an argumentless Creator. Don't try to do #AssisstedInject in your Creator as this will imply that you will need a new creator for every Actor that you want to create. Personally I believe that initializing this in the actor is better done through messaging.
let the ActorCreator consume an injector such that you can easily create the Actor Object within the Creator.
Here is a code example using current Akka 2.5. This is the preferred setup we chose for our Akka 2.5 deployment. For brevity I did not provide the Module, but it should be clear from the way the Members are injected, what you want to provide.
Code:
class ActorCreator implements Creator<MyActor>
#Inject
Injector injector;
public MyActor create() {
return injector.getInstance(MyActor.class);
}
}
class MyActor extends AbstractActor {
#Inject
SomeController object;
#Nullable
MyDataObject data;
public ReceiveBuilder createReceiveBuilder() {
return receiveBuilder()
.match(MyDataObject.class, m -> { /* doInitialize() */ })
.build();
}
}
class MyParentActor extends AbstractActor {
#Inject
ActorCreator creator;
void createChild() {
getContext().actorOf(new Props(creator));
}
void initializeChild(ActorRef child, MyDataObject obj) {
child.tell(obj);
}
}
Generic Akka Guice integration without dependency on Play,
keeping in mind, not the only actor should be created in the actor system.
import akka.actor.Actor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import com.google.inject.AbstractModule;
import com.google.inject.Provider;
import com.google.inject.name.Names;
public abstract class AkkaGuiceModule extends AbstractModule {
protected <T extends Actor> void bindActor(Class<T> actorClass, String name) {
bind(actorClass);
Provider<ActorSystem> actorSystemProvider = getProvider(ActorSystem.class);
Provider<T> actorProvider = getProvider(actorClass);
bind(ActorRef.class)
.annotatedWith(Names.named(name))
.toProvider(ActorRefProvider.of(actorSystemProvider, actorProvider, name))
.asEagerSingleton();
}
}
Generic ActorRefProvider to create ActorRef for each Actor
import akka.actor.Actor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.japi.Creator;
import com.google.inject.Provider;
import lombok.Value;
#Value(staticConstructor = "of")
public class ActorRefProvider<T extends Actor> implements Provider<ActorRef> {
private Provider<ActorSystem> actorSystemProvider;
private Provider<T> actorProvider;
private String name;
public final class ActorCreator implements Creator<Actor> {
#Override
public Actor create() {
return actorProvider.get();
}
}
#Override
public ActorRef get() {
return actorSystemProvider.get().actorOf(Props.create(new ActorCreator()), name);
}
}
Usage example
import akka.actor.ActorSystem;
import com.google.inject.Provides;
import com.typesafe.config.Config; // optional
public class MyAkkaModule extends AkkaGuiceModule {
#Provides
#Singleton
ActorSystem actorSystem(Config config) {
return ActorSystem.create("actor-system-name", config);
}
#Override
protected void configure() {
bindActor(SomeActor1.class, "actorName1");
bindActor(SomeActor2.class, "actorName2");
}
}

Binding #Provides method as eager singleton

I want to make a binding using a method annotated with #Provides into an eager singleton. I've found bug 216, which suggests this isn't possible, but doesn't mention the #Provides annotation explicitly.
I currently have a class that requests the eager singletons in time by itself being a singleton, but it's not a very nice solution.
public class LogicModule extends AbstractModule {
#Override public void configure() {
bind(SomeDep.class);
bind(MyWorkaround.class).asEagerSingleton();
}
// cannot add eager requirement here
#Provides #Singleton Logic createLogic(SomeDep dep) {
return LogicCreator.create(dep);
}
private static class MyWorkaround {
#Inject Logic logic;
}
}
Can I change something near the comment that would make the workaround class obsolete?
Why not to use
bind(Logic.class).toInstance(LogicCreator.create(dep));
//ohh we missing dep
then we can do this
class LogicProvider implements Provider<Logic> {
private final SomeDep dep;
#Inject
public LogicProvider(SomeDep dep) {
this.dep = dep;
}
#Override
public Logic get() {
return LogicCreator.create(dep);
}
}
and then
bind(Logic.class).toProvider(LogicProvider.class).asEagerSingleton();
You can even pass SomeDep dep to your provider as Provider<SomeDep> and then call providerDep.get() in LogicCreator.create() that would be a bit more robust.

Categories

Resources