## 14.4 The BeanBuilder DSL Explained

#### Using Constructor Arguments

Constructor arguments can be defined using parameters to each method that reside between the class of the bean and the last closure:

    bb.beans {
        exampleBean(MyExampleBean, "firstArgument", 2) {
            someProperty = [1,2,3]
        }
    }

#### Configuring the BeanDefinition (Using factory methods)

The first argument to the closure is a reference to the bean configuration instance, which you can use to configure factory methods and invoke any method on the AbstractBeanDefinition class:

    bb.beans {
        exampleBean(MyExampleBean) { bean ->
            bean.factoryMethod = "getInstance"
            bean.singleton = false
            someProperty = [1,2,3]
        }
    }

As an alternative you can also use the return value of the bean defining method to configure the bean:

    bb.beans {
        def example = exampleBean(MyExampleBean) {
            someProperty = [1,2,3]
        }
        example.factoryMethod = "getInstance"
    }

#### Using Factory beans

Spring defines the concept of factory beans and often a bean is created not from a class, but from one of these factories. In this case the bean has no class and instead you must pass the name of the factory bean to the bean:

    bb.beans {
        myFactory(ExampleFactoryBean) {
            someProperty = [1,2,3]
        }
        myBean(myFactory) {
            name = "blah"
        }
    }

Note in the example above instead of a class we pass a reference to the `myFactory` bean into the bean defining method. Another common task is provide the name of the factory method to call on the factory bean. This can be done using Groovy's named parameter syntax:

    bb.beans {
        myFactory(ExampleFactoryBean) {
            someProperty = [1,2,3]
        }
        myBean(myFactory:"getInstance") {
            name = "blah"
        }
    }

Here the `getInstance` method on the `ExampleFactoryBean` bean will be called in order to create the `myBean` bean.

#### Creating Bean References at Runtime

Sometimes you don't know the name of the bean to be created until runtime. In this case you can use a string interpolation to invoke a bean defining method dynamically:

    def beanName = "example"
    bb.beans {
        "${beanName}Bean"(MyExampleBean) {
            someProperty = [1,2,3]
        }
    }

In this case the `beanName` variable defined earlier is used when invoking a bean defining method.

Furthermore, because sometimes bean names are not known until runtime you may need to reference them by name when wiring together other beans. In this case using the `ref` method:

    def beanName = "example"
    bb.beans {
        "${beanName}Bean"(MyExampleBean) {
            someProperty = [1,2,3]
        }
        anotherBean(AnotherBean) {
            example = ref("${beanName}Bean")
        }
    }

Here the example property of `AnotherBean` is set using a runtime reference to the `exampleBean`. The `ref` method can also be used to refer to beans from a parent `ApplicationContext` that is provided in the constructor of the `BeanBuilder`:

    ApplicationContext parent = ...//
    der bb = new BeanBuilder(parent)
    bb.beans {
        anotherBean(AnotherBean) {
            example = ref("${beanName}Bean", true)
        }
    }

Here the second parameter `true` specifies that the reference will look for the bean in the parent context.

#### Using Anonymous (Inner) Beans

You can use anonymous inner beans by setting a property of the bean to a block that takes an argument that is the bean type:

    bb.beans {
        marge(Person.class) {
            name = "marge"
            husband =  { Person p ->
                name = "homer"
                age = 45
                props = [overweight:true, height:"1.8m"]
            }
            children = [bart, lisa]
        }
        bart(Person) {
            name = "Bart"
            age = 11
        }
        lisa(Person) {
            name = "Lisa"
            age = 9
        }
    }

In the above example we set the `marge` bean's husband property to a block that creates an inner bean reference. Alternatively if you have a factory bean you can ommit the type and just use passed bean definition instead to setup the factory:

    bb.beans {
        personFactory(PersonFactory.class)
        marge(Person.class) {
            name = "marge"
            husband =  { bean ->
                bean.factoryBean = "personFactory"
                bean.factoryMethod = "newInstance"
                name = "homer"
                age = 45
                props = [overweight:true, height:"1.8m"]
            }
            children = [bart, lisa]
        }
    }

#### Abstract Beans and Parent Bean Definitions

To create an abstract bean definition define a bean that takes no class:

    class HolyGrailQuest {
        def start() { println "lets begin" }
    }
    class KnightOfTheRoundTable {
        String name
        String leader
        KnightOfTheRoundTable(String n) {
            this.name = n
        }
        HolyGrailQuest quest    def embarkOnQuest() {
            quest.start()
        }
    }def bb = new grails.spring.BeanBuilder()
    bb.beans {
        abstractBean {
            leader = "Lancelot"
        }
        …
    }

Here we define an abstract bean that sets that has a `leader` property with the value of `"Lancelot"`. Now to use the abstract bean set it as the parent of the child bean:

    bb.beans {
        …
        quest(HolyGrailQuest)
        knights(KnightOfTheRoundTable, "Camelot") { bean ->
            bean.parent = abstractBean
            quest = quest
        }
    }

> When using a parent bean you must set the parent property of the bean before setting any other properties on the bean!

If you want an abstract bean that has a class you can do it this way:

    def bb = new grails.spring.BeanBuilder()
    bb.beans {
        abstractBean(KnightOfTheRoundTable) { bean ->
            bean.'abstract' = true
            leader = "Lancelot"
        }
        quest(HolyGrailQuest)
        knights("Camelot") { bean ->
            bean.parent = abstractBean
            quest = quest
        }
    }

In the above example we create an abstract bean of type `KnightOfTheRoundTable` and use the bean argument to set it to abstract. Later we define a knights bean that has no class, but inherits the class from the parent bean.

#### Using Spring Namespaces

Since Spring 2.0, users of Spring have been granted easier access to key features via XML namespaces. With BeanBuilder you can use any Spring namespace by first declaring it:

    xmlns context:"http://www.springframework.org/schema/context"

And then invoking a method that matches the names of the Spring namespace tag and its associated attributes:

    context.'component-scan'( 'base-package' :"my.company.domain" )

You can do some useful things with Spring namespaces, such as looking up a JNDI resource:

    xmlns jee:"http://www.springframework.org/schema/jee"jee.'jndi-lookup'(id:"dataSource", 'jndi-name':"java:comp/env/myDataSource")

The example above will create a Spring bean with the identifier of `dataSource` by performing a JNDI lookup on the given JNDI name. With Spring namespaces you also get full access to all of the powerful AOP support in Spring from BeanBuilder. For example given the following two classes:

    class Person {
     int age;
     String name; void birthday() {
          ++age;
     }
    }
    class BirthdayCardSender {
       List peopleSentCards = []
       void onBirthday(Person person) {
          peopleSentCards << person
       }
    }

You can define an AOP aspect that uses a pointcut to detect whenever the `birthday()` method is called:

    xmlns aop:"http://www.springframework.org/schema/aop"
    fred(Person) {
        name = "Fred"
        age = 45
    }birthdayCardSenderAspect(BirthdayCardSender)aop {
       config("proxy-target-class":true) {
           aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) {
              after method:"onBirthday", pointcut: "execution(void ..Person.birthday()) and this(person)"
           }
       }
    }