Inconsistent Dependency Injection to domains with Grails

Thursday, October 18, 2012

I've encountered strange behavior with a domain class in my project: services that should be injected were null. I've became suspicious as why is that? Services are injected properly in other domain classes so why this one is different?

Constructors experiment

I've created an experiment. I've created empty LibraryService that should be injected and Book domain class like this:

Book has 4 explicit constructors. I want to check which constructor is injecting dependecies. This is my method that constructs Book objects and I called it in controller:

class BookController {
    def index() {
        constructAndExamineBooks()
    }

    static constructAndExamineBooks() {
        println("Started constructAndExamineBooks")
        Book book1 = new Book().logInjectedService()
        Book book2 = new Book("foo").logInjectedService()
        Book book3 = new Book("foo", 'bar').logInjectedService()
        Book book4 = new Book("foo", 'bar', 100).logInjectedService()
        Book book5 = new Book(author: "foo", title: 'bar')
        println("Finished constructor Book(Map params)")
        book5.logInjectedService()
    }
}

Analysis

Output looks like this:

What do we see?

  1. Empty constructor injects dependencies.
  2. Constructor that invokes empty constructor explicitly injects dependencies.
  3. Constructor that invokes parent's constructor explicitly does not inject dependencies.
  4. Constructor without any explicit call declared does not call empty constructor thus it does not inject dependencies.
  5. Constructor provied by Grails with a map as a parameter invokes empty constructor and injects dependencies.

Conclusion

Always explicitily invoke empty constructor in your Grail domain classes to ensure Dependency Injection! I didn't know until today either!

10 comments:

  1. Hi Tomasz,

    thanks a million for this post! I have the problem that I was unable to inject services into my domain classes and kept fighting with this ever since they started!

    Your post got me on the right track! But honestly I am using grails for the first time ... and by now I wish I didn't its a complete mess. I mean how can such a thing be? Is completely unintuitive and unlogical ... what a load of cr...!

    Anyway! Thanks again for your post! You really saved my day!

    ReplyDelete
  2. Hi Tomasz,

    thank you very much for the post.
    It saved lot of my time

    --Gangadhar

    ReplyDelete
  3. This is fantastic info & should be part of the Grail docs (is it? did i miss it?). I've been hunting for this info for while, and it explains why I see services injected in a my superclass only *after* load from the db. Thanks so much for posting.

    ReplyDelete
  4. Please check the below code.
    I am still getting NullPointerException. :(

    public class PgpEncryptionService implements ResourceLoaderAware {

    ResourceLoader resourceLoader

    public PgpEncryptionService() {

    }

    }

    ReplyDelete
    Replies
    1. Please ignore that public access modifier, it doesn't work without that also.

      Delete
    2. This is a post about Grails 2 three years ago. You probably use a newer Grails version so this post may be irrelevant.

      Delete
    3. Thanks for your reply..I am using Grails 2.1.0 and its a legacy application.. :(

      Delete
  5. I'm learning Grails 3.0.9 now and hit the same problem. After some Googling, your solution is the only one I found that seemed like it might work so I tried it and it does - thanks so much for that. Saved me a ton of time.

    ReplyDelete