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
Related
I am pretty new to spring or dependency injection. I have an abstract class A in a jar file built already, which is not managed by Spring (This is based on the fact that it does not have any of its dependencies auto-wired, no spring annotations used in the library.).
I have project which needs to use this class and want to inject my implementations of class A's dependency (say, of Type B). This project uses springboot.
How can I inject dependency of type B into A?
I tried following :
1. Created a configuration (#Configuration) class and added a method getB() annotated as #Bean which will return object of type B using my implementation of B.
#Bean
public B getB () {
return new MyB();
}
If you want to inject B into A you cannot. Since A is not managed by Spring, the IOC container will never inject anything in a class that he does not know.
The key to your problem is the way you want to get and use the instance of A.
If you want to use A in your code managed by spring then you have to create yourself a factory for A :
#Bean
public A a() {
B b = new MyB();
A a = new A(b); // new A is not possible since A is abstract but you got the idea
return a;
}
// ...
class MyService {
#Autowired
A a;
void something() {
(a.b instanceof MyB) // true
}
}
Having class like so:
public class A {
#Inject B b;
#Inject C c;
}
is it possible to tell Weld NOT to inject into c? I can veto A class using event:
<T> void processAnnotatedType(#Observes ProcessAnnotatedType<T> pat)
but then also B object would not be injected. I am searching for sth like: "if class name is A and field type is C then omit injection."
To be more specific I want HK2 engine to inject into the "C" field and the problem is that HK2 and Weld are both using #Inject annotation.
Siliarus solution:
I gave a try to Siliarus solution. I found the type that I want add my custom injection implementation to like:
<T> void processIT(#Observes ProcessInjectionTarget<T> pat, BeanManager beanManager) {
Set<InjectionPoint> injectionPoints = pat.getInjectionTarget().getInjectionPoints();
for (InjectionPoint injectionPoint : injectionPoints) {
if (injectionPoint.getType().equals(B.class)) {
l.info("Adding CustomInjection to {}", pat.getAnnotatedType().getJavaClass());
pat.setInjectionTarget(new CustomInjection<T>(pat.getInjectionTarget(), beanManager));
}
}
}
}
}
and after I added overrided inject(...) in CustomInjection
public CustomInjection(InjectionTarget<T> originalInjectionTarget, BeanManager beanManager) {
this.wrappedInjectionTarget = originalInjectionTarget;
this.beanManager = beanManager;
}
like:
#Override
public void inject(T instance, CreationalContext<T> ctx) {
l.trace("Injecting into {}", instance);
//....create my own HK2 object. Can it be just new B() for example ?!
locator =ServiceLocatorUtilities.createAndPopulateServiceLocator();
B b = locator.createAndInitialize(B.class);
l.trace("First injecting standard dependencies {}", instance);
wrappedInjectionTarget.inject(instance, ctx);
// dispose created by CDI B type object ?! - seems messy but works
manageBViaReflection((x, y, z) -> x.set(y, z), instance, b);
}
In manageBViaReflection I just set the object B - b to field X of type B and name b on instance Y - instance.
The delicate inaccuracy is that line:
wrappedInjectionTarget.inject(instance, ctx);
performs and CDI injection on B. I have producer to type B but I want to create it on my own in this particular class - not using a producer. Object B must be disposed and when I override its value using manageBViaReflection then I must dispose it first - its a bit messy but generally that idea works.
Siliarus, jwells131313 - maybe U have any further suggestions ?
Alright, from Weld/CDI point of view, here is how to disable injection into those fields. Note that I don't know HK2 so I don't know how you then want to link it there, but from CDI perspective you need to have the bean as #Dependent (to avoid proxying where things would get nastier). You haven't specified the version for CDI, so I'll make notes for both, 1.x and 2.0.
Actually what comes to me are two things, first, its the ProcessAnnotatedType phase, where you could remove the #Inject annotation so that when CDI takes that annotated type (which it turns into bean), it will no longer see it as injection point. You would do that as follows:
void processAnnotatedType(#Observes ProcessAnnotatedType<T> pat) {
pat.configureAnnotatedType().remove(Inject.class); // CDI 2.0 solution
// for CDI 1.x you need to implement your own AT, which
// will do just the same, the call this:
// pat.setAnnotatedType(yourOwnAT);
}
Second though takes into consideration ProcessInjectionTarget. You would need to wrap InjectionTarget with your own implementation. The strength of this approach is that you can hook HK2 internals here directly. The main idea is to override javax.enterprise.inject.spi.InjectionTarget.inject(T, CreationalContext<T>) and put the HK2 code here, so when CDI actually tries to make injection, it would use HK2.
void processIT(#Observes ProcessInjectionTarget<T> pat) {
pat.setInjectionTarget(myITImpl); // just set your wrapped impl here
// there is no diff here in CDI 1.x and 2.0, no configurator here
}
Whichever way you choose, bear in mind that CDI has a nice huge set of TCK tests which cover all this stuff and hence can be used as an example to see how to implement such wrapper.
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().
I have a Spring bean, let's say:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class AImpl implements A {
public void setSomeDependency(D dependency) {
// This setter DOES NOT BELONG to interface A
}
}
<bean id="aImpl" class="AImpl"/>
Now I want to integration test it, but first I need to mock the dependency D, because it does too much stuff. Since the AImpl implements an interface and contains a transactional annotation, the generated proxy is only compatible with the interface A, so I can do this:
#Inject #Named("aImpl")
private A a;
but cannot:
#Inject #Named("aImpl")
private AImpl a;
As a result, I can't mock my dependency.
Please note that adding void setSomeDependency(D dependency) to interface A is not an option, as it has no business meaning. Neither it is using the proxy-target-class="true", as it breaks a whole lot of other beans (this attribute affects all beans in the context).
Is there a way to unproxy the injected bean A, so I could cast it to AImpl?
Try this:
if(AopUtils.isAopProxy(a) && a instanceof Advised) {
Object target = ((Advised)a).getTargetSource().getTarget();
AImpl ai = (AImpl)target;
}
Bonus: in Scala I am using the following equivalent function for the very same purpose:
def unwrapProxy(a: AnyRef) = a match {
case advised: Advised if(AopUtils.isAopProxy(advised)) =>
advised.getTargetSource.getTarget
case notProxy => notProxy
}
With the introduction of Spring 4.2.RC1, there is now a dedicated utility class in the spring-test module that handles this case for you.
The class is called AopTestUtils and provides the methods:
getTargetObject (unwraps only the top-level proxy)
getUltimateTargetObject (unwraps multiple levels of proxies if they exist).
Check out the relevant commit as well as the respective issue.
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.