Multiple bindings to the same provider instance with Guice - java

I have two interfaces A and B and B is extending A.
I have one provider being able to provide instances whose Class is implementing B (and consequently A).
I would like to bind Provider to B.class (straightforward) and to A.class with an Annotation in a singleton scope.
bind(B.class).toProvider(MyBImplProvider.class).in(Scopes.SINGLETON);
bind(A.class).annotatedWith(Names.named("B")).toProvider(MyBImplProvider.class).in(Scopes.SINGLETON);
How to return the same instance from the provider no matter if I inject through B.class or through A.class+Annotation. For instance, I'd like to be able to define constuctors as
#Inject
C(B param)
or
#Inject
C(#Named("B") param)
In both case, I'd like param to be valuated with the same singleton.

How about making your A Provider depend on the B provider you've defined above?
#Provides
#Named("B")
A provideA(Provider<B> bProvider) {
return bProvider.get();
}
That should work since you said B extends A. You might need to play around with the #Named bit.
Another option would be to use a toInstance(yourObject) binding. But this makes it messy to inject any dependencies into that object. You would have to use Binder#requestInjection().

Related

Injecting #EJB into explicitly created object -> NullPointerException

I am trying to figure out how object instantiation works in Java EE. I have noticed that I get a NullPointerException if I try to access a member that is supposed to be injected through #EJB if the Class defining the member has been instantiated explicitly by me rather than the container. My conclusion is that even if a bean is marked to be managed it is not if one doesn't let the container instantiate it. Can we make the container manage such objects?
Let's say that we have the following setup, would it be possible to instantiate (explicitly) ClassB in ClassC and have ClassB invoke a method from ClassA without throwing a NullPointerException?
#Stateless
public class ClassA {
public void bar() {
// Does something fun
}
}
#Stateless
public class ClassB {
#EJB
private ClassA A;
public void foo() {
A.bar(); // throws NullPointerException if ClassB
// is explicitly instantiated works fine
// if injected with #EJB
}
}
public class ClassC {
//#EJB // Only way to go? Can we choose an implementation of ClassB?
private ClassB B;
public ClassC() {
this.B = new ClassB(); // Bad idea? Possible??
this.B.foo();
}
}
The reason I'm looking in to it is because I in my, equivalent of, ClassA need to use an EntityManager to persist some data, at the same time my ClassB is actually an interface so I need to be able to decide at runtime which implementation to instantiate in ClassC. Maybe there are other ways of doing this?
I have noticed that I get a NullPointerException if I try to access a member that is supposed to be injected through #EJB if the Class defining the member has been instantiated explicitly by me rather than the container.
This is obvious as the dependencies are injected by the container. So if you are creating the instance and not setting any value for the dependency, then the dependency will be null. On the other hand, when instances are created by the container, it also sets the values of its dependencies.
My conclusion is that even if a bean is marked to be managed it is not if one doesn't let the container instantiate it.
Yes, that is correct. When you create the instance, the instance is therefore, not managed.
Let's say that we have the following setup, would it be possible to instantiate (explicitly) ClassB in ClassC and have ClassB invoke a method from ClassA without throwing a NullPointerException?
No, when you create the instance, the dependencies will be null.
The reason I'm looking into it is because I in my, equivalent of, ClassA need to use an EntityManager to persist some data, at the same time my ClassB is actually an interface so I need to be able to decide at runtime which implementation to instantiate in ClassC. Maybe there are other ways of doing this?
If you need to inject a specific implementation, the you can do that by specifying bean name.
#EJB(beanName="DefaultService")
private Service defautService;
#EJB(beanName="SpecificService")
private Service specificService;
Refer to this link: http://www.adam-bien.com/roller/abien/entry/injecting_different_implementations_into_an
Alternatively, if you're using CDI you can use #Qualifier
The other way to get an EJB reference if you cannot use injection is to use JNDI to look it up.
Context initialContext = new InitialContext();
ClassB b = (ClassB)initialContext.lookup("java:global/yourappname/ClassB!com.package.containing.ClassB");
Therefore you can use whatever logic you need to determine the JNDI name of the actual ClassB implementation you need and then look it up.

Does guice MapBinder expose binding key for injection?

Suppose I have class Fruit
class Fruit extends FruitBase {
#Inject Fruit(Type type) {...}
}
FruitBase injects some stuff via method injection, so Fruit has to be injected through Guice as well.
Now I need in another class to inject a Map<Type, Fruit>. So I create a MapBinder. Easiest thing to do is to create a few subclasses of Fruit for each type:
class Orange extends Fruit {
#Inject Orange() {
super(Type.ORANGE);
}
}
// and later
mapBinder.addBinding(Type.ORANGE).to(Orange.class);
But if I don't want to create a bunch of simple subclasses and instead have MapBinder inject the label I'm binding to (Type.ORANGE, Type.APPLE) into Fruit itself? So I would have:
mapBinder.addBinding(Type.ORANGE).to(Fruit.class);
mapBinder.addBinding(Type.APPLE).to(Fruit.class);
and then my injected Map will have two instances of Fruit: one with type ORANGE, and one with APPLE.
Is that possible?
I found one workaround here: https://groups.google.com/d/msg/google-guice/m-m9LiVsgSM/pKVi2EIILCsJ
but factories.get(type).create(type); just kinda smells.
You can use binding to pre created instances. Note, in this case the instances created not by injector but members of these instances will be injected anyway later.
mapBinder.addBinding(Type.ORANGE).toInstance(new Fruit(Type.ORANGE));
mapBinder.addBinding(Type.APPLE).toInstance(new Fruit(Type.APPLE));
But same instances will be shared between several injected maps, that can cause problems.

Guice assisted injection deeper down the dependency hierarchy

I want to conduct a chain of processing elements and wire them together via Guice. Let's assume the following path:
interface A implemented by class AImpl needs some input
interface B implemented by class BImpl needs A
interface C implemented by class CImpl needs B
interface D implemented by class DImpl needs C
The dependency of A can only be resolved at runtime and not at configuration time. The usual approach would be to use Assisted Injection in this case to create a factory, that takes the missing instances as parameters, just like this:
public interface AFactory {
public A createA(String input);
}
But what I actually want is something like this:
public interface DFactory {
public D createD(String inputForA);
}
I don't want to manually pass AImpl-specific dependencies through the whole hierarchy.
Is it possible to achieve this with Guice? If not, what's the best way to circumvent this problem elegantly while still retaining benefits of injection?
Cheating way: Stick input in a static variable or singleton ThreadLocal. Set it before your pipeline starts and clear it after it ends. Bind everything else through DI.
Fancy way: In A, refer to a #PipelineInput String inputString but don't bind it in your main injector. Otherwise, bind dependencies as you normally would, including referring to #PipelineInput in other pipeline-related classes. When you do need a D, get it from your implementation of a DFactory, which I'm calling PipelineRunner.
public class PipelineRunner {
#Inject Injector injector; // rarely a good idea, but necessary here
public D createD(final String inputForA) {
Module module = new AbstractModule() {
#Override public void configure() {
bindConstant(inputForA).annotatedWith(PipelineInput.class);
}
};
return injector.createChildInjector(new PipelineModule(), module)
.getInstance(D.class);
}
}
Naturally, binding attempts for A, B, C, and D will fail outside of PipelineRunner for lack of a #PipelineInput String--you'll get a CreationException when you create the injector with those unsatisfied dependencies, as you discovered--but those pipeline-based dependencies should be easy to separate into a Module that you install into the child injector.
If this feels too hacky, remember that PrivateModules are also "implemented using parent injectors", and that the whole point of dependency injection is to make a dependency like inputForA available to the whole object graph in a decoupled way.
I see three options. They depend on how often you change the input for A .
1) Bind input as a constant in your module. This works only, if you know that value before you create the Injector and never want to change the value. See bindConstant
2) Use a private submodule which binds either A or the value for input inside that module. Basically you can have two or three instance graphs with different value. See newPrivateBinder.
3) Use a Scope ala RequestScope, SessionScope, ... This way you can change the input often but you must enter/leave the scope at some point to be defined. See Custom Scopes for an example.

Using autowired beans in an object created at runtime

I have a class B which implements W interface. It has a default implementation of W's method. class C and D override default implementation for which they need a service whose bean is instantiated by spring. String a and b comes from user and hence there is no way I can create a bean of B/C/D in advance. So I have a factory which creates a new object based on user parameters (it will create B/C/D based on parameters). Is there any clean way I can use service beans(aa/bb/cc/dd etc.) from inside C and D (spring autowires during server startup, at that time parameter required for instantiating B/C/D are not available) or is there any better way to solve the problem ?
Class B implements W{
String a;
String b;
B (String a, String b);
w_method(){
}
}
Class C extends B {
#Autowired
Service aa;
#Autowired
Service bb;
#Autowired
Service cc;
#override
w_method(){
}
}
Class D extends B {
#Autowired
Service dd;
#override
w_method(){
}
}
There are three possible approaches:
The fact that constructor arguments come from user doesn't mean that these objects cannot be created by Spring.
You can declare them as Spring beans of scope prototype and do the following in your factory:
public C createC(String a, String b) {
return applicationContext.getBean("c", a, b);
}
A disadvantage of this method is that your factory depends on ApplicationContext.
You can annotate these classes with #Configurable and enable AspectJ weaving. In this case Spring will configure objects of these classes even if you create them with new. See 7.8.1 Using AspectJ to dependency inject domain objects with Spring.
You can trigger autowiring manually as
applicationContext.getAutowireCapableBeanFactory().autowireBean(...);
This approach is useful when you don't have control over creation of objects that you need to autowire (servlets, etc).
I think the simplest method would be to wire the services into the factory and call setters on the B / C / D objects before you return them, rather than attempting to use #Autowired.
Or use axtavt's constructor argument method. If you want to avoid depending on ApplicationContext, you can use Lookup Method Injection, but you'll have to patch Spring per this blog post: http://nurkiewicz.blogspot.co.uk/2010/08/creating-prototype-spring-beans-on.html

CDI with unmanaged objects

Suppose that I have two classes, first a class without any properties, fields or annotations:
public class B {}
And a class which gets B injected, like this:
public class A {
#Inject
private B b;
public B getB() {
return b;
}
}
Now class A is pretty useless until we use it, so there are two options:
#Inject it
Construct it manually, using the trusty "new A()"
If A gets injected, CDI manages it and is kind enough to inject B which has the implicit scope of #Dependent. Cool, just what I want.
However, if I manually construct A (let's say in a factory or a builder), CDI completely ignores my object and won't inject an object of type B.
Example I'm talking about when it doesn't work, here object a will always remain null:
public class Builder {
#Inject
private A a;
public static Builder ofTypeSomething() {
// do some magic here
return new Builder();
}
private Builder() {
// and some more here
}
}
Why doesn't this work?
Class A is a valid managed bean and has a valid scope, just like class B. Even if I add #Producer to the static method, it won't change anything (which is fine, cause the idea of the static method is to call it, not to inject Builder anywhere).
Dependency injection, while useful, is not magical. The way DI works is that when you ask the container for an instance of an object the container first constructs it (via new()) and then sets the dependencies (how this happens depends on your framework).
If you construct the entity yourself then the container has no idea you've constructed the entity and can't set the dependencies of the entity.
If you want to use a factory then most frameworks have some way of configuring the entity so that the container knows to make a static factory method call and not call the constructor of the entity. However, you still have to obtain your entity from the container.
Edit: This site seems to demonstrate how to use a factory in CDI.

Categories

Resources