Dan Fox
Dan Fox

Reputation: 61

Grails service using a method from another service

I'm building a grails app and have come across an issue when trying to instatiate a service, in a different service. Both of the services use a method defined in the other eg.

class fooService{
    def barService
    barService.doIt()

    def getIt(){
    ...
    }
}

class barService{
    def fooService
    fooService.getIt()

    def doIt(){
    ...
    }
}

When I run the app and go to where the methods are used, it brings up this error;

Error creating bean with name 'fooService': 
org.springframework.beans.factory.FactoryBeanNotInitializedException: FactoryBean is 
not fully initialized yet

Is this something that cannot be done in grails? Or could anyone offer any advice?

Thanks

Upvotes: 5

Views: 5742

Answers (5)

saurabh
saurabh

Reputation: 2459

You can handle the circular reference using the following -

Lets call it firstSerivce and secondService.

Code changes for secondService class

protected def firstService 
def grailsApplication 

def initialize() {
    this.firstService = grailsApplication.mainContext.firstService 
}

code changes in Bootstrap.groovy

def secondService

def init = { servletContext ->

    secondService.initialize()
...
..

Upvotes: 0

CheddarMonkey
CheddarMonkey

Reputation: 486

All these answers are excellent and show how to handle the problem through the framework. Although, when I had this problem I realized there must be a flaw in my plan and architecture if I absolutely must have services calling each other and causing conflicts. Instead of finding a work-around I took a slightly less complicated and strait forward approach -- I restructured. I moved the offending methods from the service class into another service class. It took some refactoring, rethinking and copy/paste skills but I think the application is better for it.

I'm not saying this is better than the other answers. I'm saying, this time, with this project refactoring was a better, faster, less complicated solution. I highly recommend it.

UPDATE Our final strategy is to refactor all "utility" service functions into a baseService class then have all other services that need the utility services extend baseService. The new policy is to avoid injecting services into other services, unless some situation arises that doesn't allow us to follow this inheritance pattern. This will give us a cleaner code base and less of a spaghetti trail of injections to follow. Plus, it eliminates the emergence of this error.

Upvotes: 2

Sushil
Sushil

Reputation: 31

Service can be called by another service but not possible at time of initialization. If you want to implement this, the way should be like.

class fooService{
    def barService

    def getIt(){
        ...
    }

    def anotherFooMethod(){

        barService.doIt();
    }
}

class barService{
    def fooService


    def doIt(){
        ...
    }

    def anotherBarMethod(){

        fooService.getIt();
    }
}

Upvotes: 3

Ian Roberts
Ian Roberts

Reputation: 122364

I've had similar issues in the past, but only when both services are transactional. If it's possible to make at least one of them non-transactional then it should work as-is. If that's not possible then the fallback is to do a kind of "late binding"

class FooService {
  def grailsApplication
  private getBarService() {
    grailsApplication.mainContext.barService
  }

  public methodThatUsesBarService() {
    barService.doSomething()
  }
}

This will look up barService in the app context at the point where it is used, rather than at the point where the FooService is created.

Upvotes: 4

Burt Beckwith
Burt Beckwith

Reputation: 75671

That's not valid code, so it's hard to know what's really going on. Are the doIt() and getIt() calls in constructors? If so, change the services to implement org.springframework.beans.factory.InitializingBean and do the calls in the afterPropertiesSet method.

Upvotes: 1

Related Questions