Guice Constructor Injection withOUT Annotations? - java

Can someone help with an implementation of Guice withOUT annotations?
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>
What I've 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'm getting is:
Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
I understand the error.
But I'm hoping I can "point" Guice to the correct constructor......instead of using the annotation.
As you can see, using a default/empty constructor is not a good option, as this example is simple, but I want to stick with constructor based inject.
APPEND:
Based on the "hint" I got from Hemant Singh in the comments, I think I got closer.
I created a ProductionInjectModule, that uses
bind(MyInterface.class).toConstructor(MyConcrete.class.getConstructor(org.apache.commons.logging.Log.class));
But even though I am "forcing" the issue by pointing to a specific constructor (using "toConstructor").......I'm still getting:
Classes must have either one (and only one) constructor annotated with
#Inject or a zero-argument constructor that is not private.
Gaaaaaaaaaaaaaaaaaaaaa!
Full "module" code below:
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);
}
}
}
And following the same hint, I found some documentation to support:
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 APPEND:
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.

I got it! My "APPEND:" area in the original question was close! But now I see my small mistake.
My ProductionInjectModule above was correct.
My "ask to resolve" was wrong.
Notice in my getInstance, I still had the concrete.
I needed to have this: (emphasis on the argument of the getInstance)
IVehicle veh = injector.getInstance(IVehicle.class);
int wc = veh.getWheelCount();
IAnimal amh = injector.getInstance(IAnimal.class);
amh.makeNoise();
Full working code: (with the interfaces and concretes from 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 APPEND:
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 more recent update:
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

Why does #Inject of a #Singleton in Java always result in null when using Guice?

I'm trying to implement the simplest possible Java program where a #Singleton object is injected via #Inject. However, after #Inject, the object is always null.
I realized that I need to use Guice to bind a certain behavior. I'm doing so through MyGuiceModule, which extends AbstractModule. However MyGuiceModule never got called so I had to add this line:
Injector injector = Guice.createInjector(new MyGuiceModule());
But it does not work. Here are my files:
LonelyObject
import javax.inject.Inject;
import javax.inject.Singleton;
#Singleton
public class LonelyObject {
public LonelyObject() {
System.out.println("LonelyObject Constructor");
}
public void alive() {
System.out.println("I AM ALIVE");
}
}
TheTest
public class TheTest {
// inject LonelyObject here
#Inject
LonelyObject L;
public TheTest() {
}
// use LonelyObject
public void doit() {
L.alive();
}
}
MyGuiceModule
import com.google.inject.AbstractModule;
import com.google.inject.Singleton;
import javax.inject.Inject;
public class MyGuiceModule extends AbstractModule {
#Override
protected void configure() {
System.out.println("MyGuiceModule extends AbstractModule");
// make sure LonelyObject is always instantiated as a singleton
bind(LonelyObject.class).asEagerSingleton();
}
}
main function
public static void main(String[] args) {
System.out.println("main");
// this is only here so MyGuiceModule gets called, otherwise
// it will be ignored. this seems to be the only way I can see
// to configure Guice. note that the returned Injector is not used.
Injector injector = Guice.createInjector(new MyGuiceModule());
TheTest t = new TheTest();
// crashes here with Exception in thread "main" java.lang.NullPointerException
t.doit();
}
You're bypassing Guice entirely.
Actually, the culprit is this line:
TheTest t = new TheTest();
You shouldn't create your instance yourself. Instead, ask Guice to create it for you:
TheTest t = injector.getInstance(TheTest.class);
An alternative would be to request Guice to inject the fields directly in your instance for you (but this recommended only when integrating legacy libraries):
TheTest t = new TheTest();
injector.injectMembers(t);

Guice specify modules to use for injection

In my application there are multiple modules binding something to a specific name or class. Is there a way to tell Guice, which modules it should use when resolving the dependencies to inject.
My simplified dependency graph looks something like this where blue indicates classes from module 1 and red indicates classes from module 2. Now I want to create two instances from the A class, but with different classes bound to some dependencies.
public class Module1 extends AbstractModule {
#Override
protected void configure() {
bind(C.class).to(C_Impl1.class)
bind(D.class).to(D_Impl1.class)
}
}
public class Module2 extends AbstractModule {
#Override
protected void configure() {
bind(C.class).to(C_Impl2.class)
bind(D.class).to(D_Impl2.class)
}
}
public class Application {
#Inject #UseModules(Module1, ...) private final A someClassUsingImpl1;
#Inject #UseModules(Module2, ...) private final A someClassUsingImpl2;
public void doSomethingWithImpl1() {
someClassUsingImpl1.doSomething()
}
public void doSomethingWithImpl2() {
someClassUsingImpl2.doSomething()
}
}
This is the problem private modules were built for. You will still need to use a binding annotation to differentiate whether you're asking for the Impl1 version of A or the Impl2 version of A.
/** Marks Impl1 classes. Inject #Impl1 A to get A using C_Impl1 and D_Impl1. */
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#interface Impl1 {}
/** Marks Impl2 classes. Inject #Impl2 A to get A using C_Impl2 and D_Impl2. */
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#interface Impl2 {}
/** This is now a PrivateModule. Only exposed bindings can be used outside. */
public class Module1 extends PrivateModule {
#Override
protected void configure() {
// Bind C and D as you had before.
bind(C.class).to(C_Impl1.class);
bind(D.class).to(D_Impl1.class);
// Here's the tricky part: You're binding "#Impl1 A" to
// "A" without a binding annotation, but only in here.
bind(A.class).annotatedWith(Impl1.class).to(A.class);
// Now you expose #Impl1 A, so it can be used outside.
// As long as A, C, and D are only bound within private modules,
// they won't conflict with one another, and #Impl1 A is unique.
expose(A.class).annotatedWith(Impl1.class);
}
}
/** Treat Module2 the same way, as a private module. */
public class Application {
#Inject #Impl1 private final A someClassUsingImpl1;
#Inject #Impl2 private final A someClassUsingImpl2;
// ...
}
If this is a common pattern for you, create a general PrivateModule that takes in the classes that vary as constructor parameters, so you don't need to repeat yourself. These can be added to the top-level injector, or installed within other modules.
Injector injector = Guice.createInjector(new YourMainModule(),
new ImplModule(Impl1.class, C_Impl1.class, D_Impl1.class),
new ImplModule(Impl2.class, C_Impl2.class, D_Impl2.class));

auto scan for guice

I have never used guice before, and I wanted to try it out on an example project with jersey based JAX-RS API backed by a service-bean. I followed this guide: http://randomizedsort.blogspot.de/2011/05/using-guice-ified-jersey-in-embedded.html and was able to bring it to work. My setup is very simple, a JAX-RS resource is invoked via Guice and has a field that is annotated #Inject and injected by Guice:
#Path("configuration")
#Produces(MediaType.APPLICATION_JSON)
#Singleton
public class ConfigurationResource {
#Inject
private ConfigurationService configurationService;
So far so good, everything works like it should, besides following: I am using GuiceServletContextListener for setting things up and have to name each component explicitly:
#WebListener
public class GuiceInitializer extends GuiceServletContextListener{
#Override
protected Injector getInjector() {
return Guice.createInjector(new JerseyServletModule() {
#Override
protected void configureServlets() {
//resources
bind(ConfigurationResource.class);
//services
bind(ConfigurationService.class).to(ConfigurationServiceImpl.class);
// Route all requests through GuiceContainer
serve("/management/*").with(GuiceContainer.class);
}
});
}
}
I find it pretty inconvenient to explicitly name all dependencies. I have worked with standalone jersey before and it's perfectly capable of auto-scanning for resources in defined packages. Also Spring and CDI are capable of mapping implementation to interfaces without need to explicitly name them.
Now the question part:
is there any autoscan extension/setting for guice? I found some on the internet, but it's hard to tell which of them are still useable and uptodate.
is there any other possibility to make configuration of implementations and resources more convenient?
thanks in advance.
Leon
I do not think Guice has built in support for someting like the component-scan of Spring framework. However, it is not difficult to simulate this feature in Guice.
You simply need to write a helper module like the following
import com.google.inject.AbstractModule;
import org.reflections.Reflections;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* To use this helper module, call install(new ComponentScanModule("com.foo", Named.class); in the configure method of
* another module class.
*/
public final class ComponentScanModule extends AbstractModule {
private final String packageName;
private final Set<Class<? extends Annotation>> bindingAnnotations;
#SafeVarargs
public ComponentScanModule(String packageName, final Class<? extends Annotation>... bindingAnnotations) {
this.packageName = packageName;
this.bindingAnnotations = new HashSet<>(Arrays.asList(bindingAnnotations));
}
#Override
public void configure() {
Reflections packageReflections = new Reflections(packageName);
bindingAnnotations.stream()
.map(packageReflections::getTypesAnnotatedWith)
.flatMap(Set::stream)
.forEach(this::bind);
}
}
To component scan a package like com.foo and sub packages for classes carrying #Singleton, use it in this way:
public class AppModule extends AbstractModule {
public void configure() {
install(new ComponentScanModule("com.foo", Singleton.class));
}
}

Guice: Using providers to get multiple instances:

I am trying to learn Guice for dependency Injection using Providers to create multiple instances of an object(Example from getting started guide on Guice website). how should I test this? Please advise.
The following is the module:
package testing;
import com.google.inject.AbstractModule;
public class BillingModule extends AbstractModule {
#Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(BillingService.class).to(RealBillingService.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
}
}
The following is the class under test:
package testing;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class RealBillingService implements BillingService {
private Provider<CreditCardProcessor> processorProvider;
private Provider<TransactionLog> transactionLogProvider;
#Inject
public RealBillingService(Provider<CreditCardProcessor> processorProvider,
Provider<TransactionLog> transactionLogProvider) {
this.processorProvider = processorProvider;
this.transactionLogProvider = transactionLogProvider;
}
public void chargeOrder() {
CreditCardProcessor processor = processorProvider.get();
TransactionLog transactionLog = transactionLogProvider.get();
/* use the processor and transaction log here */
processor.toString();
transactionLog.toString();
}
}
The following is the test class with main():
public class test {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BillingModule());
BillingService billingService = injector.getInstance(BillingService.class);
billingService.chargeOrder();
}
}
Upon running this, I am expecting the output from the following toString methods to show up but am seeing nothing:
processor.toString();
transactionLog.toString();
What am i missing here?
Please advise,
thanks!
This happens because you just call toString without putting the resulting string anywhere (eg the call to System.out.println)
However providers are not intended to be used like that. You should not call Provider.get yourself: instead require the result of the provider, register your provider and let Guice do its job (you can also annotate methods in your modules with #Provides instead of defining provider classes)
By default providers are called each time a new instance of a certain class is required. Instances are not recycled unless you explicitly request it via using scopes (like the builtin Singleton)

Using a custom hk2 InjectionResolver to inject application configuration

Kind of a follow up to my previous question. I'm trying to inject application configuration data using JSR-330 standard annotations and the HK2 framework bundled with jersey.
Ideally I'd like to create a custom InjectionResolver for the Named annotation, which will lookup the desired values in a Map or Properties object that I will populate from data read elsewhere. In my first attempt I've created an Application instance like
public class MyApplication extends ResourceConfig {
...
packages(MY_PACKAGES);
property(MY_CONFIG_PROPERTY, someValue);
register(new AbstractBinder() {
#Override
protected void configure() {
bind(ConfigurationInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<Named>>(){})
.in(Singleton.class)
}
});
}
and then my InjectionResolver looks like
public class ConfigurationInjectionResolver implements InjectionResolver<Named> {
#Context Application application;
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> serviceHandle) {
// lookup data in application.getProperties();
}
}
My problem is that application.getProperties() is empty. Any idea what's wrong? Also, could I bind an instance of my Injector instead of binding the class? That way I could construct the instance passing my Map data as a parameter.
"My problem is that application.getProperties() is empty. Any idea what's wrong?
No. This actually works perfectly fine for me.
public class ConfigurationInjectionResolver implements InjectionResolver<Named> {
#Context
Application application;
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> root) {
Named annotation = injectee.getParent().getAnnotation(Named.class);
Map<String, Object> props = application.getProperties();
String name = annotation.value();
System.out.println(props.get(name));
return props.get(name);
}
#Override
public boolean isConstructorParameterIndicator() { return false; }
#Override
public boolean isMethodParameterIndicator() { return false; }
}
#ApplicationPath("/rest")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("jersey.startup.test");
property("hello.config", "Hello World Property");
register(new AbstractBinder() {
#Override
protected void configure() {
bind(ConfigurationInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<Named>>() {
}).in(Singleton.class);
}
});
}
}
Resource
#Path("/config")
public class ConfigResource {
#Named("hello.config")
String hello;
#GET
public Response getHello() {
return Response.ok(hello).build();
}
}
C:\>curl http://localhost:8080/test/rest/config
Hello World Property
Personally though, in this situation, I would create my own annotation, as to not override any existing functionality of the #Named annotation.
Another cool option
HK2 has a configuration extension, where you can load a Properties object from say a .properties file and and have those properties automatically injected with the #Configured annotation. I couldn't find any documentation on this, but there is an example usage of it in the HK2 source code examples.
Here's an example implementation
Required dependencies. Check the Jersey version and see what HK2 version it depends on. In my case Jersey 2.13 uses HK2 2.3.0-b10, so that should be the ${hk2.version}
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-configuration-hub</artifactId>
<version>${hk2.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-configuration-integration</artifactId>
<version>${hk2.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-property-file</artifactId>
<version>${hk2.version}</version>
</dependency>
App config
#ApplicationPath("/rest")
public class JerseyApplication extends ResourceConfig {
#Inject
public JerseyApplication(ServiceLocator locator) {
packages("jersey.startup.test");
ServiceLocatorUtilities.addClasses(locator, ConfigResource.class);
try {
loadConfigurationProperties(locator);
} catch (IOException ex) {
Logger.getLogger(JerseyApplication.class.getName())
.log(Level.SEVERE, null, ex);
}
}
private void loadConfigurationProperties(ServiceLocator locator)
throws IOException {
ConfigurationUtilities.enableConfigurationSystem(locator);
PropertyFileUtilities.enablePropertyFileService(locator);
PropertyFileService propertyFileService
= locator.getService(PropertyFileService.class);
Properties props = new Properties();
URL url = getClass().getResource("/configuration.properties");
props.load(url.openStream());
PropertyFileHandle propertyFileHandle
= propertyFileService.createPropertyHandleOfAnyType();
propertyFileHandle.readProperties(props);
}
}
configuration.properties
AppConfiguration.App.hello=Hello Squirrel Property!
Resource
#Path("/config")
#ConfiguredBy("AppConfiguration")
public class ConfigResource {
#Configured
String hello;
#GET
public Response getHello() {
return Response.ok(hello).build();
}
}
C:\>curl http://localhost:8080/test/rest/config
Hello Squirrel Property!
Diclaimer: Since this feature isn't well documented, I am not sure if I have a good implementation here. It is just by trial and error. For instance this
ServiceLocatorUtilities.addClasses(locator, ConfigResource.class);
I feel shouldn't be necessary. It seems redundant, as I am already package scanning. So to explicitly add the ConfigResource to the locator context doesn't seem right to me.

Categories