Optional bean registration in bean method without annotations - java

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.

Related

How to change instance (target) under CDI (Weld) proxy without proxy recreation

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.

dynamic constructor injection in spring

I am learning Spring Core. I am facing some problem.
As in constructor injection, values are passed through xml file which contains bean definition.
I want to define the bean in xml file and want to initialized the bean with dynamic value passed by the user. Is it possible to create bean with dynamic value by using constructor injection ? What are the various ways to do this?
You can't.
You would have to refactor and inject a provider/factory of your required class, ie add a level of abstraction. You can then call this provider/factory with your required values and get an appropriate instance.

Struts2 + spring autowiring actions by-name without exposing certain properties

I am using Struts 2 and Spring autowiring. Right now, the default strategy is set to by-name, but usually we use the constructor and the fallback works to autowire in properties when only one implementing class is available.
There is one property however that I'd like to wire into an action class that has several implementing classes, so I made the Action a java bean, with the properties as fields that can be set. Unfortunately, the only ways that these will be used (apparently) is if they have a public getter/setter, which also exposes them to the type converter at request time. In other words, if a client adds their name to the request as form fields or parameters, Struts will attempt to write those values to them.
So my question is, is it actually possible to use by-name autowiring without exposing properties like that (which may or may not be a security hazard), or am I better off just using XML and defining the Action as an object with scope prototype?
I did eventually track down the documentation for the ParametersInterceptor which actually lists three ways you can limit what parameters are set by the interceptor.
Configuring excludeParams in the parameter configuration, which is a global regex which applies to all actions (not what I want, also possibly deprecated as it is no longer described in the most recent class docs).
Setting excludeMethods (does the same as the previous, the preferred method for global excludes)
Implementing ParameterNameAware, which is the closest to what I wanted. Here you can whitelist what parameters are used.
In the end, defining the action as a prototype object in the normal Spring configuration seemed to be the most prudent. Letting the action manage what parameters it has means another place where parameters need to be explicitly white listed every time a change is made.

How to specify interceptor at inject time

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.)

Get access to all spring beans of a given type

I have a Spring application (Spring Batch not web application). In a test class, I want to grab access to all of my beans of a given type.
I understand that in Spring you should generally use IOC and let the container inject your beans. However in this case, I want to loop through a variable number of beans that extend a given class (org.springframework.batch.item.database.JdbcCursorItemReader), and do something (want it to be a unit/integration test that just connects it to the database and reads 1 row, so we can confirm at test time that all of the JdbcCursorItemReader in the system have valid SQL and row mappers).
Problem 1) I can only get beans one at a time. I can have my class implement BeanFactoryAware to get a reference to my beanfactory. Then I can do beanFactory.getBean("name"); to get access to a single bean. How do I instead get ALL beans? I can loop through and drop the ones that aren't the class I want.. but somehow I need a list of all beans the beanfactory knows about or something.
Problem 2) The bean I get back from the beanfactory is a proxy. If I try to cast and use my bean I get something like
java.lang.ClassCastException: $Proxy0 cannot be cast to org.springframework.batch.item.database.JdbcCursorItemReader
You can get around the first problem by using ApplicationContextAware instead of BeanFactoryAware. This will pass in the ApplicationContext, which has the getBeansOfType() method which lets you retrieve all beans that are of a given type.
The second problem is likely caused because something is creating AOP proxies around your JdbcCursorItemReader bean. These generated proxies will, by default, implement the same interfaces that JdbcCursorItemReader does (specifically, ItemReader and ItemStream). Your code should not try and cast to the class type (JdbcCursorItemReader), but to one of those interface types instead. It's usually possible to force the proxy to extend the proxied class directly, but without knowing anything about your setup, I can't help you with that.

Categories

Resources