Dagger2 Basics - Field Injection - Not working - java

I am trying to do Field Injection using Dagger2. I realize I need to call inject manually in case of method injection. I am primarily trying to inject an Engine for a Car. The Engine is decided at runtime, and injected.
The data goes like this
CarInterface
import dagger.Binds;
public interface Car {
public void run();
}
Car Implementation
public class Volkswagen implements Car {
#Inject
public Engine engine;
public void run() {
System.out.println("About to Run");
engine.start();
}
}
Engine Interface
public interface Engine {
public String start();
}
Engine Implementation
public class Ferrari4Cylinder implements Engine {
#Override
public String start() {
return "Ignition----Vroom-- Vroom-- Sweet Purring Sound";
}
}
Car Module
public class CarModule{
#Provides #Singleton
Car provideCar(){
return new Volkswagen();
}
}
Engine Module
#Module
public class EngineModule {
#Provides #Singleton
public Engine provideEngine(){
return new Ferrari4Cylinder();
}
}
Component Class
#Singleton
#Component(modules = {CarModule.class, EngineModule.class})
public interface MyCarComponent {
public Car provideCar();
void inject(Car car);
}
Main Method
public class Main {
public static void main(String[] args) {
MyCarComponent carComponent= DaggerMyCarComponent.builder().build();
Car car = carComponent.provideCar();
carComponent.inject(car);
car.run();
}
}
For some reason :
The Car.run() Method always returns null, as the Engine is never Injected.
Exception in thread "main" java.lang.NullPointerException
Can anybody help out on what is happenning here?
Update 9/02/2016 :
I figured out that the following changing the component to point to the actual implementation works as shown below. Not sure why the other one does not, but it helped me move forward on the issue.
#Singleton
#Component(modules = {CarModule.class, EngineModule.class})
public interface MyCarComponent {
public Volkswagen provideCar();
void inject(Volkswagen car);
}
Hope this helps folks trying to solve the Field Injection issues in Dagger.

You need to annotate your Engine field with #Inject. I also believe you'll
need to provide the implemented class (Volkswagen as opposed to just Car) to your inject method.
public class Volkswagen implements Car {
#Inject public Engine engine;
public void run() {
System.out.println("About to Run");
engine.start();
}
}
--
#Singleton
#Component(modules = {CarModule.class, EngineModule.class})
public interface MyCarComponent {
public Car provideCar();
void inject(Volkswagen car);
}

It seems you forgot to add the EngineModule to the MyCarComponent.
In order to do field injection you should add the #Inject annotation on the Engine in the Car class. But it is encouraged to avoid field injection if possible. Instead consider doing this:
public class Volkswagen implements Car {
private final Engine engine;
public Volkswagen(Engine engine) {
this.engine = engine;
}
}
Then in CarModule
#Provides
#Singleton
static Car provideCar(Engine engine) {
return new Volkswagen(engine);
}
Also, this way you don't need the inject method on the component interface.
Remember to add the EngineModule to the component, so that dagger can provide an Engine.

Related

Inject a backend and a frontend instance into the Game class from the Main class with Dependency Injection

I will simplify the code to make my question easier to understand. The code is something like that:
import sample.backend.*;
import sample.frontend.*;
public class Game {
public void run(){
GameBackendImpl gameBackend = new GameBackendImpl();
GameUIImpl gameUI = new GameUIImpl();
}
}
And this next would be my main code, which I have separated for easy testing.
public class Main {
public static void main(String[] args) {
Game game = new Game();
game.run();
}
}
My question here is to know if it is possible to inject a backend and a frontend instance into the Game class from the Main class, using dependency injection.
Thanks in advance
In this simplified case the dependency injection means just creating the instances of the classes you need in the main() method and passing them to the constructor of the Game class:
public class Game {
privat final GameBackend backend;
privat final GameUI ui;
public Game(GameBackend gameBackend, GameUI gameUI) {
this.backend = gameBackend;
this.ui = gameUI;
}
public void run(){
...
}
}
Main class:
public class Main {
public static void main(String[] args) {
GameBackend gameBackend = new GameBackendImpl();
GameUI gameUI = new GameUIImpl();
Game game = new Game(gameBackend, gameUI);
game.run();
}
}
But this approach, of course, doesn't bring the advantages of the Dependency Injection/Inversion of Control.
I guess you are looking for the possibility to inject your dependencies automatically and to be able to configure them according to your needs (different implementations for different environments etc.). In this case you can use a framework like Spring which will take control on the program flow, instantiating and injecting the dependencies into corresponding classes.
The simple implementation using Spring Boot would be the following:
GameBackend.java:
public interface GameBackend {
String getVersion();
}
GameUI.java:
public interface GameUI {
String getVersion();
}
GameBackendImpl.java:
#Component
public class GameBackendImpl implements GameBackend {
#Override
public String getVersion() {
return "Backend_v1";
}
}
GameUiImpl.java:
#Component
public class GameUiImpl implements GameUI {
#Override
public String getVersion() {
return "UI_v1";
}
}
Game.java:
#Component
public class Game {
private final GameBackend backend;
private final GameUI ui;
#Autowired
public Game (GameBackend backend, GameUI ui) {
this.backend = backend;
this.ui = ui;
}
public void run() {
System.out.println("Game bean instantiated with the UI '"+this.ui.getVersion()+"' and Backend '"+this.backend.getVersion()+"' versions");
}
}
SpringBootDemoApp.java:
#SpringBootApplication
public class SpringBootDemoApp implements CommandLineRunner {
#Autowired
ApplicationContext applicationContext;
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApp.class, args);
}
#Override
public void run(String... args) {
((Game)(applicationContext.getBean("game"))).run();
}
}
What happens here:
Spring scans classes in the package and finds Beans annotated with the #Component annotation.
Upon instantiating the Game class, Spring considers its constructor, which is annotated with #Autowired and requires exactly 2 parameters (dependencies), and looks for the candidates to be injected. In this case there is only one candidate per each type (you can create multiple different implementations of the GameBackend and GameUI interfaces). Thus, all the preparation work is done by the framework.
There is much more happening under the hood of course.
In the main class, we can check the result by getting the instance of the Game class (Bean with the name "game) from the ApplicationContext. Calling its run() method will print:
"Game bean instantiated with the UI 'UI_v1' and Backend 'Backend_v1' versions"
NOTE: getting and using the instance of the Game class from the main class doesn't bring any advantages and is done only for the demonstration.
There are more DI/IoC frameworks for Java (CDI in J2EE, Guice etc.)

Alternative to #Qualifier in spring boot

I have this scenario
team A is implementing an interface Vehicle as ClassAVehicle
team B is implementing a dashboard service in which it uses vehicle implementation
Now team A have new implementation of Vehicle as ClassBVehicle. And team B wants to use it. One way I know is that use of #Qualifier annotation. But for this I require to change team B's code.
So do I have tight coupling here? Can I have some XML based configuration so that team B's code resolves new ClassBVehicle instance automatically?
interface Vehicle{
int getNoTyre();
}
class ClassAVehicle{
int getNoTyre(){
return 1;
}
}
class ClassBVehicle{
int getNoTyre(){
return 2;
}
}
class Dashboard{
// Here everything is fine until classBVehicle is not there
// Now I want to use new classBVehicle.
// One way I see is that using #Qualifier but will it not be tight coupling?
#Autowired
Vehicle oldAInstance;
}
If you use xml to define bean, your way is good to decouple. Another way is that you can use ApplicationContext to get bean dynamically in annotation program. There are two way to getBean with beanName or beanClass. The below is sample:
#Service
public class BService {
private Vehicle vo;
#Autowired
ApplicationContext context;
public void getVehicle(String beanName){
this.vo = (Vehicle) context.getBean(beanName);
}
public void getVehicle(Class beanClz){
this.vo = (Vehicle) context.getBean(beanClz);
}
public void print(){
System.out.println("---class is "+vo.getClass());
}
}
public interface Vehicle {
}
#Component
public class OneVehicle implements Vehicle{
}
#Component
public class TwoVehicle implements Vehicle{
}
#SpringBootApplication
public class SpringDependenciesExampleApplication implements ApplicationRunner {
#Autowired
BService bService;
public static void main(String[] args) {
SpringApplication.run(SpringDependenciesExampleApplication.class, args);
}
#Override
public void run(ApplicationArguments applicationArguments) throws Exception {
bService.getVehicle("oneVehicle");
bService.print();
}
}
// output is ---class is class OneVehicle

Dagger field injection not working with simple java classes

I am trying field injection with dagger although constructor injection is working absolutely fine but i don't know what is wrong with field injection. May be I am doing wrong. I am adding the code snippets. I am getting null pointer exception on engine.start() because the engine dependency is not fed. It is similar to A->B->C dependencies where A->B is fed but B->C is not. Its been long I am unable to resolve.
package com.raghav.java.car;
import javax.inject.Inject;
public class App
{
#Inject
Car car;
App() {
DaggerCarComponent.create().inject(this);
}
public static void main( String[] args )
{
App app = new App();
app.perform();
}
private void perform() {
car.run();
}
}
public interface Engine {
void start();
}
class FordEngine implements Engine {
public void start() {
System.out.println("Engine started -- Vroom Vroom");
}
}
public interface Car {
void run();
}
class MarutiCar implements Car {
#Inject
Engine engine;
public void run() {
engine.start();
System.out.println("WOW!! Maruti Running ");
}
}
#Singleton
#Component(modules = {CarModule.class})
public interface CarComponent {
void inject(App app);
}
#Module
class CarModule {
#Singleton
#Provides
public Car provideCar() {
return new MarutiCar();
}
#Singleton
#Provides
public Engine provideEngine() {
return new FordEngine();
}
}
if you want to do nested injection you need to use constructor injection otherwise that wont happen automatically because when you provide a dependency out of Dagger style (through constructor injection or argument injection in module) dagger has no idea about that. change your classes like below:
change your MarutiCar like this:
class MarutiCar implements Car {
Engine engine;
#Inject
public MarutiCar(Engine engine)
{
this.engine = engine;
}
public void run() {
engine.start();
System.out.println("WOW!! Maruti Running ");
}
}
and your FordEngine class like this:
class FordEngine implements Engine {
#inject
public FordEngine()
{
}
public void start() {
System.out.println("Engine started -- Vroom Vroom");
}
}
then change your CarModule like below:
#Module
class CarModule {
#Singleton
#Provides
public Car provideCar(MarutiCar marutiCar) {
return marutiCar;
}
#Singleton
#Provides
public Engine provideEngine(FordEngine fordEngine) {
return fordEngine;
}
}
UPDATE: DAGGER WONT INJECT FIELDS OF A CLASS THAT IS NOT CREATED BY ITSELF.
you are creating the MarutiCar instance by your self how you expect dagger to know what it needs ? you can start a new chain of dagger creation in that class to achieve this which is a weird thing to do.
you need to tell dagger what you need by showing dependencies through constructor or module method argument so that dagger instantiate them for you to know what they need. dagger doesnt provide your nested dependencies injected fields because it hasnt created them so it has no idea about their dependencies, unless you start another chain of dagger creation like what you did in your App class.
there is another way if you dont want to use constructor injection which i only show this for you Car and MarutiCar class:
#Module
class CarModule {
#Singleton
#Provides
public Car provideCar(Engine engine) {
MarutiCar marutiCar = new MarutiCar(engine);
}
#Singleton
#Provides
public Engine provideEngine(FordEngine fordEngine) {
return fordEngine;
}
}
and the MarutiCar class would be like this (no need for #inject)
class MarutiCar implements Car {
Engine engine;
public MarutiCar(Engine engine)
{
this.engine = engine;
}
public void run() {
engine.start();
System.out.println("WOW!! Maruti Running ");
}
}

Dagger 2 Null field injection

Hi I've read through other posts but I am not being able to fix it. Basically my issue is that I call .inject and when I want to use the field it's still null.
I have this class:
public class Application extends Game implements IApplication {
#Inject IApplication app;
#Inject IRouter router;
public Application(IPlatformCode platformCode) {
}
#Override
public void create() {
initDagger();
System.out.println(app); //NULL
System.out.println(router); //NULL
router.showPage(Page.MenuPage); //NULL EXCEPTION
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 0.5f, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
super.render();
}
#Override
public void setPage(IPage page) {
setScreen(page);
}
protected void initDagger() {
ApplicationComponent.Initializer.init(this).inject(this);
RouterComponent.Initializer.init().inject(this);
}
}
I won't show the router because I'm doing the same in app.
My Application component looks like this:
#Singleton
#Component ( modules = {ApplicationModule.class })
public interface ApplicationComponent {
void inject(IApplication application);
IApplication getApplication();
static final class Initializer {
private Initializer(){}
public static ApplicationComponent init(IApplication app) {
return DaggerApplicationComponent
.builder()
.applicationModule(new ApplicationModule(app))
.build();
}
}
}
And this is the module:
#Module
public class ApplicationModule {
private IApplication app;
public ApplicationModule(IApplication app) {
this.app = app;
}
#Provides
#Singleton
public IApplication providesApplication(){
return app;
}
}
As far as I read after calling inject(IApplication) the #Inject IApplication should be injected and have a value but right now it's null.
The generated code looks like this:
public final class DaggerApplicationComponent implements ApplicationComponent {
private Provider<IApplication> providesApplicationProvider;
private DaggerApplicationComponent(DaggerApplicationComponent.Builder builder) {
assert builder != null;
this.initialize(builder);
}
public static DaggerApplicationComponent.Builder builder() {
return new DaggerApplicationComponent.Builder();
}
private void initialize(DaggerApplicationComponent.Builder builder) {
this.providesApplicationProvider = DoubleCheck.provider(ApplicationModule_ProvidesApplicationFactory.create(builder.applicationModule));
}
public void inject(IApplication application) {
MembersInjectors.noOp().injectMembers(application);
}
public IApplication getApplication() {
return (IApplication)this.providesApplicationProvider.get();
}
public static final class Builder {
private ApplicationModule applicationModule;
private Builder() {
}
public ApplicationComponent build() {
if(this.applicationModule == null) {
throw new IllegalStateException(ApplicationModule.class.getCanonicalName() + " must be set");
} else {
return new DaggerApplicationComponent(this);
}
}
public DaggerApplicationComponent.Builder applicationModule(ApplicationModule applicationModule) {
this.applicationModule = (ApplicationModule)Preconditions.checkNotNull(applicationModule);
return this;
}
}
}
Thanks in advance.
Your inject method
void inject(IApplication application);
needs to change to
void inject(Application application);
Note the change from IApplication to just Application. You can't use interfaces for inject methods, you need to use a class.
Typically, Dagger 2 component creation is done in a class extending one of Android's Application classes. This is primarily done to ensure that these components (and the dependencies they house) are only instantiated once. (see Dagger docs for more details: https://google.github.io/dagger/users-guide)
While I haven't seen anything that says you can't wire it up differently, I haven't found an example of it, either. I'm wondering if trying to wire the components on-the-fly with the Initializer.init() calls you're making is somehow bypassing Dagger's ability to setup Components for injection correctly. Would it be possible to refactor the instantiation of the Component classes into an Application implementation instead?
The code above looks like it should work (outside of getting a new DaggerApplicationComponent instance with every init() call instead of a Singleton), I can't really explain why it doesn't.

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.

Categories

Resources