Currently I try to rewrite my Java Spring Boot Application with Kotlin. I encountered a problem that in all of my classes which are annotated with @Service
the depe
I faced the same problem working with Kotlin but the null instance was a JpaRepository. When I added the @Transactional
annotation to a method inside a service, I got a message saying Methods annotated with '@Transactional' must be overridable
so I went ahead and marked both, the class and the method as open
. Easy, right?! Well, not quite.
Although this compiles, I got the required repository as null at execution time. I was able to solve the problem in two ways:
open
:open class FooService(private val barRepository: BarRepository) {
open fun aMethod(): Bar {
...
}
@Transactional
open fun aTransactionalMethod(): Bar {
...
}
}
This works but having all the methods in a class marked with open
might look a bit odd, so I tried something else.
interface IFooService {
fun aMethod(): Bar
fun aTransactionalMethod(): Bar
}
open class FooService(private val barRepository: BarRepository) : IFooService {
override fun aMethod(): Bar {
...
}
@Transactional
override fun aTransactionalMethod(): Bar {
...
}
}
This way you can still use the annotation since all the methods will be overridable and you won't need to use open
everywhere.
Hope this helps =)
Which Spring Boot version do you use? Since 1.4 Spring Boot is based on Spring Framework 4.3 and since then you should be able to use constructor injection without any @Autowired
annotation at all. Have you tried that?
It would look like this and works for me:
@Service
class UserServiceController(val dsl: DSLContext, val teamService: TeamService) {
// your class members
}
I just bumped into exactly same issue - injection worked well, but after adding @Transactional annotation all the autowired fields are null.
My code:
@Service
@Transactional
open class MyDAO(val jdbcTemplate: JdbcTemplate) {
fun update(sql: String): Int {
return jdbcTemplate.update(sql)
}
}
The problem here is that the methods are final by default in Kotlin, so Spring is unable to create proxy for the class:
o.s.aop.framework.CglibAopProxy: Unable to proxy method [public final int org.mycompany.MyDAO.update(...
"Opening" the method fixes the issue:
Fixed code:
@Service
@Transactional
open class MyDAO(val jdbcTemplate: JdbcTemplate) {
open fun update(sql: String): Int {
return jdbcTemplate.update(sql)
}
}