Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
vaadin-spring: @Autowired does not work outside of top level UI classes?
In https://vaadin.com/forum#!/thread/11086928 I alrady tried to describe my problems with vaadin-spring and with injecting DAO/Service objects into view model classes.
OK, this post was probably into the wrong category and not clear enough, so here a second try:
- I structured the layer above the DAO/Service layer according to the MVVP pattern.
- The GUI has a coordinating ViewModel, which is not a vaadin component (neither a View nor an UI) and which contains a field holding the DAO used here - and this field has an @Autowired annotation. The problem is - it is not set correctly, i.e. it stays null.
Methinks, the problem here is that the Model itself is not @Autowired, but created via normal constructor call - i.e. if you make a field in a lower level class @Autowired, the instance of this class must itself be @Autowired and so on, until we reach a Vaadin UI class or Vaadin View class.
Is this right? I dont want to make everything be injected, just the lower level service and DAO classes - due to the dynamical nature of our GUI, I'm forced to hand-create views anyway, so there is no real in in using CDI here - is there a possibility of going only partially the injection route?
By default, in order for an object to get is properties injected, means that the object itself also needs to be injected (and its parent). Thus autowiring will only work "in a chain", if you break the chain, then autowiring will not work. That said, there seems to be a trick how you can autowrite properties even for self-initiated objects. You'll still have to autowire the beanFactory, so you still need work around your problem somehow.
Personally, when using CDI or Spring together with the MVP patter, I have my views and my presenters both injected. This makes sense, since you want to leverale the UI scope provided by the CDI add-on / Spring add-on. That way I won't have the problem you described. I do not inject speficic Vaadin components, unless they are other (sub)views and/or have something that needs to be injected.
Thanks for your answer - this "broken chain" was the main reason for my problems.
I found two ways ouf of this conundrum (your link about using @Configurable looks like a third way):
- Ensure the chain is not broken by using Spring to also manage the main views and to inject all sub-views which may appear. My view is split into sub-components, and it will be partially dynamical - i.e. sub-views which need an injected service will be created depending on the object in another subview. I am not certain yet that autowiring will be worth the troubles in this case (I can of course inject the Service field(s) into the master view, which uses ordinary "new" to create partial views and which then passes the appropriate service/dao along.).
- Define a singleton object (easy in scala). In the ContextLoaderListener needed for the VaadinSpringServlet, use WebApplicationContextUtils.getWebApplicationContext(event.getServletContext) to stash the web app contex away in this singleton object. Later on, use this context'sgetBean method to retrieve the service/DAO layer beans. This is not in the "spirit of spring", but I was getting sick of wading through stack traces, and hey, brute force works :-)
Your link seems to provide a third way, but with a performance penalty? I'm not fully sure I want to get down this route...
If performance is a critical factor, then test and benchmark before making any assumptions. Trying to "optimize" something that doesn't necessarily really need optimizing might lead to cluttered code which will be a pain to maintain.