grailsgrails-4

Grails 4 service not being injected inside Grails Data Service


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]


Solution

  • 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-

    enter image description here