Java – Guice constructor injection without OUT annotations?

Guice constructor injection without OUT annotations?… here is a solution to the problem.

Guice constructor injection without OUT annotations?

Can someone help implement Guice without OUT comments?

public interface IAnimal {
  void makeNoise();
}

public interface IVehicle {
  int getWheelCount();
}

import org.apache.commons.logging.Log;
public class Car implements IVehicle {

private Log Logger;

public Car(Log lgr) {
        this. Logger = lgr;
    }

public final int getWheelCount() {
      this.Logger.info("getWheelCount is returning 4");
      return 4;
    }
}

import org.apache.commons.logging.Log;
public class Dog implements IAnimal {

private Log Logger;

public Dog(Log lgr) {
        this. Logger = lgr;
    }

public final void makeNoise() {
        this.Logger.info("Bark Bark Bark");
    }
}

pom.xml

    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.3</version>
    </dependency>

<dependency>
        <groupId>com.google.inject</groupId>
        <artifactId>guice</artifactId>
        <version>4.2.0</version>
    </dependency>

I tried :

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.google.inject.*;

public class App {

public static void main(String[] args) {

Log localLogger = 
        LogFactory.getLog(App.class);

Injector injector = Guice.createInjector();

IVehicle veh = injector.getInstance(Car.class);  
    int wc = veh.getWheelCount();

IAnimal amh = injector.getInstance(Dog.class);  
    amh.makeNoise();
  }
}

The error I get is:

Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.

I misunderstood.

But I wish I could “point” Guice at the correct constructor… Instead of using comments.

As you can see, using the default/null constructor is not a good choice because this example is simple, but I want to stick with constructor-based injection (inject).

Append:

Based on the “tip” I got from Hemant Singh in the comments, I think I’m closer.

I created a ProductionInjectModule that it uses

bind(MyInterface.class).toConstructor(MyConcrete.class.getConstructor(org.apache.commons.logging.Log.class));

But even if I “force” this by pointing to a specific constructor (using “toConstructor”)… I still get:

Classes must have either one (and only one) constructor annotated with
@Inject or a zero-argument constructor that is not private.

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Below is the complete “module” code:

public class App {

public static void main(String[] args) {
    runGuice();

}

private static void runGuice() {
    Log localLogger = LogFactory.getLog(App.class);

ProductionInjectModule pm = new ProductionInjectModule(localLogger);
    Injector injector = Guice.createInjector(pm);
    Injector injector = Guice.createInjector();
     injector.injectMembers(localLogger);

IVehicle veh = injector.getInstance(Car.class);
    int wc = veh.getWheelCount();

IAnimal amh = injector.getInstance(Dog.class);
    amh.makeNoise();
  }

}

import com.google.inject.AbstractModule;
import com.google.inject.Module;

public class ProductionInjectModule extends AbstractModule implements Module {
   public void configure(Binder binder) {
   binder.bind(IVehicle.class).to(Car.class);
   binder.bind(InterfaceB.class).to(ConcreteB.class);
   binder.bind(InterfaceC.class).to(ConcreteC.class);
  // }

private final org.apache.commons.logging.Log Logger;

public ProductionInjectModule(org.apache.commons.logging.Log concreteLogger) {
    this. Logger = concreteLogger;
  }

@Override
  protected void configure() {
    try {
      bind(org.apache.commons.logging.Log.class).toInstance(this. Logger);
      bind(IVehicle.class).toConstructor(Car.class.getConstructor(org.apache.commons.logging.Log.class));
      bind(IAnimal.class).toConstructor(Dog.class.getConstructor(org.apache.commons.logging.Log.class));
    } catch (NoSuchMethodException e) {
      addError(e);
    }
  }

}

Following the same tips, I found some documentation to back it up:

From: http://www.baeldung.com/guice

You can also inject a dependency that doesn’t have a default no-arg
constructor using constructor binding:

>     public class BasicModule extends AbstractModule {
>   
>     @Override
>     protected void configure() {
>         bind(Boolean.class).toInstance(true);
>         bind(Communication.class).toConstructor(
>           Communication.class.getConstructor(Boolean.TYPE)); } 
The snippet above will inject an instance of Communication using the

constructor that takes a boolean argument. We supply the true argument
to the constructor by defining an untargeted binding of the Boolean
class.

This untargeted binding will be eagerly supplied to any constructor in
the binding that accepts a boolean parameter. With this approach, all
dependencies of Communication are injected.

Another approach to constructor-specific binding is the instance
binding, where we provide an instance directly in the binding:

>     public class BasicModule extends AbstractModule {
>   
>     @Override
>     protected void configure() {
>         bind(Communication.class)
>           .toInstance(new Communication(true));
>     }     }

Summer 2019 Addendum:

It would be wiser to use “slf4j” instead of “org.apache.commons”

org.slf4j.Logger 
and
org.slf4j.LoggerFactory.getLogger(MyClass.class);

and

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.25</version>
</dependency>

Why?

https://www.slf4j.org/codes.html#multiple_bindings

Embedded components such as libraries or frameworks should not declare
a dependency on any SLF4J binding but only depend on slf4j-api. When a
library declares a compile-time dependency on a SLF4J binding, it
imposes that binding on the end-user, thus negating SLF4J’s purpose.
When you come across an embedded component declaring a compile-time
dependency on any SLF4J binding, please take the time to contact the
authors of said component/library and kindly ask them to mend their
ways.

Solution

I understand! My “Attach:” area in the original question is close! But now I see my little mistake.

My ProductionInjectModule above is correct.

My “ask to solve” is wrong.

Note that in my getInstance, I still have specifics.

I need this: (emphasis on getInstance arguments).

IVehicle veh = injector.getInstance(IVehicle.class);
int wc = veh.getWheelCount();

IAnimal amh = injector.getInstance(IAnimal.class);
amh.makeNoise();

Complete working code: (with interface and content above).

public class App {

public static void main(String[] args) {
    runGuice();

}

private static void runGuice() {
    Log localLogger = LogFactory.getLog(App.class);

ProductionInjectModule pm = new ProductionInjectModule(localLogger);
    Injector injector = Guice.createInjector(pm);

IVehicle veh = injector.getInstance(IVehicle.class);
    int wc = veh.getWheelCount();

IAnimal amh = injector.getInstance(IAnimal.class);
    amh.makeNoise();
  }

}

import com.google.inject.AbstractModule;
import com.google.inject.Module;

public class ProductionInjectModule extends AbstractModule implements Module {

private final org.apache.commons.logging.Log Logger;

public ProductionInjectModule(org.apache.commons.logging.Log concreteLogger) {
    this. Logger = concreteLogger;
  }

@Override
  protected void configure() {
    try {
      bind(org.apache.commons.logging.Log.class).toInstance(this. Logger);
      bind(IVehicle.class).toConstructor(Car.class.getConstructor(org.apache.commons.logging.Log.class));
      bind(IAnimal.class).toConstructor(Dog.class.getConstructor(org.apache.commons.logging.Log.class));
    } catch (NoSuchMethodException e) {
      addError(e);
    }
  }

}

Summer 2019 Addendum:

It would be wiser to use “slf4j” instead of “org.apache.commons”

org.slf4j.Logger 
and
org.slf4j.LoggerFactory.getLogger(MyClass.class);

and

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.25</version>
</dependency>

Of course, check for recent updates:

https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.slf4j%22%20AND%20a%3A%22slf4j-api%22

Why?

https://www.slf4j.org/codes.html#multiple_bindings

Embedded components such as libraries or frameworks should not declare
a dependency on any SLF4J binding but only depend on slf4j-api. When a
library declares a compile-time dependency on a SLF4J binding, it
imposes that binding on the end-user, thus negating SLF4J’s purpose.
When you come across an embedded component declaring a compile-time
dependency on any SLF4J binding, please take the time to contact the
authors of said component/library and kindly ask them to mend their
ways.

Related Problems and Solutions