I have some beans for which, in specific injections, I want to add a given interceptor.
I was naïvely thinking there was something like a #Interceptors annotation that could allow me to write
private #Interceptors(Logging.class, Connection.class) #Inject MyBean instance;
Unfortunatly, Weld documentation clearly states the opposite.
So, how could I inject an intercepted version of my bean ? Is it possible using a cdi Instance object ?
EDIT
Although LightGuard's answser is really relevant, it doesn't totally answser my question, so let me rephrase it.
I want to have an annotation that triggers some kind of method call event sending. For that, I created a CDI Interceptor, complete with its own interceptor binding (let's say interceptor is called SenderInterceptor, and the binding is called SenderBinding). What I want now is to add a CDI qualifier (let's call it SenderQualifier) that, when used for an injection, installs SenderInterceptor.
To be more clear, I want the following code to use SenderInterceptor
/* calling any method of that bean should trigger an event */
private #Inject #SenderQualifier MyBean aBean;
while this one doesn't
private #Inject MyBean aBean;
What I tried so far was
detecting fields requiring those injections using reflections library (that works)
create using seam solder an AnnotatedType from bean class (during the BeforeBeanDiscovery event) (the type is created, but not really distinguishable from the initial one) and giving that AnnotatedType the interceptor binding annotation.
create using seam solder (again) a Bean from generated AnnotatedType, and giving it the required qualifier annotation
All seems to worrk, except it's the original bean which gets injected.
I could of course replace original one with intercepted one, but there are some cases where such interception is not required, so I have to keep both AnnotatedType refering the same concrete type. I was thinking I coulld do that in CDI, but it doesn't seems to work (as original type is never replaced by intercepted one).
What you would need to do:
Add the interceptor to beans.xml so it's activated
Create an extension to add the interceptor binding or the interceptor annotation to the type in ProcessAnnotatedType life cycle event. You'll need to call getAnnotatedType, add the annotation(s) then call setAnnotatedType. I strongly recommend looking at Seam Solder or Apache DeltaSpike project for the AnnotatedTypeBuilder to make this easier.
Possibly, you could try #Inject MyInterceptedBean instance;, where the interceptors are listed with the MyInterceptedBean?
(Caveat: this does not look right, though, using inheritance for types that only differ in annotations ... probably acceptable when it's always the two stated same annotations and not different annotations in each case.)
Related
How can I omit bean registration directly inside a bean method on certain conditions, not with Annotations?
My use case:
I generate child contexts with varying properties for services. (OpenFeign -> ClientConfiguration Contexts)
I want to look up a couple of different settings like 'my.service.default', 'my.service.group', 'my.service.subgroup', 'my.service.name' and merge them. If the merged result satisfies a couple of constrains, I want to provide a MySpecialConfigurationProperty as Bean.
Other beans define ConditionalOnBean(MySpecialConfigurationProperty.class) and can setup all the beans I need.
Now, my issue is with the MySpecialConfigurationProperty bean.
I know, I could define a custom #Condition Annotation. But this would need to replicate the property build logic and I don't want to do it twice.
Instead I'd like to return an Optional.empty() or something like a EmptyBeanRegistration that basically tells Spring: "Don't include this bean. It's fine."
Alternatively, is there a way to send context from the condition to the bean method, so i'm still not building up everything twice?
It's not allowed to return null from a bean method.
I could write a BeanFactoryPostProcessor, but it seems overcomplicated and I wondered, if there is a simple solution, ideally a special return type.
I want to refresh bean (destroy, initialize) if some property is changed, for example db url connection. The problem is that this bean might be already injected in other beans in CDI container. I have 2 thoughts about this:
1. If bean is proxied - destroy target for this proxy, re-initialize target inside this proxy.
2. For #Singleton and #Dependent beans, because they are not proxied, I can wrap such beans in proxy and do the same as above.
The reason I want to wrap it in proxy is that when property changed and I want to recreate real object, I should also know all dependent beans that have dependency on my bean.
So my questions are:
1. How to replace real object inside proxy in CDI? or
2. If I dont want to keep proxy as I explained above, how to create proxy object for my bean and re-inject it to all dependent beans in CDI container?
This is my previous question:
Re-inject CDI bean if some injected property changed
Again, I use CDI (Weld), not Spring IoC, so I can not use #RefreshScope from Spring cloud config, but I think my expected functionality can be similar with using custom scope.
For #DependedSCoped beans you can use
class MyBean {
#Inject
private Instance<MYType> myTypeInst;
// This will ensure, that the bean is always fresh created.
// But the property value on the former instance will be lost
// So the changable value has to be provided another way to the created bean
public void do SomeThing(){
MyType bean = myTypeInst.get();
myTypeInst.destroy(bean);
}
}
If you use a #Depended scoped bean, then you must be aware that the injection target gets its instance which is exclusively for this bean, so who is changing the value? Is the #Dependend scope the right scope for your use case?
It should not be necessary to provide an own proxy or hack into an existing one, just find the proper scope for your use case and implement the bean properly. If a connection url can change then the bean managing the connection must be aware of a change and recreate the connection and the beans using this bean need to retrieve the connection each time the use it.
Maybe you could provide an description of your use case, then we maybe can you provide you with an better answer.
Conclusion
As the use case became clear (see comments below), it resulted in the intention to implement a custom scope, because CDI doesn't seem to provide a suitable scope for this use case. I recommend to try to find a provided CDI scope if possible and implement a custom scope only if necessary, because you will have to take care about the lifecycle of your beans, management of your scope and how the beans, managed by your scope, can and will be used by an application. If not implemented with care a custom scope could cause problems such as memory leaks, if for instance your beans are not properly discarded after usage.
Say I have a service type Service that has a number of different implementations, ServiceImplX and ServiceImplY. I also have a caching layer, CachedService, that implements Service and wraps some basic implementation of Service to access the data.
What I want is to be able to bind one of ServiceImplX and ServiceImplY as the basic implementation to be injected into CachedService, while CachedService itself should be bound to Service to be injected into actual clients of this service.
I would like to avoid naming annotations to solve this since that seems fragile. Is there any safer way of achieving this?
Define a proper binding annotation:
#RetentionPolicy(RUNTIME)
#BindingAnnotation
#interface ServiceBinding {}
This is a lot more robust than an #Named binding annotation because:
It's a symbol, just like a class name or variable, so you can easily find references to it in your code; the name in an #Named annotation can be constructed at runtime, so it is much harder to find.
You can control the accessibility of a binding annotation via public/private etc modifiers, so you can control where the annotation is configured and referenced. The strings of #Named annotations are in a global scope.
I have sucessfully used Guice to Inject Providers into the servlet portion of an existing java web application, however, I can't access the injectors through the business layer (non-servlet java classes) of the application.
I have read up on Injecting the Injector, but to me that seems more like a hack and in several places, including the Guice documentation, it says not to do that too much.
I guess my question is, Where do I bootstrap a java web app so that the non-servlet/filter classes have access to the injector created in the class I use to extend GuiceServletContextListener? Is there any way to make those classes injectable without injecting the injector?
Thank you and let me know if you need any clarification.
Edit:
I am attempting to do this with a simple logger, so far, in my
servlets, I call:
#Inject
private static org.slf4j.Logger log;
The injection is set up in MyLoggerModule as follows (which is in the
createInjector call with ServletModule) :
#Override
public void configure() {
bindListener(Matchers.any(), new SLF4JTypeListener()); // I
built my own SLF4JTypeListener...
}
This all works perfectly in the servlets, but the field injection does
not work when called by a class that is not a servlet or filter.
Guice doesn't intercept calls for new objects, so if your business layer isn't already using Guice to create the objects that need injection, it'll need modification to do so.
The injection only works when handled by Guice during injection. So starting from the base injector you've made, whatever is marked with #Inject which is needed for the instance you've requested will be provided by Guice as best it can, and in turn, during instanciation of those, further #Inject annotations will be filled in by providers and bindings until nothing new needs to be instanciated. From that point on however you are not going to get fields injected into servlets created outside Guice's injection, perhaps by calling new somewhere, which is likely what your Object Factory is doing.
You'll need to change your Object Factory to use providers instead of new. If you could edit these, it wouldn't be too hard to do since Guice can give you default providers for bindings.
So one way your business layer could be Guice aware is to have whatever is creating servlets first create an Injector and then request the servlets be created by the injector. If this means you'll have more than one injector, then yes, that will be a problem but only for the objects you want to be singletons. So you could make a factory pattern class for a singleton injector, or you could find where these classes (here typed bar) which are creating servlets themselves are created (in foo), and then start with the injector there (in foo) using one Guice injector to create those (bar type) classes and also modifying them (bar type) to request a provider for the servlets which they'll use instead of making calls for a new servlet.
Now that I think about this, it could be simple if it kind of only happens once or twice for 10-20 servlet types, or it could be complicated if there's some framework that defines totally flexible behavior for what gets newed up when and why.
Another option would be avoiding #Inject on fields at all times, as recommended. So now your servlets are taking in an org.slf4j.Logger as a construction parameter. The constructor is marked #Inject, and it assigns the parameter's value to the field. Then any place you're not using injection should break with an incorrect number of parameters at a new call. Fix these by figuring out how to either get the servlet provided here instead, or how to get a provider for the servlet into the class.
Not sure what you mean... if you inject objects in to your servlets/filters, those objects have their dependencies injected by Guice as well, and so on all the way down.
How are you creating the classes that you're trying to inject this logger in to? They must be created by Guice to be injected, which means no new.
I'd like to introduce Guice for the use of an existing mid-sized project.
For my demands I need a custom scope (session is too big, while request to small for my project).
Imagine that I request guice to provide me an instance of Class A which has direct and indirect dependencies to many other classes (composition).
My custom provider is able to provide the instance of classes which are used as constructor arguments of all involved classes.
Question:
Do I really have to put an #Inject (and my custom scope) annotation on the constructors of all involved classes or is there a way that guice only requires these annotations on the top-level class which I request and that all further dependencies are resolved by "asking" my custom scope for a provider of the dependent types?
If this is true this would increase the effort of introducing Guice because I have to adjust more than 1000 classes. Any help and experiences during the introduction of guice is appreciated.
First of all, it's possible to use Guice without putting an #Inject annotation anywhere. Guice supports Provider bindings, #Provides methods and constructor bindings, all of which allow you to bind types however you choose. However, for its normal operation it requires #Inject annotations to serve as metadata telling it what dependencies a class requires and where it can inject them.
There reason for this is that otherwise, it cannot deterministically tell what it should inject and where. For example, classes may have multiple constructors and Guice needs some way of choosing one to inject that doesn't rely on any guessing. You could say "well, my classes only have one constructor so it shouldn't need #Inject on that", but what happens when someone adds a new constructor to a class? Then Guice no longer has its basis for deciding and the application breaks. Additionally, this all assumes that you're only doing constructor injection. While constructor injection is certainly the best choice in general, Guice allows injection of methods (and fields) as well, and the problem of needing to specify the injection points of a class explicitly is stronger there since most classes will have many methods that are not used for injection and at most a few that are.
In addition to #Inject's importance in telling Guice, it also serves as documentation of how a class is intended to be used--that the class is part of an application's dependency injection wired infrastructure. It also helps to be consistent in applying #Inject annotations across your classes, even if it wouldn't currently be absolutely necessary on some that just use a single constructor. I'd also note that you can use JSR-330's #javax.inject.Inject annotation in Guice 3.0 if a standard Java annotation is preferable to a Guice-specific one to you.
I'm not too clear on what you mean by asking the scope for a provider. Scopes generally do not create objects themselves; they control when to ask the unscoped provider of a dependency for a new instance and how to control the scope of that instance. Providers are part of how they operate, of course, but I'm not sure if that's what you mean. If you have some custom way of providing instances of objects, Provider bindings and #Provides methods are the way to go for that and don't require #Inject annotations on the classes themselves.
NO YOU DONT
GUICE does not ask you to inject every single object. GUICE will try and create only injected objects. So you can #Inject objects that you want to be injected.
On the scope bit - Scope essentially controls how your objects gets created by GUICE. When you write your own custom scope you can have a datastructure that controls the way objects are created. When you scope a class with your custom annotation, GUICE will call your scope method before creation with a Provider for that class. You can then decide if you want to create a new object or use an existing object from a datastructure (such as hashmap or something). If you want to use an existing one you get that and return the object, else you do a provider.get() and return.
Notice this
public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
return new Provider<T>() {
public T get() {
Map<Key<?>, Object> scopedObjects = getScopedObjectMap(key);
#SuppressWarnings("unchecked")
T current = (T) scopedObjects.get(key);
if (current == null && !scopedObjects.containsKey(key)) {
current = unscoped.get();
scopedObjects.put(key, current);
}
// what you return here is going to be injected ....
// in this scope object you can have a datastructure that holds all references
// and choose to return that instead depending on your logic and external
// dependencies such as session variable etc...
return current;
}
};
}
Here's a tutorial ...
http://code.google.com/p/google-guice/wiki/CustomScopes
At the most basic level, the #Inject annotation identifies the stuff guice will need to set for you. You can have guice inject into a field directly, into a method, or into a constructor. You must use the #Inject annotation every time you want guice to inject an object.
Here is a guice tutorial.