How to use Spring Autowired (or manually wired) in Scala object?
axtavt's solution did not work for me, but combining different suggestions from the other answers I think this is the most elegant solution:
object User {
@Autowired val repo: UserRepository = null
def instance() = this
}
@Configuration
class CompanionsConfig {
@Bean def UserCompanion = User.instance
}
<context:component-scan base-package="your-package" />
A few notes:
- Using @Configuration ensures that your companion objects are eagerly autowired
- Using @Bean def avoids having to deal with noisy names Scala gives to the class that implements the companion object
- val works just fine, as mentioned by Dave Griffith
- there is no need for Scala's @BeanProperty, Spring understands Scala properties out of the box (I'm using 3.2.2)
What I do is use AutowiredAnnotationBeanPostProcessor to inject the object at construction time.
For example:
object UserRest extends RestHelper {
@Autowired
var userRepository: UserRepository = _
AppConfig.inject(this)
}
@Configuration
class AppConfig extends ApplicationListener[ContextRefreshedEvent] {
// Set the autowiredAnnotationBeanPostProcessor when the Spring context is initialized
def onApplicationEvent(event: ContextRefreshedEvent) {
autowiredAnnotationBeanPostProcessor =
event.applicationContext.
getBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME).
asInstanceOf[AutowiredAnnotationBeanPostProcessor]
}
}
object AppConfig {
var autowiredAnnotationBeanPostProcessor: AutowiredAnnotationBeanPostProcessor = null
def inject(obj: AnyRef) {
autowiredAnnotationBeanPostProcessor.processInjection(obj);
}
}
Now you can use AppConfig.inject() to inject any object whose lifecycle is not controlled by Spring. For example, JPA Entities, etc.
Basically, you have two problems:
Property should be mutable, i.e.
var
rather thanval
All methods of Scala
object
arestatic
, whereas Spring expects instance methods. Actually Scala creates a class with instance methods namedUserRest$
behind the scene, and you need to make its singleton instanceUserRest$.MODULE$
available to Spring.
Spring can apply configuration to preexisting singleton instances, but they should be returned by a method, whereasUserRest$.MODULE$
is a field. Thus, you need to create a method to return it.
So, something like this should work:
object UserRest extends RestHelper {
@BeanProperty
var userRepository: UserRepository = null;
def getInstance() = this
...
}
.
<bean id="userRest"
class="com.abc.rest.UserRest"
factory-method = "getInstance">
<property name="userRepository" ref="userRepository"/>
</bean>
You can replace <property>
with @Autowired
, but cannot replace manual bean declaration with @Service
due to problems with singleton instance described above.
See also:
- What is the Java equivalent of a Scala object?
- 3.3.2.2 Instantiation with a static factory method
All that's actually necessary is that you define your object as a class, rather than an object. That way Spring will instantiate it.
@Service
object UserRest extends RestHelper {
@Autowired
@BeanProperty
val userRepository: UserRepository = null;
.....
}
<beans>
.....
<bean id="userRest" class="com.abc.rest.UserRest" >
<!--- this is my attempt to manually wire it --->
<property name="userRepository" ref="userRepository"/>
</bean>
</beans>
Changing the "val" to "var" is unnecessary (Spring uses reflection, which ignores immutability). I'm pretty sure that that @BeanProperty is also unnecessary (Spring will assign to the underlying field, reflectively).