This is about a Grails service injected into a Data Service. The problem is that the injected service is null at runtime. Here is an example.
class MessagingService {
def sendEmail(String message) {
...
}
}
interface IFlowService {
...
}
@Service(Flow)
abstract class FlowService implements IFlowService {
MessagingService messagingService
void sendFoo() {
messagingService.sendEmail(message)
}
}
FlowService
and MessagingService
both reside under grails-app/services
.
When FlowService
calls sendEmail
there is an NPE because messagingService
is null.
MessagingService
is hand-written and is not associated with a domain.
This project uses Grails 4.0.10 and the issue occurred several times. When the usual Gails magic (i.e. injection) didn't work I solved the first one or two issues with kludges, you know, just to avoid getting stuck.
Now it seems to me the issue is quite predictable, it happens every time I write a service not associated with a domain. Did I miss something in the documentation? What is the appropriate way to handle this?
Kludge: To get around the issue I include a method sayHi
in the problematic service. It just logs a debug message. I invoke sayHi
from BootStrap to check that it works. It does, surprisingly. Then I add code in BootStrap to assign the service to the supposedly injected property in the service. [Shudder]
I tried to reproduce the same-
interface IFlowService {
}
@Service(Flow)
abstract class FlowService implements IFlowService {
MessagingService messagingService
void hello() {
println "hello"
messagingService.hi() // <- NPE
}
}
class MessagingService {
void hi() {
println "hi"
}
}
This seems to be a bug to be in Grails. But you can easily solve this (probably as a workaround) by just adding @Autowired
in the service-
import org.springframework.beans.factory.annotation.Autowired
@Service(Flow)
abstract class FlowService implements IFlowService {
@Autowired
MessagingService messagingService
void hello() {
println "hello"
messagingService.hi() // <- No NPE
}
}
It prints-