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/
Related
I am trying to apply ioc into a school project. I have an abstract class Application without any field
public abstract class Application {
abstract public void execute(ArrayList<String> args, OutputStream outputStream, InputStream inputStream) throws IOException;
}
And I will call the concrete class that extends Application by
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Application app = (Application)context.getBean(appName);
My questions are:
Is it a bad practice to initialise a bean without any field (or all the fields are constants) using Spring?
As there is no dependency to other classes in Application, are we still consider this as a dependency injection or IOC? If no, what is the difference between this and a normal factory pattern? It seems that what Spring does here is simply matching the class and initializing it.
UPDATE
Here is the code snippet of the class where the instance of Application is needed.
String appName = argument.get(0);
Application app = ApplicationFactory.getApplication(appName);
ArrayList<String> appArgs
= new ArrayList<String>(argument.subList(1, argument.size()));
app.execute(appArgs, outputStream, inputStream);
Further questions:
in my code the class X will call the instance of Application by specifying a concrete application class name. In this case, it is still not possible for Spring to inject the dependency to Application, right? As what I need is a concrete class but not Application itself.
if Application does have fields but these fields are initialsed somewhere higher than X (X receives them as inputs and passes them to Application), can I use DI in this case?
Is it a bad practice to initialise a bean without any field (or all the fields are constants) using Spring?
No, its totally fine. Its true that you won't be able to "take advantage" of the automatic dependency injection mechanisms provided by spring (because obviously there are no dependencies in the class Application in your example), however spring can still:
Make sure that the Application as a singleton "obeys" the rule of being a single instance in the whole application context. For "manually" maintaining singletons you need to write code. Spring does it for you.
Manages the lifecycle of the object. Example, Spring has "postConstruct"/"preDestroy" methods that can can be run in the appropriate time and make example any custom code of the class Application.
If this class does some heavy-lifting (even without spring) than it can make sense to define it "lazy" so that the initialization of this instance will actually be done upon the first request to it.
Sometimes you/or spring itself will create a proxy of this class in runtime (for many different reasons, for example this aforementioned lazy functionality, but there are also other use cases). This is something that spring can do for you only if it manages the Application and not if its defined outside the spring.
Ok, you don't have dependencies in the application, This means that this Application class has some useful methods (at least on method, like public void foo() for
simplicity). But this in turn means that there is some class (lets call it X) that calls this method. So this class has an instance of Application as a dependency. So now the real question is who manages this class X. Probably it makes sense to manage it in Spring as well, and then you will benefit of the Dependency Injection mechanisms in this class X only because Application is also managed by Spring. In general Spring can inject dependencies only if these dependencies are managed by Spring.
I know, this last paragraph may sound vague given the use case you've presented, but you've got a point, for example in real application people make an initial bootstrapping in very certain places. Usually also people use spring boot that kind of encapsulates this kind of things for you.
As there is no dependency to other classes in Application, are we still consider this as a dependency injection or IOC? If no, what is the difference between this and a normal factory pattern? It seems that what Spring does here is simply matching the class and initializing it.
So as you see, the concept of DI container goes far beyond of what the factory pattern has to offer. In short, factory pattern only specifies the way to create the objects. Spring on the other hand, not only creates the objects but also manages them.
First, I very strongly suggest that you use Spring Boot instead of manually manipulating Spring at a low level like this.
It's perfectly ordinary to use beans that don't have their own fields for settings, but this is usually so that other beans can have pluggable strategies or providers and you can define in your application setup which to use.
If your Application class doesn't need anything else, then there really is not much advantage to Spring. Most real-world programs get complicated soon, however, and that's where it becomes useful.
Finally, you should almost never pass ArrayList as a parameter; use List instead. In the code you showed, however, if you have String[] args, you couldn't say app.execute(Arrays.asList(args), System.out).
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 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
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.