I would like to be able to use Spring using setter injection into Scala components. Unfortunately, Scala’s native setters are named differently from than the JavaBeans standard, foo_= rather than setFoo. Scala does provide a couple of workarounds for this, annotations which force the creation of JavaBeans setters/getters as well as native Scala ones, but that requires annotating every component that I wish to inject. Much more convenient would be to override the BeanWrapper used by Spring with one which knew how to handle Scala-style getters and setters.
There doesn’t appear to be any documentation on how to do such a thing or whether it is even feasible, nor any online examples of anyone else doing it. So before diving into the source, I figured I’d check here
It looks like
AbstractAutowireCapableBeanFactory(where most of the work with BeanWrapper is done) is hardcoded to useBeanWrapperImpl. No point of extension there.BeanWrapperImplusesCachedIntrospectionResultswhich usesIntrospectorin turn. Looks like there is no way to configure any of these dependencies. We can try to use standard points of extension:BeanPostProcessororBeanFactoryPostProcessor.Using just
BeanPostProcessorwill not work, because if we are doing something like this:where
BeanForInjectionis a Scala classand
BeanToBeInjectedis a bean we want to inject, then we will catch exception beforeBeanPostProcessorwill have a chance to step in. Beans gets populated with values before any callbacks ofBeanPostProcessorcalled.But we can use
BeanFactoryPostProcessorto ‘hide’ properties that are expected to be injected through Scala-like setters and apply them latter.Something lilke this:
This implementation simply checks is any bean has properties that are not listed as properties and also have Scala-like setters. All properties that match this contract are removed from properties list and saved as attributes of the bean. Now, all we need is to pull this attributes (if any) for every bean and apply them. There is where we need
BeanPostProcessor(AutowiredAnnotationBeanPostProcessor can be a good example of BeanPostProcessor).Simply create these two beans in your context:
Note:
This is not a final solution. It will work for classes, but it will not work for simple types:
Solution will work for
bean, but not forname. This can be fixed, but at this point I think you will be better off just using @BeanInfo annotation.