I am trying to let a piece of runtime state decide WHICH implementation of an interface to use, preferably solely by autowiring.
I have tried making an object factory for the interface thet uses dynamic proxies, and I used qualifiers to coerce the #Autowired injections to use the factory. The qualifiers are necessary because both the factory and the implementations respond to the same interface.
The problem with this is that I end up annotating every #Autowired reference with the #Qualifier. What I'd really want to do is annotate the non-factory implementations with something like #NotCandidateForAutowiringByInterface (my fantasy annotation), or even better make spring prefer the single un-qualified bean when injecting to an un-qualified field
I may thinking along the totally wrong lines here, so alternate suggestions are welcome.
Anyone know how to make this happen ?
You could use #Resource and specify the bean name of the factory.
I haven't looked at this myself but I noticed Spring JavaConfig is made it to M4 and it seems to allow more flexible configuration through a combination of annotations and Java code. I wonder if it would offer a solution to your problem.
Related
I have done my research before asking but no luck.
I have a StartUp Singleton bean. In this bean I have an #Inject #Any Instance. I loop all the implementations and try to check if the class is annotated with a custom annotation. All the implementations(all the classes that I want to inspect) are Stateful or Stateless beans.
Sometime the class I want is found and I can perform getClass().isAnnotationPresent(ClassNameAnnotation.class)
Most of the times I get a proxy object and in this case I cannot perform the above check.
I cannot find a way to get the real object. I have tried to get the SuperClass but not luck.
I will attach some of the code so you can have a better idea.
#Singleton
#Startup
public class CacheLoader {
#Inject
#Any
private Instance<ClassNameA> aClasses;
.......
#Lock(LockType.READ)
public void evaluate() {
if (!aClasses.isUnsatisfied()) {
for (ClassNameA className : aClasses) {
if (className.getClass().isAnnotationPresent(ClassNameAnnotation.class)) {
....
}
}
}
}
}
I tried to use the SuperClass of the proxy object but it does not return what I want. I tried also via Proxy.getInvocationHandler(). Even when I check the methods Proxy.isProxyClass(getClass()) or isSynthetic() does not return that the object is a proxy.
Thank you!
I think you would be better served by using a CDI Portable Extension, rather than a Singleton EJB. A couple of reasons
In CDI, everything is a proxy. So like some of the commenters have said, using reflection would be very fragile as it's not part of the spec. You're dealing with classes that are defined at runtime. It may work if you tie yourself to implementation-specific details, but it could break between releases of your CDI container.
The CDI Container will do all of the annotation scanning for you :)
A portable extension runs on startup, before other stuff starts flying around your app
A google search gave me this guide, but there are lots of them: https://www.baeldung.com/cdi-portable-extension
I think you would want to hook in processAnnotatedType() if you're modifying the bean declarations, or afterBeanDiscovery() if you're just documenting them as you said.
We actually have a CDI Portable Extension we use internally that does some config magic for environments. One of the config params is an annotation that is not a qualifier annotation, which sounds like what you want... the CDI container can get you the type, from which you can inspect the annotations.
Finally, this is not directed related to your question but may be useful: If your annotations drive configuration through fields of the annotations, selecting them can be quite complicated because of how the Java type and inheritance system works with annotations. You may benefit by using AnnotationLitreal in those cases. Read up here on this useful utility class here: http://www.kurtsparber.de/?p=387
EDIT:
Another side note... even thought I think you should switch to a Portable Extension, you shouldn't need #EJB's Singleton Startup anymore! you can do this with pure CDI: https://rmannibucau.wordpress.com/2015/03/10/cdi-and-startup/
Today, we found this pattern in our code:
class Foo {
private List<String> errors;
public void addError(String error) { ... }
public List<String> getErrors();
}
While the code seems to work, this is a singleton Spring bean and it's injected in several independent places and the consumers of the bean assume that they each have their own list of errors. So this introduces subtle bugs.
The obvious solution is to educate developers to avoid this kind of error but I was wondering if there is a static or runtime code analysis tool which can find this kind of bug.
For example, a bean postprocessor could analyze the bean before it's returned and look for private fields that aren't #Autowired.
After pouring some more brains (ours and other peoples) on this, we came up with this approach:
Install a BeanPostProcessor which makes sure that all singleton beans (i.e. where the scope in the bean definition is Singleton) have the custom annotation #Stateless on the actual bean type.
We chose a custom annotation instead of reusing #Singleton since we need this functionality elsewhere, too.
If the annotation is missing, the factory throws an error.
In a unit test, we use ClassPathScanningCandidateComponentProvider with out custom annotation to locate all classes on the classpath. We can then do the complex and expensive tests to make sure the bean has no state that changes after the initial configuration (i.e. after the autowiring has happened).
The second step could become a little bit easier if we moved the autowired fields into the constructor but we don't like methods that take many, many arguments. It would be nice if Java or an IDE could generate builders from the bean code. Since that's not the case, we stick to autowired fields and/or setters.
You could create a JUnit test that would load your app config.
This could combine ListableBeanFactory from here :
Can I dynamically create a List by scanning the beans in a spring configuration file?
with the 'isSingleton' check here :
How to enforce a prototype scope of Spring beans
i.e. list all the beans in the app context, then check to see which are singletons.
This would let you find all singleton beans...although it wouldn't really prevent your error case where someone treats one of these singletons as if it were not.
I would like to make sure if I understand this correctly. Spring needs a setter to inject a field reference? Couldn't it do it by just detecting it as a public field?
Is there an alternative to this. From what I understand Java EE's #Inject annotation can do this without any problem. But I have always been inclined more to Spring.
This depends on how you're creating your bean. Spring does not require setters. There are a number of other ways:
Autowiring (with or without Qualifiers) via annotation at the field level
Constructor injection (either by xml or annotations in the code)
Public fields (as you suggested) might work, though i have never tried it, and would advise against it even if it does.
Unfortunately, the XML approach does not look into private fields (that i know of). You either need to add a setter, use the constructor, or set up some sort of autowiring.
Keep in mind, autowiring can be combined with XML. Spring will pay attention to your wiring annotations even if you create your bean via xml (as opposed to something like #Component and component scanning).
It is not necessary to have Setter to inject a reference, you can use Autowire on a public variable of a class or on the setter method, u can also inject beans using constructor-arg which is a good way of injecting dependencies and autowiring can be done on Constructors also. #inject also does the same functionality as #autowired, however #Autowired has an additional behaviour where it internally also uses #required attribute, to see if the bean has a references and injected properly.
Spring provides several alternatives for DI besides setter injection. For example, you can use constructor injection. Alternatively, you can use Spring's #Autowired annotation for constructor, field or setter injection. Since you mentioned it, I guess that you would also be interested in knowing that Spring supports the #Inject annotation.
I am reading the book Pro Spring 3. It has a certain paragraph that really confused me. The paragraph is about autowiring in spring. Here is an excerpt:
In most cases, the answer to the question of whether you should use
autowiring is definitely “no!” Autowiring can save you time in small
applications, but in many cases, it leads to bad practices and is
inflexible in large applications. Using byName seems like a good
idea, but it may lead you to give your classes artificial property
names so that you can take advantage of the autowiring functionality.
The whole idea behind Spring is that you can create your classes how
you like and have Spring work for you, not the other way around ...
... For any nontrivial application, steer clear of autowiring at all
costs.
I have always been using the #Autowired tag in applications I have created. Can someone explain what is wrong with it and what I should use instead?
A mini example on how I handle most things now is:
#Service("snippetService")
public class SnippetService {
#Autowired
private TestService testService;
public Snippet getSnippet() {
return testService.getSnippet();
}
}
Is using autowiring like this "wrong" or am I missing something?
I believe there are two things confused here. What is meant by 'autowiring' in this chapter is marking bean for automated detection and injection of dependencies. This can be achieved through setting of "autowire" bean attribute.
This is in fact opposed to using #Autowired where you explicitely indicate field or setter for dependency injection.
Have a look here: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-factory-autowire.
To explain it, assume you have
public class SnippetService {
private TestService testService;
public Snippet getSnippet() {
return testService.getSnippet();
}
public void setTestService(TestService testService) {
this.testService = testService;
}
}
If you defined a bean:
<bean class="mypackage.SnippetService" autowire="byType"/>
spring would attempt to inject bean of matching type, TestService in this case, by calling setTestService setter. Even though you did not use #Autowired. This indeed is dangerous since some setters might not be meant to be called by spring.
If you set autowire="no", nothing will be injected unless marked so with #Autowired, #Resource, #Inject.
There's nothing wrong with what you have, especially if you are starting out with one implementation of TestService anyways. As Johan mentions though, it's better to use #javax.annotation.Resource which also allows you to be more specific if you need to (for example using the name or the type attribute).
The only problem I see here is that you are loosing control a little. For example, say you have two or more instances of TestService in your app config and you want to use one of them. Having Autowire makes is trickier than using config XML to inject for you. This is what your book is trying to point i.e. it becomes difficult/trickier in big application where such needs are more frequent.
If you don't have such situations, I think its fine.
Autowire through XML is completely safe and helpful if you do constructor based autowiring particularly if you make the collaborators private final.
I'm kind shocked the author said that when I did the above on an extremely large spring 2.5 project a couple years ago. (at the time the annotation support was not working in JBoss)
Is it possible to make the BeanFactoryPostProcessor detects if beans classes have methods annotated with a custom annotation (#inject for instance) and proceed to make a certain treatment if it's the case ?
If this is not possible, can you explain how i get access to the beans metadata and exploit it in the BeanFactoryPostProcessor ?
Thanks in advance.
Edit: I came across this link, not sure if it's the right solution though, since i heard that using reflections considerably deteriorates the overall application performance.
The ConfigurableListableBeanFactory passed into the postProcessBeanFactory() method call, has a method getBeanDefinition(String), from which you can get the class name of that bean. From here you can do a Class.forName(String), and get the class, and then you can inspect its members for your annotation. Of course this suggestion uses Java Reflection also.
You could also try to annotate each class that you want to inspect with its own custom annotation. From the ConfigurableListableBeanFactory you can then call getBeansWithAnnotation(Class). This returns a map from beanName to the corresponding instance.
Or you can take a look at the JavaDoc yourself:
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/config/ConfigurableListableBeanFactory.html