Guice - Inject dependency into a class with static helper methods - java

I'm still new to Guice and haven't used any DI frameworks before. After reading the official wiki and many other documents I'm still unable to wrap my head around it completely.
In my particular case I want to write a EL taglib function that uses some other (to-be-injected) class. As all taglib functions have to be declared as static, I can't just #Inject my dependency via constructor or setter. I thought of using the requestStaticInjection() method described in http://code.google.com/p/google-guice/wiki/Injections#Static_Injections but I unable to get it to work and haven't been able to find any good tutorial.
Thanks in advance for any help,
Arman

It doesn't get much more clear than that Guice documentation but here's a unit test that shows an example of how you can use static injection:
public class StaticInjectionExample {
static class SomeClass {}
static class TagLib{
#Inject
static SomeClass injected;
public static void taglibFunction(String foo) {
injected.something(foo);
}
}
static class TestModule extends AbstractModule {
#Override
protected void configure() {
requestStaticInjection(TabLib.class);
}
}
#Test
public void test() {
Injector injector = Guice.createInjector(new TestModule());
TagLib receiver = injector.getInstance(TagLib.class);
// Do something with receiver.injected
}
}

Related

Unable to call function of autowired class

I have the following classes :
Class 1:
package com.assets;
#Component
#Scope("request)
public class AssetDetailsImpl implements AssetApi
{
public void function1(){
....
}
public void function2(){
AssetUtil.test1();
}
}
Class 2:
package com.assets;
#Component
public class AssetUtil
{
#Autowired
AssetDetailsImpl impl;
//some functions
public static void test1{
impl.function1();// NPE I am getting
}
Here my auto wiring not working, its coming null. Both the classes are in the same package. Is it because of the request scope which is there in AssetDetailsImpl? I even tried with #Inject that also was not working. Can anyone please help me to resolve this? Thanks in advance!
I have tried removing the scope, but then also the same problem.
I have also tried:
AssetUtil(AssetDetailsImpl impl) {
this.impl = impl;
}
But I am not sure how to deal with the static thing then also how to invoke this constructor?
The method test1 is static.
But Spring doesn't work with static members because it creates instances of the beans.
Remove static:
public void test1{
impl.function1();
}
And now you have to make sure that the client of this method is also using autowiring to get an instance of AssetUtil
It looks to me like the issue is that the AssetDetailsImpl Component is Request-scoped, which means it comes and goes with each HTTP request, while the AssetUtil Component which is trying to use it is default-scoped, which is Application/singleton scope.
Personally, I try to use singletons as much as possible. I wouldn't use request scope for the first Component.

What is actually involved in a mvp scenario to use google guice?

I am very familiar with using spring to inject using #Bean & #Autowired. I have switched over to looking at guice and I am wondering what is the minimum involved to have it functioning. The following basic example throws a NPE:
import javax.inject.Inject;
public class ClassA {
String a = "test";
#Inject
public ClassA() {
System.out.println(a);
}
public void go() {
System.out.println("two");
}
}
The following class attempting to instantiate a new instance of ClassA:
import javax.inject.Inject;
public class ClassB {
#Inject
ClassA guice;
public ClassB() {
guice.go();
}
public static void main(String[] args) {
ClassB b = new ClassB();
}
}
I have tried all sorts of combinations of the following with no success:
public class SupportModule extends AbstractModule {
#Override
protected void configure() {
bind(ClassA.class);
//bind(ClassA.class).to(ClassB.class);
//others too
}
}
I must be missing a key thing somewhere here, I'm not quite sure where? do I need some manual instantiation of guice/configuration itself? I assume I possibly do.
guice.go(); <= NullPointerException occurs here, obviously the obj is null because my guice setup isn't right
In Spring i can do the following, I assume Guice can aid me in doing this too:
#Bean
public FrameworkProperties properties() {
return new FrameworkProperties();
}
and then just:
#Autowired
FrameworkProperties props;
do I need some manual instantiation of guice/configuration itself? I assume I possibly do.
Yes, you assumed right. You'll have to bootstrap the Injector modules that you have defined using the Guice.createInjector() method. Also, one other thing to note is when using a custom defined constructor like in ClassB, you'll have to use constructor injection. So in order to get this working, ClassB should look like:
public class ClassB {
private ClassA guice;
#Inject //This will inject the dependencies used in the constructor arguments
public ClassB(final ClassA guice) {
this.guice = guice;
guice.go();
}
public static void main(String[] args) {
/**
* If only type to type binding is required, you can skip creating a Module class &
* bootstrap the injector with empty argument createInjector like used below. But, when
* there are other kind of bindings like Type to Implementations defined in modules, you can use:
* final Injector injector1 = Guice.createInjector(new GuiceModule1(), new GuiceModule2());
*/
final Injector injector = Guice.createInjector();
final ClassB b = injector.getInstance(ClassB.class); //This will create dependency graph for you and inject all dependencies used by ClassB and downwards
}
}
Also, you can remove the #Inject annotation used in ClassA's constructor as you are not injecting any external dependencies in that constructor. You can look up the Guice's getting started wiki for more documentation.

How to inject values without explicit calls?

I'm familiar with dependency injection concepts and its benefits, but using frameworks that would handle this business for me gets kind of confusing.
This question is valid for any DI framework, but I will stick to the Guice with this question.
The problem
Let's say, I have following classes:
public interface Tea {
void prepare();
}
public class GreenTea implements Tea {
public void prepare() {
System.out.println("Preparing Green Tea");
}
}
public class BlackTea implements Tea {
public void prepare() {
System.out.println("Preparing Black Tea");
}
}
Without frameworks, in my main method, I would do something like this:
public static void main(String[] args) {
Tea tea = new GreenTea();
tea.prepare();
}
With the help of Google Guice Inject I could get futher and do something like this:
public class TeaModule extends AbstractModule {
protected void configure() {
bind(Tea.class).to(GreenTea.class);
}
}
public class Main {
#Inject
private Tea tea;
public static void main(String[] args) {
Injector injector = Guice.createInjector(new TeaModule());
Main main = injector.getInstance(Main.class);
main.tea.prepare();
}
}
Now, let's say I have some random class, which needs my tea interface injected:
public class RandomClass {
private Tea tea;
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
public Tea getTea() {
return tea;
}
#Inject
public void setTea(Tea tea) {
this.tea = tea;
}
}
Unfortunately this throws NullPointerException, because RandomClass is not aware of any injections from outside.
Solutions I found so far
1) I've read about creating custom Providers, such as:
public class TeaProvider implements Provider<Tea> {
public Tea get() {
Tea tea = new BlackTea();
return tea;
}
}
As far as I know, this solution requires creating new class in order to work:
//In main method
injector.injectMembers(new RandomClass());
2) Worse solution, is to inject injector inside RandomClass and manually asking for class instance, like so:
public class RandomClass {
#Inject
Injector injector;
private Tea tea;
public RandomClass() {
tea = injector.getInstance(Tea.class);
}
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
}
Even so, I must get RandomClass instance from injector in my bootstrapping method.
The questions
I really don't get the whole concept of DI frameworks, if they require providing classes either way.
1) Is there any possible way to inject Tea instance into RandomClass without explicitly telling injecting in bootstrapping method to do so? If possible, then how?
2) What's the pros in using DI frameworks, if I've to manually "load" all classes to inject values? I mean, I can provide new instance of some class to the dependent without using frameworks at all. Then why people would use it?
The idea behind DI frameworks is simple: A class shouldn't be responsible for instantiating its dependencies. So, though I wouldn't recommend going this far, a 100% DI solution should include zero calls to new. It should happen entirely from a factory class.
Here's your RandomClass with no DI:
public class RandomClass {
private Tea tea;
public RandomClass() {
tea = new BlackTea();
}
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
}
At this point, you should notice that it is impossible to test RandomClass without testing Tea's functionality, because you've provided no way to provide an alternative implementation.
Another way you could do it:
public class RandomClass {
private Tea tea;
public RandomClass(Tea tea) {
this.tea = tea;
}
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
}
public class RandomClassProvider {
public RandomClass create() {
return new RandomClass(new BlackTea());
}
}
Now, with DI annotations:
public class RandomClass {
private Tea tea;
#Inject public RandomClass(Tea tea) {
this.tea = tea;
}
public void doStuff() {
System.out.print("Doing stuff and.. ");
tea.prepare();
}
}
// Guice writes Provider<RandomClass> automatically.
Now you can use RandomClass manually (by calling the #Inject-annotated constructor) or automatically (just requesting an instance through Guice). This should make it easy to switch implementations, including to switch implementations only in tests to test doubles you've written or that you've created through Mockito.
A final word about providers: You shouldn't have to worry about Providers yourself: No matter how you bind an instance or provider, you can access it using #Inject X or #Inject Provider<X> anywhere in a constructor or field (or getInstance or getProvider). Inject a Provider if you're not sure you need an instance, or if you'll need more than one, and only write a Provider manually if you need to call some external method to get an instance if you need to postprocess.

Inject instance in all objects using Guice

class A {
public A() {
}
}
class B {
#Inject
#Named("A")
private A a;
public B() {
}
public A getA() {
return a;
}
}
class AModule extends AbstractModule {
#Override
protected void configure() {
}
#Provides
#Singleton
#Named("A")
public A providesA() {
return new A();
}
}
We are doing like this:
AModule module = new AModule();
Injector injector = Guice.createInjector(module);
B b = injector.getInstance(B.class);
System.out.println(sample.getA());
But we have many classes with A as dependency and we don't want to add this code every time we create an instance.
So, is there any way to auto inject instance of A while creating instance of B?
It is (usually) not correct to create as many top-level Injectors as you suggest in your question. Injector creation is expensive, and once Guice has calculated your graph of dependencies, you should not need to calculate it all over again. In general there should be one top-level Injector across your application, and any other Injectors are either "child injectors" or parts of a separate and unrelated object graph.
In order from "worst" to "best":
Keep the Injector statically
If you are introducing DI into a lot of existing or legacy code, then it may be tempting to stash the Injector into a publicly-accessible object.
public class InjectorHolder() {
private InjectorHolder() {} // Not instantiable
private static Injector injector;
public static void initializeInjector() {
injector = Guice.createInjector(new AModule(), new BModule(), andSoOn());
}
public static Injector get() {
return injector;
}
public static B getB() {
return injector.getInstance(B.class);
}
}
At this point you can call InjectorHolder.get().getInstance(B.class) or InjectorHolder.getB() from the parts of the app you've migrated so far. Note that this may be difficult to test, and relies on Guice directly from across your application—both of which are not ideal.
Use Guice static injections
Guice provides a few features for static injection, notably the method call requestStaticInjection(Class... types). With a call to that in your module, Guice will inject static members that have #Inject annotations as soon as the Injector is created.
public class StaticBModule extends AbstractModule() {
#Override public void configure() { requestStaticInjection(BFactory.class); }
}
public class BFactory() {
#Inject #Named("B") private static Provider<B> bProvider;
public B get() {
return bProvider.get();
}
}
Now you can call new BFactory().get() instead of new B(), and it'll all go to the same injector. Naturally, you could also allow new B() instead if you put a static Provider<A> into your B class and request static injection for that instead, or you could keep your BFactory as an instance and replace it during tests to issue the B instances you need. At that point, you might as well just retrofit the classes that call new BFactory() to instead include a static Provider<B>, and have them inject statically, and then migrate those, all the way up until you have a full DI solution (explained below).
You may also consult this SO question, which has an example.
Ideal solution
You've shown us A and B, but presumably some other class C uses many instances of B, and maybe YourApplication (which contains your static main method) uses C. You can use Guice to create an instance of YourApplication or C, and then C can contain an injected Provider<B> bFactory. Then, rather than call new B(), you can call bFactory.get() to create as many B instances as you might need.
This way, your classes depend on exactly what they depend on, with no static state or references to Guice other than at the top level.

Google Guice desktop application - how to make it work?

I have used Guice in my web app without problems and I wanted to use it in desktop app. I am certainly missing one thing - some way to tell my app how to bind everything and know what is what. In web app, I had declaration for that in Application class, how should I do it in my desktop app?
Here is relevant code that I am using:
public class GuiceModule extends AbstractModule
{
#Override
protected void configure()
{
// Enable per-request-thread PersistenceManager injection.
install(new PersistenceManagerFilter.GuiceModule());
// Business object bindings go here.
bind(ProjectQueries.class).to(JdoProjectQueries.class);
bind(new TypeLiteral<Repository<Project>>() { }).to(JdoProjectRepository.class);
}
My main class:
#Inject
public Repository<Project> projectRepo;
public void createNewProject() {
...
projectRepo.persist(newProject);
}
I am of course getting on projectRepo.persist(newProject);
So, what else do I have to do to make it work?
EDIT:
Ok, that part work now, thanks :) It seems that I need to do a bit more though to make persistence work that way.
I am getting NPE here now:
public void persist(T entity)
{
pmProvider.get().makePersistent(entity);
}
get() returns null here
It looks like
install(new PersistenceManagerFilter.GuiceModule());
is not enough. What do I need to do? My Repository class starts with:
public abstract class JdoRepository<T> implements Repository<T> {
private final Class<T> clazz;
private final Provider<PersistenceManager> pmProvider;
protected JdoRepository(Class<T> clazz, Provider<PersistenceManager> pmProvider) { this.clazz = clazz; this.pmProvider = pmProvider;
}
At my PMF I have:
public static class GuiceModule extends AbstractModule {
#Override protected void configure() {
bind(PersistenceManager.class).toProvider(new Provider<PersistenceManager>() {
public PersistenceManager get() {
return PersistenceManagerFilter.pm.get();
}
});
}
}
Create Bootstrap class with main method.
Move your current static main method code to non-static one. For example Application#run.
Create main method in Bootstrap class:
public static void main(String[] args) {
Injector injector = Guice.createInjector(new GuiceModule())
Application app = injector.getInstance(Application.class);
app.run();
}
Run Bootstrap class.
Any object that is created using a Guice injector will inject objects into its properties and methods. So one way will be to create an injector in createNewProject.
Injector injector = Guice.createInjector(new BeanModule(),.....
YourMainClass startClass = injector.getInstance(YourMainClass.class);
startClass.kickOfEveryThing();....
You need to at least ask one root object to the injector. This root object will be injected with objects, which will be injected with objects, etc. The the process needs to bootstrap.
See http://code.google.com/p/google-guice/wiki/GettingStarted
Injector injector = Guice.createInjector(new GuiceModule());
Main main = injector.getInstance(Main.class);

Categories

Resources