Injecting components in manually created instances - java

Suppose I have something like this:
#Component(immediate = true)
public class A {}
public class B {
#Reference
public void injectA(A a) {...}
}
Is there a way to have A be injected into B if I manually create instances of B?
If not, is the only alternative to just use the service registry or is there a go-to pattern?
UPDATE:
I can't manually inject an instance of A (without using the service registry) because the code that creates instances of B doesn't have it.

Clearly you can do new B().injectA(new A()). But if you want to manually inject the A instance created by SCR, you need to get that A instance from the service registry which is where SCR makes it available.

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.

Spring task executor only creates one instance when the #Scheduled annotation is placed inside of polling class

I have a series of services that extend a base service. In this base service I instantiate a class designed to poll databases and send notifications based on their contents, the timing of this polling is handled by spring. What I expect is that there should be an instance of this poller for each service extending the base service, but depending on where I put the #Scheduled annotation, it doesn't work.
What I want is this:
public class Base {
private Poller p = new Poller(this);
// the rest of the service code
}
public class Poller{
Base b;
public Poller(Base B){
b=B;
}
#Scheduled(fixedDelay=5000)
public void poll(){
//do stuff
System.out.println(b.name); //doesn't work, causes really unhelpful errors
System.out.println("----"); //prints as expected, but only once
//regardless of how many extending services exist
}
}
but it only seems to instantiate one poller between all extenders. If I Structure it like this:
public class Base {
private Poller p = new Poller(this);
// the rest of the service code
#Scheduled(fixedDelay=5000)
public void poll(){
p.poll();
}
}
public class Poller{
Base b;
public Poller(Base B){
b=B;
}
public void poll(){
//do stuff
System.out.println(b.name); //prints the name of the service for each extender
System.out.println("----"); //prints as expected, once for each extender
}
}
it works as expected, but doesn't sit well with the design goals here.
Is there a way to get the scheduled annotation to stay in the Poller, while ensuring that each extending service gets its own instance of it?
It is because your Poller class isn't Spring managed, where Base is. Poller is instantiated with the new operator in Base, and therefore, Spring has no handle on it. If Spring isn't creating the instance, then it is not going to be Spring managed.
I think your design in general is flawed though. Your child has a reference to the base and the base to the child. To me, it seems like you may have a hard time creating multiple child classes this way.
If you want to have a base class, I would recommend one of two things.
Inheritance. Have Poller (as well as other child classes) extend Base.
Delegation. Have Base be a member of each child class, and delegate to it in the children classes.
With either one of these designs, I think you could get your code to work as you expect.

Can I combine manual instantiation with autowiring?

Ok. I am not sure how to even ask the question, which is the sign I must be missing something. The best I can do is: "Is there a way to instantiate an object manually and still use injection within that object?"
Concretely, say I have:
class A {
public A(MyObject1 obj1, MyObject2 obj2, ..., MyObjectn objn) {
...
}
}
I want to wire all of these objects except MyObjectn. As far as I know, if I use #Autowired in front of that constructor above, then I should only instantiate that object as follows in the code that uses an instance of that class:
#Autowired
A a;
which doesn't allow me to pass in objn in the constructor manually. Is there a way to get around that limitation short of manually initializing A in the code that uses an instance of that class?
Short answer - no.
You either use an IoC or you manually instantiate Objects.
One workaround that comes to my mind:
Create a Service with every MyObject1 being #Autowired
create a method inside this service:
public A createA(MyObjectN objn) {
return new A(object1, object2... objn); //note that object1 .. objectn-1 are autowired.
}
Inject the service with #Autowired ;) and call service.createA()
sunilkumar from vmoksha
NO we cant create like that

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