diff --git a/spring-beans/spring-beans.gradle b/spring-beans/spring-beans.gradle index 3c5d34179e7..ddc008baf97 100644 --- a/spring-beans/spring-beans.gradle +++ b/spring-beans/spring-beans.gradle @@ -1,6 +1,5 @@ description = "Spring Beans" -apply plugin: "groovy" apply plugin: "kotlin" dependencies { @@ -14,25 +13,4 @@ dependencies { testImplementation("jakarta.annotation:jakarta.annotation-api") testFixturesApi("org.junit.jupiter:junit-jupiter-api") testFixturesImplementation("org.assertj:assertj-core") -} - -// This module does joint compilation for Java and Groovy code with the compileGroovy task. -sourceSets { - main.groovy.srcDirs += "src/main/java" - main.java.srcDirs = [] -} - -compileGroovy { - options.compilerArgs += "-Werror" -} - -// This module also builds Kotlin code and the compileKotlin task naturally depends on -// compileJava. We need to redefine dependencies to break task cycles. -tasks.named('compileGroovy') { - // Groovy only needs the declared dependencies (and not the result of Java compilation) - classpath = sourceSets.main.compileClasspath -} -tasks.named('compileKotlin') { - // Kotlin also depends on the result of Groovy compilation - classpath += files(sourceSets.main.groovy.classesDirectory) -} +} \ No newline at end of file diff --git a/spring-beans/src/main/groovy/org/springframework/beans/factory/groovy/GroovyDynamicElementReader.groovy b/spring-beans/src/main/groovy/org/springframework/beans/factory/groovy/GroovyDynamicElementReader.groovy deleted file mode 100644 index 8157450773b..00000000000 --- a/spring-beans/src/main/groovy/org/springframework/beans/factory/groovy/GroovyDynamicElementReader.groovy +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.factory.groovy - -import groovy.xml.StreamingMarkupBuilder -import org.springframework.beans.factory.config.BeanDefinitionHolder -import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate -import org.w3c.dom.Element - -/** - * Used by GroovyBeanDefinitionReader to read a Spring XML namespace expression - * in the Groovy DSL. - * - * @author Jeff Brown - * @author Juergen Hoeller - * @since 4.0 - */ -@groovy.transform.PackageScope -class GroovyDynamicElementReader extends GroovyObjectSupport { - - private final String rootNamespace - - private final Map xmlNamespaces - - private final BeanDefinitionParserDelegate delegate - - private final GroovyBeanDefinitionWrapper beanDefinition - - protected final Boolean decorating; - - private boolean callAfterInvocation = true - - - public GroovyDynamicElementReader(String namespace, Map namespaceMap, - BeanDefinitionParserDelegate delegate, GroovyBeanDefinitionWrapper beanDefinition, boolean decorating) { - super(); - this.rootNamespace = namespace - this.xmlNamespaces = namespaceMap - this.delegate = delegate - this.beanDefinition = beanDefinition; - this.decorating = decorating; - } - - - @Override - public Object invokeMethod(String name, Object args) { - if (name.equals("doCall")) { - def callable = args[0] - callable.resolveStrategy = Closure.DELEGATE_FIRST - callable.delegate = this - def result = callable.call() - - if (this.callAfterInvocation) { - afterInvocation() - this.callAfterInvocation = false - } - return result - } - - else { - StreamingMarkupBuilder builder = new StreamingMarkupBuilder(); - def myNamespace = this.rootNamespace - def myNamespaces = this.xmlNamespaces - - def callable = { - for (namespace in myNamespaces) { - mkp.declareNamespace([(namespace.key):namespace.value]) - } - if (args && (args[-1] instanceof Closure)) { - args[-1].resolveStrategy = Closure.DELEGATE_FIRST - args[-1].delegate = builder - } - delegate."$myNamespace"."$name"(*args) - } - - callable.resolveStrategy = Closure.DELEGATE_FIRST - callable.delegate = builder - def writable = builder.bind(callable) - def sw = new StringWriter() - writable.writeTo(sw) - - Element element = this.delegate.readerContext.readDocumentFromString(sw.toString()).documentElement - this.delegate.initDefaults(element) - if (this.decorating) { - BeanDefinitionHolder holder = this.beanDefinition.beanDefinitionHolder; - holder = this.delegate.decorateIfRequired(element, holder, null) - this.beanDefinition.setBeanDefinitionHolder(holder) - } - else { - def beanDefinition = this.delegate.parseCustomElement(element) - if (beanDefinition) { - this.beanDefinition.setBeanDefinition(beanDefinition) - } - } - if (this.callAfterInvocation) { - afterInvocation() - this.callAfterInvocation = false - } - return element - } - } - - /** - * Hook that subclass or anonymous classes can overwrite to implement custom behavior - * after invocation completes. - */ - protected void afterInvocation() { - // NOOP - } - -} diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 2ded080cd5d..00e1b73f342 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -541,9 +541,8 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA * @param ann the Autowired annotation * @return whether the annotation indicates that a dependency is required */ + @SuppressWarnings("cast") protected boolean determineRequiredStatus(MergedAnnotation ann) { - // Cast to (AnnotationAttributes) is required. Otherwise, the :spring-beans:compileGroovy - // task fails in the Gradle build. return determineRequiredStatus((AnnotationAttributes) ann.asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation.getType()))); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyDynamicElementReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyDynamicElementReader.java new file mode 100644 index 00000000000..7cd9e852b6e --- /dev/null +++ b/spring-beans/src/main/java/org/springframework/beans/factory/groovy/GroovyDynamicElementReader.java @@ -0,0 +1,144 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.groovy; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.Map; + +import groovy.lang.Closure; +import groovy.lang.GroovyObject; +import groovy.lang.GroovyObjectSupport; +import groovy.lang.Writable; +import groovy.xml.StreamingMarkupBuilder; +import org.w3c.dom.Element; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; + +/** + * Used by GroovyBeanDefinitionReader to read a Spring XML namespace expression + * in the Groovy DSL. + * + * @author Jeff Brown + * @author Juergen Hoeller + * @author Dave Syer + * @since 4.0 + */ +class GroovyDynamicElementReader extends GroovyObjectSupport { + + private final String rootNamespace; + + private final Map xmlNamespaces; + + private final BeanDefinitionParserDelegate delegate; + + private final GroovyBeanDefinitionWrapper beanDefinition; + + protected final boolean decorating; + + private boolean callAfterInvocation = true; + + + public GroovyDynamicElementReader(String namespace, Map namespaceMap, + BeanDefinitionParserDelegate delegate, GroovyBeanDefinitionWrapper beanDefinition, boolean decorating) { + super(); + this.rootNamespace = namespace; + this.xmlNamespaces = namespaceMap; + this.delegate = delegate; + this.beanDefinition = beanDefinition; + this.decorating = decorating; + } + + + @Override + public Object invokeMethod(String name, Object obj) { + Object[] args = (Object[]) obj; + if (name.equals("doCall")) { + @SuppressWarnings("unchecked") + Closure callable = (Closure) args[0]; + callable.setResolveStrategy(Closure.DELEGATE_FIRST); + callable.setDelegate(this); + Object result = callable.call(); + + if (this.callAfterInvocation) { + afterInvocation(); + this.callAfterInvocation = false; + } + return result; + } + else { + StreamingMarkupBuilder builder = new StreamingMarkupBuilder(); + String myNamespace = this.rootNamespace; + Map myNamespaces = this.xmlNamespaces; + + Closure callable = new Closure<>(this) { + @Override + public Object call(Object... arguments) { + ((GroovyObject) getProperty("mkp")).invokeMethod("declareNamespace", new Object[] {myNamespaces}); + int len = args.length; + if (len > 0 && args[len-1] instanceof Closure callable) { + callable.setResolveStrategy(Closure.DELEGATE_FIRST); + callable.setDelegate(builder); + } + return ((GroovyObject) ((GroovyObject) getDelegate()).getProperty(myNamespace)).invokeMethod(name, args); + } + }; + + callable.setResolveStrategy(Closure.DELEGATE_FIRST); + callable.setDelegate(builder); + Writable writable = (Writable) builder.bind(callable); + StringWriter sw = new StringWriter(); + try { + writable.writeTo(sw); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + + Element element = this.delegate.getReaderContext().readDocumentFromString(sw.toString()).getDocumentElement(); + this.delegate.initDefaults(element); + if (this.decorating) { + BeanDefinitionHolder holder = this.beanDefinition.getBeanDefinitionHolder(); + holder = this.delegate.decorateIfRequired(element, holder, null); + this.beanDefinition.setBeanDefinitionHolder(holder); + } + else { + BeanDefinition beanDefinition = this.delegate.parseCustomElement(element); + if (beanDefinition != null) { + this.beanDefinition.setBeanDefinition((AbstractBeanDefinition) beanDefinition); + } + } + if (this.callAfterInvocation) { + afterInvocation(); + this.callAfterInvocation = false; + } + return element; + } + } + + /** + * Hook that subclasses or anonymous classes can override to implement custom behavior + * after invocation completes. + */ + protected void afterInvocation() { + // NOOP + } + +} diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 6c2e05068c2..9c00e0fcf38 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -1935,6 +1935,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp * * @since 5.3 */ + @SuppressWarnings("serial") private class BeanPostProcessorCacheAwareList extends CopyOnWriteArrayList { @Override diff --git a/spring-context/spring-context.gradle b/spring-context/spring-context.gradle index f7bb843fcc1..60130032046 100644 --- a/spring-context/spring-context.gradle +++ b/spring-context/spring-context.gradle @@ -1,6 +1,5 @@ description = "Spring Context" -apply plugin: "groovy" apply plugin: "kotlin" dependencies { diff --git a/spring-context/src/test/groovy/org/springframework/context/groovy/GroovyBeanDefinitionReaderTests.groovy b/spring-context/src/test/groovy/org/springframework/context/groovy/GroovyBeanDefinitionReaderTests.groovy deleted file mode 100644 index eac5493d907..00000000000 --- a/spring-context/src/test/groovy/org/springframework/context/groovy/GroovyBeanDefinitionReaderTests.groovy +++ /dev/null @@ -1,1063 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.groovy - -import org.junit.jupiter.api.Test - -import org.springframework.aop.SpringProxy -import org.springframework.beans.factory.ObjectFactory -import org.springframework.beans.factory.config.Scope -import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader -import org.springframework.context.support.GenericApplicationContext -import org.springframework.context.support.GenericGroovyApplicationContext -import org.springframework.stereotype.Component - -import static groovy.test.GroovyAssert.* - -/** - * @author Jeff Brown - * @author Sam Brannen - */ -class GroovyBeanDefinitionReaderTests { - - @Test - void importSpringXml() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - importBeans "classpath:org/springframework/context/groovy/test.xml" - } - - appCtx.refresh() - - def foo = appCtx.getBean("foo") - assertEquals "hello", foo - } - - @Test - void importBeansFromGroovy() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - importBeans "classpath:org/springframework/context/groovy/applicationContext.groovy" - } - - appCtx.refresh() - - def foo = appCtx.getBean("foo") - assertEquals "hello", foo - } - - @Test - void singletonPropertyOnBeanDefinition() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - singletonBean(Bean1) { bean -> - bean.singleton = true - } - nonSingletonBean(Bean1) { bean -> - bean.singleton = false - } - unSpecifiedScopeBean(Bean1) - } - appCtx.refresh() - - assertTrue 'singletonBean should have been a singleton', appCtx.isSingleton('singletonBean') - assertFalse 'nonSingletonBean should not have been a singleton', appCtx.isSingleton('nonSingletonBean') - assertTrue 'unSpecifiedScopeBean should not have been a singleton', appCtx.isSingleton('unSpecifiedScopeBean') - } - - @Test - void inheritPropertiesFromAbstractBean() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - myB(Bean1){ - person = "wombat" - } - - myAbstractA(Bean2){ bean -> - bean.'abstract' = true - age = 10 - bean1 = myB - } - myConcreteB { - it.parent = myAbstractA - } - } - - appCtx.refresh() - - def bean = appCtx.getBean("myConcreteB") - assertEquals 10, bean.age - assertNotNull bean.bean1 - } - - @Test - void contextComponentScanSpringTag() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - xmlns context:"http://www.springframework.org/schema/context" - - context.'component-scan'( 'base-package' :" org.springframework.context.groovy" ) - } - - appCtx.refresh() - - def p = appCtx.getBean("person") - assertTrue(p instanceof AdvisedPerson) - } - - @Test - void useSpringNamespaceAsMethod() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - xmlns aop:"http://www.springframework.org/schema/aop" - - fred(AdvisedPerson) { - name = "Fred" - age = 45 - } - birthdayCardSenderAspect(BirthdayCardSender) - - aop { - config("proxy-target-class":true) { - aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) { - after method:"onBirthday", pointcut: "execution(void org.springframework.context.groovy.AdvisedPerson.birthday()) and this(person)" - } - } - } - } - - appCtx.refresh() - - def fred = appCtx.getBean("fred") - assertTrue (fred instanceof SpringProxy) - fred.birthday() - - BirthdayCardSender birthDaySender = appCtx.getBean("birthdayCardSenderAspect") - - assertEquals 1, birthDaySender.peopleSentCards.size() - assertEquals "Fred", birthDaySender.peopleSentCards[0].name - } - - @Test - void useTwoSpringNamespaces() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - TestScope scope = new TestScope() - appCtx.getBeanFactory().registerScope("test", scope) - - reader.beans { - xmlns aop:"http://www.springframework.org/schema/aop" - xmlns util:"http://www.springframework.org/schema/util" - scopedList(ArrayList) { bean -> - bean.scope = "test" - aop.'scoped-proxy'() - } - util.list(id: 'foo') { - value 'one' - value 'two' - } - } - appCtx.refresh() - - assert ['one', 'two'] == appCtx.getBean("foo") - - assertNotNull appCtx.getBean("scopedList") - assertNotNull appCtx.getBean("scopedList").size() - assertNotNull appCtx.getBean("scopedList").size() - - // should only be true because bean not initialized until proxy called - assertEquals 2, scope.instanceCount - - appCtx = new GenericApplicationContext() - reader = new GroovyBeanDefinitionReader(appCtx) - appCtx.getBeanFactory().registerScope("test", scope) - - reader.beans { - xmlns aop:"http://www.springframework.org/schema/aop", - util:"http://www.springframework.org/schema/util" - scopedList(ArrayList) { bean -> - bean.scope = "test" - aop.'scoped-proxy'() - } - util.list(id: 'foo') { - value 'one' - value 'two' - } - } - appCtx.refresh() - - assert ['one', 'two'] == appCtx.getBean("foo") - - assertNotNull appCtx.getBean("scopedList") - assertNotNull appCtx.getBean("scopedList").size() - assertNotNull appCtx.getBean("scopedList").size() - - // should only be true because bean not initialized until proxy called - assertEquals 4, scope.instanceCount - } - - @Test - void springAopSupport() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - xmlns aop:"http://www.springframework.org/schema/aop" - - fred(AdvisedPerson) { - name = "Fred" - age = 45 - } - birthdayCardSenderAspect(BirthdayCardSender) - - aop.config("proxy-target-class":true) { - aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) { - after method:"onBirthday", pointcut: "execution(void org.springframework.context.groovy.AdvisedPerson.birthday()) and this(person)" - } - } - } - - appCtx.refresh() - - def fred = appCtx.getBean("fred") - assertTrue (fred instanceof SpringProxy) - fred.birthday() - - BirthdayCardSender birthDaySender = appCtx.getBean("birthdayCardSenderAspect") - - assertEquals 1, birthDaySender.peopleSentCards.size() - assertEquals "Fred", birthDaySender.peopleSentCards[0].name - } - - @Test - void springScopedProxyBean() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - TestScope scope = new TestScope() - appCtx.getBeanFactory().registerScope("test", scope) - reader.beans { - xmlns aop:"http://www.springframework.org/schema/aop" - scopedList(ArrayList) { bean -> - bean.scope = "test" - aop.'scoped-proxy'() - } - } - appCtx.refresh() - - assertNotNull appCtx.getBean("scopedList") - assertNotNull appCtx.getBean("scopedList").size() - assertNotNull appCtx.getBean("scopedList").size() - - // should only be true because bean not initialized until proxy called - assertEquals 2, scope.instanceCount - } - - @Test - void springNamespaceBean() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - xmlns util: 'http://www.springframework.org/schema/util' - util.list(id: 'foo') { - value 'one' - value 'two' - } - } - appCtx.refresh() - - assert ['one', 'two'] == appCtx.getBean('foo') - } - - @Test - void namedArgumentConstructor() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - holyGrail(HolyGrailQuest) - knights(KnightOfTheRoundTable, "Camelot", leader:"lancelot", quest: holyGrail) - } - appCtx.refresh() - - KnightOfTheRoundTable knights = appCtx.getBean("knights") - HolyGrailQuest quest = appCtx.getBean("holyGrail") - - assertEquals "Camelot", knights.name - assertEquals "lancelot", knights.leader - assertEquals quest, knights.quest - } - - @Test - void abstractBeanDefinition() { - def appCtx = new GenericGroovyApplicationContext() - appCtx.reader.beans { - abstractBean { - leader = "Lancelot" - } - quest(HolyGrailQuest) - knights(KnightOfTheRoundTable, "Camelot") { bean -> - bean.parent = abstractBean - quest = quest - } - } - appCtx.refresh() - - def knights = appCtx.knights - assert knights - shouldFail(org.springframework.beans.factory.BeanIsAbstractException) { - appCtx.abstractBean - } - assertEquals "Lancelot", knights.leader - } - - @Test - void abstractBeanDefinitionWithClass() { - def appCtx = new GenericGroovyApplicationContext() - appCtx.reader.beans { - abstractBean(KnightOfTheRoundTable) { bean -> - bean.'abstract' = true - leader = "Lancelot" - } - quest(HolyGrailQuest) - knights("Camelot") { bean -> - bean.parent = abstractBean - quest = quest - } - } - appCtx.refresh() - - shouldFail(org.springframework.beans.factory.BeanIsAbstractException) { - appCtx.abstractBean - } - def knights = appCtx.knights - assert knights - assertEquals "Lancelot", knights.leader - } - - @Test - void scopes() { - def appCtx = new GenericGroovyApplicationContext() - appCtx.reader.beans { - myBean(ScopeTestBean) { bean -> - bean.scope = "prototype" - } - myBean2(ScopeTestBean) - } - appCtx.refresh() - - def b1 = appCtx.myBean - def b2 = appCtx.myBean - - assert b1 != b2 - - b1 = appCtx.myBean2 - b2 = appCtx.myBean2 - - assertEquals b1, b2 - } - - @Test - void simpleBean() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - bean1(Bean1) { - person = "homer" - age = 45 - props = [overweight:true, height:"1.8m"] - children = ["bart", "lisa"] - } - } - appCtx.refresh() - - assert appCtx.containsBean("bean1") - def bean1 = appCtx.getBean("bean1") - - assertEquals "homer", bean1.person - assertEquals 45, bean1.age - assertEquals true, bean1.props?.overweight - assertEquals "1.8m", bean1.props?.height - assertEquals(["bart", "lisa"], bean1.children) - - } - - @Test - void beanWithParentRef() { - def parentAppCtx = new GenericApplicationContext() - def parentBeanReader = new GroovyBeanDefinitionReader(parentAppCtx) - parentBeanReader.beans { - homer(Bean1) { - person = "homer" - age = 45 - props = [overweight:true, height:"1.8m"] - children = ["bart", "lisa"] - } - } - parentAppCtx.refresh() - - def appCtx = new GenericApplicationContext(parentAppCtx) - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - bart(Bean2) { - person = "bart" - parent = ref("homer", true) - } - } - appCtx.refresh() - - assert appCtx.containsBean("bart") - def bart = appCtx.getBean("bart") - assertEquals "homer",bart.parent?.person - } - - @Test - void withAnonymousInnerBean() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - bart(Bean1) { - person = "bart" - age = 11 - } - lisa(Bean1) { - person = "lisa" - age = 9 - } - marge(Bean2) { - person = "marge" - bean1 = { Bean1 b -> - person = "homer" - age = 45 - props = [overweight:true, height:"1.8m"] - children = ["bart", "lisa"] } - children = [bart, lisa] - } - } - appCtx.refresh() - - def marge = appCtx.getBean("marge") - assertEquals "homer", marge.bean1.person - } - - @Test - void withUntypedAnonymousInnerBean() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - homer(Bean1Factory) - bart(Bean1) { - person = "bart" - age = 11 - } - lisa(Bean1) { - person = "lisa" - age = 9 - } - marge(Bean2) { - person = "marge" - bean1 = { bean -> - bean.factoryBean = "homer" - bean.factoryMethod = "newInstance" - person = "homer" } - children = [bart, lisa] - } - } - appCtx.refresh() - - def marge = appCtx.getBean("marge") - assertEquals "homer", marge.bean1.person - } - - @Test - void beanReferences() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - homer(Bean1) { - person = "homer" - age = 45 - props = [overweight:true, height:"1.8m"] - children = ["bart", "lisa"] - } - bart(Bean1) { - person = "bart" - age = 11 - } - lisa(Bean1) { - person = "lisa" - age = 9 - } - marge(Bean2) { - person = "marge" - bean1 = homer - children = [bart, lisa] - } - } - appCtx.refresh() - - def homer = appCtx.getBean("homer") - def marge = appCtx.getBean("marge") - def bart = appCtx.getBean("bart") - def lisa = appCtx.getBean("lisa") - - assertEquals homer, marge.bean1 - assertEquals 2, marge.children.size() - - assertTrue marge.children.contains(bart) - assertTrue marge.children.contains(lisa) - } - - @Test - void beanWithConstructor() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - homer(Bean1) { - person = "homer" - age = 45 - } - marge(Bean3, "marge", homer) { - age = 40 - } - } - appCtx.refresh() - - def marge = appCtx.getBean("marge") - assertEquals "marge", marge.person - assertEquals "homer", marge.bean1.person - assertEquals 40, marge.age - } - - @Test - void beanWithFactoryMethod() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - homer(Bean1) { - person = "homer" - age = 45 - } - def marge = marge(Bean4) { - person = "marge" - } - marge.factoryMethod = "getInstance" - } - appCtx.refresh() - - def marge = appCtx.getBean("marge") - - assert "marge", marge.person - } - - @Test - void beanWithFactoryMethodUsingClosureArgs() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - homer(Bean1) { - person = "homer" - age = 45 - } - marge(Bean4) { bean -> - bean.factoryMethod = "getInstance" - person = "marge" - } - } - appCtx.refresh() - - def marge = appCtx.getBean("marge") - assert "marge", marge.person - } - - @Test - void beanWithFactoryMethodWithConstructorArgs() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - beanFactory(Bean1FactoryWithArgs){} - - homer(beanFactory:"newInstance", "homer") { - age = 45 - } - //Test with no closure body - marge(beanFactory:"newInstance", "marge") - - //Test more verbose method - mcBain("mcBain"){ - bean -> - bean.factoryBean="beanFactory" - bean.factoryMethod="newInstance" - - } - } - appCtx.refresh() - - def homer = appCtx.getBean("homer") - - assert "homer", homer.person - assert 45, homer.age - - assert "marge", appCtx.getBean("marge").person - - assert "mcBain", appCtx.getBean("mcBain").person - } - - @Test - void getBeanDefinitions() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - jeff(Bean1) { - person = 'jeff' - } - graeme(Bean1) { - person = 'graeme' - } - guillaume(Bean1) { - person = 'guillaume' - } - } - - assertEquals 'beanDefinitions was the wrong size', 3, reader.registry.beanDefinitionCount - assertNotNull 'beanDefinitions did not contain jeff', reader.registry.getBeanDefinition('jeff') - assertNotNull 'beanDefinitions did not contain guillaume', reader.registry.getBeanDefinition('guillaume') - assertNotNull 'beanDefinitions did not contain graeme', reader.registry.getBeanDefinition('graeme') - } - - @Test - void beanWithFactoryBean() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - myFactory(Bean1Factory) - - homer(myFactory) { bean -> - bean.factoryMethod = "newInstance" - person = "homer" - age = 45 - } - } - appCtx.refresh() - - def homer = appCtx.getBean("homer") - - assertEquals "homer", homer.person - } - - @Test - void beanWithFactoryBeanAndMethod() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - myFactory(Bean1Factory) - - homer(myFactory:"newInstance") { bean -> - person = "homer" - age = 45 - } - } - - appCtx.refresh() - - def homer = appCtx.getBean("homer") - assertEquals "homer", homer.person - } - - @Test - void loadExternalBeans() { - def appCtx = new GenericGroovyApplicationContext("org/springframework/context/groovy/applicationContext.groovy") - - assert appCtx.containsBean("foo") - def foo = appCtx.getBean("foo") - } - - @Test - void loadExternalBeansWithExplicitRefresh() { - def appCtx = new GenericGroovyApplicationContext() - appCtx.load("org/springframework/context/groovy/applicationContext.groovy") - appCtx.refresh() - - assert appCtx.containsBean("foo") - def foo = appCtx.getBean("foo") - } - - @Test - void holyGrailWiring() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - quest(HolyGrailQuest) - - knight(KnightOfTheRoundTable, "Bedivere") { - quest = ref("quest") - } - } - - appCtx.refresh() - - def knight = appCtx.getBean("knight") - knight.embarkOnQuest() - } - - @Test - void abstractBeanSpecifyingClass() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - abstractKnight(KnightOfTheRoundTable) { bean -> - bean.'abstract' = true - leader = "King Arthur" - } - - lancelot("lancelot") { bean -> - bean.parent = ref("abstractKnight") - } - - abstractPerson(Bean1) { bean -> - bean.'abstract'=true - age = 45 - } - homerBean { bean -> - bean.parent = ref("abstractPerson") - person = "homer" - } - } - appCtx.refresh() - - def lancelot = appCtx.getBean("lancelot") - assertEquals "King Arthur", lancelot.leader - assertEquals "lancelot", lancelot.name - - def homerBean = appCtx.getBean("homerBean") - - assertEquals 45, homerBean.age - assertEquals "homer", homerBean.person - } - - @Test - void groovyBeanDefinitionReaderWithScript() { - def script = ''' -def appCtx = new org.springframework.context.support.GenericGroovyApplicationContext() -appCtx.reader.beans { -quest(org.springframework.context.groovy.HolyGrailQuest) {} - -knight(org.springframework.context.groovy.KnightOfTheRoundTable, "Bedivere") { quest = quest } -} -appCtx.refresh() -return appCtx -''' - def appCtx = new GroovyShell().evaluate(script) - - def knight = appCtx.getBean('knight') - knight.embarkOnQuest() - } - - // test for GRAILS-5057 - @Test - void registerBeans() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - personA(AdvisedPerson) { - name = "Bob" - } - } - - appCtx.refresh() - assertEquals "Bob", appCtx.getBean("personA").name - - appCtx = new GenericApplicationContext() - reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - personA(AdvisedPerson) { - name = "Fred" - } - } - - appCtx.refresh() - assertEquals "Fred", appCtx.getBean("personA").name - } - - @Test - void listOfBeansAsConstructorArg() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - - reader.beans { - someotherbean(SomeOtherClass, new File('somefile.txt')) - someotherbean2(SomeOtherClass, new File('somefile.txt')) - - somebean(SomeClass, [someotherbean, someotherbean2]) - } - - assert appCtx.containsBean('someotherbean') - assert appCtx.containsBean('someotherbean2') - assert appCtx.containsBean('somebean') - } - - @Test - void beanWithListAndMapConstructor() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - bart(Bean1) { - person = "bart" - age = 11 - } - lisa(Bean1) { - person = "lisa" - age = 9 - } - - beanWithList(Bean5, [bart, lisa]) - - // test runtime references both as ref() and as plain name - beanWithMap(Bean6, [bart:bart, lisa:ref('lisa')]) - } - appCtx.refresh() - - def beanWithList = appCtx.getBean("beanWithList") - assertEquals 2, beanWithList.people.size() - assertEquals "bart", beanWithList.people[0].person - - def beanWithMap = appCtx.getBean("beanWithMap") - assertEquals 9, beanWithMap.peopleByName.lisa.age - assertEquals "bart", beanWithMap.peopleByName.bart.person - } - - @Test - void anonymousInnerBeanViaBeanMethod() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - bart(Bean1) { - person = "bart" - age = 11 - } - lisa(Bean1) { - person = "lisa" - age = 9 - } - marge(Bean2) { - person = "marge" - bean1 = bean(Bean1) { - person = "homer" - age = 45 - props = [overweight:true, height:"1.8m"] - children = ["bart", "lisa"] - } - children = [bart, lisa] - } - } - appCtx.refresh() - - def marge = appCtx.getBean("marge") - assertEquals "homer", marge.bean1.person - } - - @Test - void anonymousInnerBeanViaBeanMethodWithConstructorArgs() { - def appCtx = new GenericApplicationContext() - def reader = new GroovyBeanDefinitionReader(appCtx) - reader.beans { - bart(Bean1) { - person = "bart" - age = 11 - } - lisa(Bean1) { - person = "lisa" - age = 9 - } - marge(Bean2) { - person = "marge" - bean3 = bean(Bean3, "homer", lisa) { - person = "homer" - age = 45 - } - children = [bart, lisa] - } - } - appCtx.refresh() - - def marge = appCtx.getBean("marge") - - assertEquals "homer", marge.bean3.person - assertEquals "lisa", marge.bean3.bean1.person - } -} - - -class HolyGrailQuest { - void start() { println "lets begin" } -} - -class KnightOfTheRoundTable { - String name - String leader - - KnightOfTheRoundTable(String n) { - this.name = n - } - - HolyGrailQuest quest - - void embarkOnQuest() { - quest.start() - } -} - -// simple bean -class Bean1 { - String person - int age - Properties props - List children -} - -// bean referencing other bean -class Bean2 { - int age - String person - Bean1 bean1 - Bean3 bean3 - Properties props - List children - Bean1 parent -} - -// bean with constructor args -class Bean3 { - Bean3(String person, Bean1 bean1) { - this.person = person - this.bean1 = bean1 - } - String person - Bean1 bean1 - int age -} - -// bean with factory method -class Bean4 { - private Bean4() {} - static Bean4 getInstance() { - return new Bean4() - } - String person -} - -// bean with List-valued constructor arg -class Bean5 { - Bean5(List people) { - this.people = people - } - List people -} - -// bean with Map-valued constructor arg -class Bean6 { - Bean6(Map peopleByName) { - this.peopleByName = peopleByName - } - Map peopleByName -} - -// a factory bean -class Bean1Factory { - Bean1 newInstance() { - return new Bean1() - } -} - -class ScopeTestBean { -} - -class TestScope implements Scope { - - int instanceCount - - @Override - public Object remove(String name) { - // do nothing - } - - @Override - public void registerDestructionCallback(String name, Runnable callback) { - } - - @Override - public String getConversationId() { - return "mock" - } - - @Override - public Object get(String name, ObjectFactory objectFactory) { - instanceCount++ - objectFactory.getObject() - } - - @Override - public Object resolveContextualObject(String s) { - return null; // noop - } -} - -class BirthdayCardSender { - List peopleSentCards = [] - - public void onBirthday(AdvisedPerson person) { - peopleSentCards << person - } -} - -@Component(value = "person") -public class AdvisedPerson { - int age; - String name; - - public void birthday() { - ++age; - } -} - -class SomeClass { - public SomeClass(List soc) {} -} - -class SomeOtherClass { - public SomeOtherClass(File f) {} -} - -// a factory bean that takes arguments -class Bean1FactoryWithArgs { - Bean1 newInstance(String name) { - new Bean1(person:name) - } -} diff --git a/spring-context/src/test/groovy/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.groovy b/spring-context/src/test/java/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.java similarity index 50% rename from spring-context/src/test/groovy/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.groovy rename to spring-context/src/test/java/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.java index 948fef89ea2..51ba8d349fc 100644 --- a/spring-context/src/test/groovy/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.groovy +++ b/spring-context/src/test/java/org/springframework/context/groovy/GroovyApplicationContextDynamicBeanPropertyTests.java @@ -14,14 +14,16 @@ * limitations under the License. */ -package org.springframework.context.groovy +package org.springframework.context.groovy; -import org.junit.jupiter.api.Test +import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.NoSuchBeanDefinitionException -import org.springframework.context.support.GenericGroovyApplicationContext +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.support.GenericGroovyApplicationContext; -import static groovy.test.GroovyAssert.* +import static groovy.test.GroovyAssert.assertEquals; +import static groovy.test.GroovyAssert.assertNotNull; +import static groovy.test.GroovyAssert.assertThrows; /** * @author Jeff Brown @@ -31,24 +33,26 @@ class GroovyApplicationContextDynamicBeanPropertyTests { @Test void testAccessDynamicBeanProperties() { - def ctx = new GenericGroovyApplicationContext(); - ctx.reader.loadBeanDefinitions("org/springframework/context/groovy/applicationContext.groovy"); - ctx.refresh() + var ctx = new GenericGroovyApplicationContext(); + ctx.getReader().loadBeanDefinitions("org/springframework/context/groovy/applicationContext.groovy"); + ctx.refresh(); - def framework = ctx.framework - assertNotNull 'could not find framework bean', framework - assertEquals 'Grails', framework + var framework = ctx.getProperty("framework"); + assertNotNull("could not find framework bean", framework); + assertEquals("Grails", framework); + ctx.close(); } @Test void testAccessingNonExistentBeanViaDynamicProperty() { - def ctx = new GenericGroovyApplicationContext(); - ctx.reader.loadBeanDefinitions("org/springframework/context/groovy/applicationContext.groovy"); - ctx.refresh() + var ctx = new GenericGroovyApplicationContext(); + ctx.getReader().loadBeanDefinitions("org/springframework/context/groovy/applicationContext.groovy"); + ctx.refresh(); - def err = shouldFail NoSuchBeanDefinitionException, { ctx.someNonExistentBean } + var err = assertThrows(NoSuchBeanDefinitionException.class, () -> ctx.getProperty("someNonExistentBean")); - assertEquals "No bean named 'someNonExistentBean' available", err.message + assertEquals("No bean named 'someNonExistentBean' available", err.getMessage()); + ctx.close(); } } diff --git a/spring-context/src/test/java/org/springframework/context/groovy/GroovyBeanDefinitionReaderTests.java b/spring-context/src/test/java/org/springframework/context/groovy/GroovyBeanDefinitionReaderTests.java new file mode 100644 index 00000000000..fa3fe2ea5c9 --- /dev/null +++ b/spring-context/src/test/java/org/springframework/context/groovy/GroovyBeanDefinitionReaderTests.java @@ -0,0 +1,1298 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.groovy; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import groovy.lang.GroovyShell; +import org.junit.jupiter.api.Test; + +import org.springframework.aop.SpringProxy; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.config.Scope; +import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.context.support.GenericGroovyApplicationContext; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.stereotype.Component; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +public class GroovyBeanDefinitionReaderTests { + + @Test + void importSpringXml() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + beans { + importBeans "classpath:org/springframework/context/groovy/test.xml" + } + """).getBytes())); + + appCtx.refresh(); + + var foo = appCtx.getBean("foo"); + assertThat(foo).isEqualTo("hello"); + } + + @Test + void importBeansFromGroovy() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + beans { + importBeans "classpath:org/springframework/context/groovy/applicationContext.groovy" + } + """).getBytes())); + + appCtx.refresh(); + + var foo = appCtx.getBean("foo"); + assertThat(foo).isEqualTo("hello"); + } + + @Test + void singletonPropertyOnBeanDefinition() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy; + beans { + singletonBean(Bean1) { bean -> + bean.singleton = true + } + nonSingletonBean(Bean1) { bean -> + bean.singleton = false + } + unSpecifiedScopeBean(Bean1) + } + """).getBytes())); + appCtx.refresh(); + + assertThat(appCtx.isSingleton("singletonBean")).as("singletonBean should have been a singleton").isTrue(); + assertThat(appCtx.isSingleton("nonSingletonBean")).as("nonSingletonBean should not have been a singleton").isFalse(); + assertThat(appCtx.isSingleton("unSpecifiedScopeBean")).as("unSpecifiedScopeBean should not have been a singleton").isTrue(); + } + + @Test + void inheritPropertiesFromAbstractBean() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy; + beans { + myB(Bean1){ + person = "wombat" + } + + myAbstractA(Bean2){ bean -> + bean."abstract" = true + age = 10 + bean1 = myB + } + myConcreteB { + it.parent = myAbstractA + } + } + """).getBytes())); + appCtx.refresh(); + + Bean2 bean = (Bean2) appCtx.getBean("myConcreteB"); + assertThat(bean.age).isEqualTo(10); + assertThat(bean.bean1).isNotNull(); + } + + @Test + void contextComponentScanSpringTag() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + beans { + xmlns context:"http://www.springframework.org/schema/context" + + context.'component-scan'( 'base-package':"org.springframework.context.groovy" ) + } + """).getBytes())); + appCtx.refresh(); + + var p = appCtx.getBean("person"); + assertThat(p).isInstanceOf(AdvisedPerson.class); + } + + @Test + void useSpringNamespaceAsMethod() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy; + beans { + xmlns aop:"http://www.springframework.org/schema/aop" + + fred(AdvisedPerson) { + name = "Fred" + age = 45 + } + birthdayCardSenderAspect(BirthdayCardSender) + + aop { + config("proxy-target-class":true) { + aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) { + after method:"onBirthday", pointcut: "execution(void org.springframework.context.groovy.AdvisedPerson.birthday()) and this(person)" + } + } + } + } + """).getBytes())); + + appCtx.refresh(); + + AdvisedPerson fred = (AdvisedPerson) appCtx.getBean("fred"); + assertThat(fred).isInstanceOf(SpringProxy.class); + fred.birthday(); + + BirthdayCardSender birthDaySender = (BirthdayCardSender) appCtx.getBean("birthdayCardSenderAspect"); + + assertThat(birthDaySender.peopleSentCards).hasSize(1); + assertThat(birthDaySender.peopleSentCards.get(0).getName()).isEqualTo("Fred"); + } + + @SuppressWarnings("unchecked") + @Test + void useTwoSpringNamespaces() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + TestScope scope = new TestScope(); + appCtx.getBeanFactory().registerScope("test", scope); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + xmlns aop:"http://www.springframework.org/schema/aop" + xmlns util:"http://www.springframework.org/schema/util" + bean1(Bean1) { bean -> + bean.scope = "test" + aop.'scoped-proxy'() + } + util.list(id: 'foo') { + value 'one' + value 'two' + } + } + """).getBytes())); + appCtx.refresh(); + + assertThat((List)appCtx.getBean("foo")).containsExactly("one", "two"); + + assertThat(appCtx.getBean("bean1")).isNotNull(); + assertThat(((Bean1)appCtx.getBean("bean1")).getPerson()).isNull(); + assertThat(((Bean1)appCtx.getBean("bean1")).getPerson()).isNull(); + + // should only be true because bean not initialized until proxy called + assertThat(scope.instanceCount).isEqualTo(2); + + appCtx = new GenericApplicationContext(); + reader = new GroovyBeanDefinitionReader(appCtx); + appCtx.getBeanFactory().registerScope("test", scope); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + import java.util.ArrayList + beans { + xmlns aop:"http://www.springframework.org/schema/aop", + util:"http://www.springframework.org/schema/util" + bean1(Bean1) { bean -> + bean.scope = "test" + aop.'scoped-proxy'() + } + util.list(id: 'foo') { + value 'one' + value 'two' + } + } + """).getBytes())); + appCtx.refresh(); + + assertThat((List)appCtx.getBean("foo")).containsExactly("one", "two"); + + assertThat(appCtx.getBean("bean1")).isNotNull(); + assertThat(((Bean1)appCtx.getBean("bean1")).getPerson()).isNull(); + assertThat(((Bean1)appCtx.getBean("bean1")).getPerson()).isNull(); + + // should only be true because bean not initialized until proxy called + assertThat(scope.instanceCount).isEqualTo(4); + } + + @Test + void springAopSupport() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + xmlns aop:"http://www.springframework.org/schema/aop" + + fred(AdvisedPerson) { + name = "Fred" + age = 45 + } + birthdayCardSenderAspect(BirthdayCardSender) + + aop.config("proxy-target-class":true) { + aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) { + after method:"onBirthday", pointcut: "execution(void org.springframework.context.groovy.AdvisedPerson.birthday()) and this(person)" + } + } + } + """).getBytes())); + + appCtx.refresh(); + + AdvisedPerson fred = (AdvisedPerson) appCtx.getBean("fred"); + assertThat(fred).isInstanceOf(SpringProxy.class); + fred.birthday(); + + BirthdayCardSender birthDaySender = (BirthdayCardSender) appCtx.getBean("birthdayCardSenderAspect"); + + assertThat(birthDaySender.peopleSentCards).hasSize(1); + assertThat(birthDaySender.peopleSentCards.get(0).getName()).isEqualTo("Fred"); + } + + @Test + void springScopedProxyBean() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + TestScope scope = new TestScope(); + appCtx.getBeanFactory().registerScope("test", scope); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + xmlns aop:"http://www.springframework.org/schema/aop" + scopedList(Bean1) { bean -> + bean.scope = "test" + aop.'scoped-proxy'() + } + } + """).getBytes())); + appCtx.refresh(); + + assertThat(appCtx.getBean("scopedList")).isNotNull(); + assertThat(((Bean1)appCtx.getBean("scopedList")).getPerson()).isNull(); + assertThat(((Bean1)appCtx.getBean("scopedList")).getPerson()).isNull(); + + // should only be true because bean not initialized until proxy called + assertThat(scope.instanceCount).isEqualTo(2); + } + + @Test + void springNamespaceBean() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + xmlns util: 'http://www.springframework.org/schema/util' + util.list(id: 'foo') { + value 'one' + value 'two' + } + } + """).getBytes())); + appCtx.refresh(); + + assertThat((List)appCtx.getBean("foo")).contains("one", "two"); + } + + @Test + void namedArgumentConstructor() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + holyGrail(HolyGrailQuest) + knights(KnightOfTheRoundTable, "Camelot", leader:"lancelot", quest: holyGrail) + } + """).getBytes())); + appCtx.refresh(); + + KnightOfTheRoundTable knights = (KnightOfTheRoundTable) appCtx.getBean("knights"); + HolyGrailQuest quest = (HolyGrailQuest) appCtx.getBean("holyGrail"); + + assertThat(knights.getName()).isEqualTo("Camelot"); + assertThat(knights.leader).isEqualTo("lancelot"); + assertThat(knights.quest).isEqualTo(quest); + } + + @Test + void abstractBeanDefinition() { + var appCtx = new GenericGroovyApplicationContext(); + appCtx.getReader().loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + abstractBean { + leader = "Lancelot" + } + quest(HolyGrailQuest) + knights(KnightOfTheRoundTable, "Camelot") { bean -> + bean.parent = abstractBean + quest = quest + } + } + """).getBytes())); + appCtx.refresh(); + + KnightOfTheRoundTable knights = (KnightOfTheRoundTable) appCtx.getProperty("knights"); + assertThat(knights).isNotNull(); + assertThatExceptionOfType(org.springframework.beans.factory.BeanIsAbstractException.class).isThrownBy(() -> + appCtx.getProperty("abstractBean")); + assertThat(knights.leader).isEqualTo("Lancelot"); + } + + @Test + void abstractBeanDefinitionWithClass() { + var appCtx = new GenericGroovyApplicationContext(); + appCtx.getReader().loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + abstractBean(KnightOfTheRoundTable) { bean -> + bean.'abstract' = true + leader = "Lancelot" + } + quest(HolyGrailQuest) + knights("Camelot") { bean -> + bean.parent = abstractBean + quest = quest + } + } + """).getBytes())); + appCtx.refresh(); + + assertThatExceptionOfType(org.springframework.beans.factory.BeanIsAbstractException.class).isThrownBy(() -> + appCtx.getProperty("abstractBean")); + + KnightOfTheRoundTable knights = (KnightOfTheRoundTable) appCtx.getProperty("knights"); + assertThat(knights).isNotNull(); + assertThat(knights.leader).isEqualTo("Lancelot"); + } + + @Test + void scopes() { + var appCtx = new GenericGroovyApplicationContext(); + appCtx.getReader().loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + myBean(ScopeTestBean) { bean -> + bean.scope = "prototype" + } + myBean2(ScopeTestBean) + } + """).getBytes())); + appCtx.refresh(); + + var b1 = appCtx.getProperty("myBean"); + var b2 = appCtx.getProperty("myBean"); + + assertThat(b1).isNotSameAs(b2); + + b1 = appCtx.getProperty("myBean2"); + b2 = appCtx.getProperty("myBean2"); + + assertThat(b1).isEqualTo(b2); + } + + @Test + void simpleBean() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + bean1(Bean1) { + person = "homer" + age = 45 + props = [overweight:"true", height:"1.8m"] + children = ["bart", "lisa"] + } + } + """).getBytes())); + appCtx.refresh(); + + assertThat(appCtx.containsBean("bean1")).isTrue(); + Bean1 bean1 = (Bean1) appCtx.getBean("bean1"); + + assertThat(bean1.person).isEqualTo("homer"); + assertThat(bean1.age).isEqualTo(45); + assertThat(bean1.props.getProperty("overweight")).isEqualTo("true"); + assertThat(bean1.props.getProperty("height")).isEqualTo("1.8m"); + assertThat(bean1.children).containsExactly("bart", "lisa"); + + } + + @Test + void beanWithParentRef() { + var parentAppCtx = new GenericApplicationContext(); + var parentBeanReader = new GroovyBeanDefinitionReader(parentAppCtx); + parentBeanReader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + homer(Bean1) { + person = "homer" + age = 45 + props = [overweight:true, height:"1.8m"] + children = ["bart", "lisa"] + } + } + """).getBytes())); + parentAppCtx.refresh(); + + var appCtx = new GenericApplicationContext(parentAppCtx); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + bart(Bean2) { + person = "bart" + parent = ref("homer", true) + } + } + """).getBytes())); + appCtx.refresh(); + + assertThat(appCtx.containsBean("bart")).isTrue(); + Bean2 bart = (Bean2) appCtx.getBean("bart"); + assertThat(bart.parent.person).isEqualTo("homer"); + } + + @Test + void withAnonymousInnerBean() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + bart(Bean1) { + person = "bart" + age = 11 + } + lisa(Bean1) { + person = "lisa" + age = 9 + } + marge(Bean2) { + person = "marge" + bean1 = { Bean1 b -> + person = "homer" + age = 45 + props = [overweight:true, height:"1.8m"] + children = ["bart", "lisa"] } + children = [bart, lisa] + } + } + """).getBytes())); + appCtx.refresh(); + + Bean2 marge = (Bean2) appCtx.getBean("marge"); + assertThat(marge.bean1.person).isEqualTo("homer"); + } + + @Test + void withUntypedAnonymousInnerBean() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + homer(Bean1Factory) + bart(Bean1) { + person = "bart" + age = 11 + } + lisa(Bean1) { + person = "lisa" + age = 9 + } + marge(Bean2) { + person = "marge" + bean1 = { bean -> + bean.factoryBean = "homer" + bean.factoryMethod = "newInstance" + person = "homer" } + children = [bart, lisa] + } + } + """).getBytes())); + appCtx.refresh(); + + Bean2 marge = (Bean2) appCtx.getBean("marge"); + assertThat(marge.bean1.person).isEqualTo("homer"); + } + + @Test + void beanReferences() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + homer(Bean1) { + person = "homer" + age = 45 + props = [overweight:true, height:"1.8m"] + children = ["bart", "lisa"] + } + bart(Bean1) { + person = "bart" + age = 11 + } + lisa(Bean1) { + person = "lisa" + age = 9 + } + marge(Bean2) { + person = "marge" + bean1 = homer + children = [bart, lisa] + } + } + """).getBytes())); + appCtx.refresh(); + + var homer = appCtx.getBean("homer"); + Bean2 marge = (Bean2) appCtx.getBean("marge"); + Bean1 bart = (Bean1) appCtx.getBean("bart"); + Bean1 lisa = (Bean1) appCtx.getBean("lisa"); + + assertThat(marge.bean1).isEqualTo(homer); + assertThat(marge.children).hasSize(2); + + assertThat(marge.children).containsExactlyInAnyOrder(bart, lisa); + } + + @Test + void beanWithConstructor() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + homer(Bean1) { + person = "homer" + age = 45 + } + marge(Bean3, "marge", homer) { + age = 40 + } + } + """).getBytes())); + appCtx.refresh(); + + Bean3 marge = (Bean3) appCtx.getBean("marge"); + assertThat(marge.person).isEqualTo("marge"); + assertThat(marge.bean1.person).isEqualTo("homer"); + assertThat(marge.age).isEqualTo(40); + } + + @Test + void beanWithFactoryMethod() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + homer(Bean1) { + person = "homer" + age = 45 + } + def marge = marge(Bean4) { + person = "marge" + } + marge.factoryMethod = "getInstance" + } + """).getBytes())); + appCtx.refresh(); + + Bean4 marge = (Bean4) appCtx.getBean("marge"); + assertThat(marge.person).isEqualTo("marge"); + } + + @Test + void beanWithFactoryMethodUsingClosureArgs() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + homer(Bean1) { + person = "homer" + age = 45 + } + marge(Bean4) { bean -> + bean.factoryMethod = "getInstance" + person = "marge" + } + } + """).getBytes())); + appCtx.refresh(); + + Bean4 marge = (Bean4) appCtx.getBean("marge"); + assertThat(marge.person).isEqualTo("marge"); + } + + @Test + void beanWithFactoryMethodWithConstructorArgs() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + beanFactory(Bean1FactoryWithArgs){} + + homer(beanFactory:"newInstance", "homer") { + age = 45 + } + //Test with no closure body + marge(beanFactory:"newInstance", "marge") + + //Test more verbose method + mcBain("mcBain"){ + bean -> + bean.factoryBean="beanFactory" + bean.factoryMethod="newInstance" + + } + } + """).getBytes())); + appCtx.refresh(); + + Bean1 homer = (Bean1) appCtx.getBean("homer"); + + assertThat(homer.person).isEqualTo("homer"); + assertThat(homer.age).isEqualTo(45); + + assertThat(((Bean1)appCtx.getBean("marge")).person).isEqualTo("marge"); + + assertThat(((Bean1)appCtx.getBean("mcBain")).person).isEqualTo("mcBain"); + } + + @Test + void getBeanDefinitions() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + jeff(Bean1) { + person = 'jeff' + } + graeme(Bean1) { + person = 'graeme' + } + guillaume(Bean1) { + person = 'guillaume' + } + } + """).getBytes())); + + assertThat(reader.getRegistry().getBeanDefinitionCount()).as("beanDefinitions was the wrong size").isEqualTo(3); + assertThat(reader.getRegistry().getBeanDefinition("jeff")).as("beanDefinitions did not contain jeff").isNotNull(); + assertThat(reader.getRegistry().getBeanDefinition("guillaume")).as("beanDefinitions did not contain guillaume").isNotNull(); + assertThat(reader.getRegistry().getBeanDefinition("graeme")).as("beanDefinitions did not contain graeme").isNotNull(); + } + + @Test + void beanWithFactoryBean() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + myFactory(Bean1Factory) + + homer(myFactory) { bean -> + bean.factoryMethod = "newInstance" + person = "homer" + age = 45 + } + } + """).getBytes())); + appCtx.refresh(); + + Bean1 homer = (Bean1) appCtx.getBean("homer"); + + assertThat(homer.person).isEqualTo("homer"); + } + + @Test + void beanWithFactoryBeanAndMethod() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + myFactory(Bean1Factory) + + homer(myFactory:"newInstance") { bean -> + person = "homer" + age = 45 + } + } + """).getBytes())); + + appCtx.refresh(); + + Bean1 homer = (Bean1) appCtx.getBean("homer"); + assertThat(homer.person).isEqualTo("homer"); + } + + @Test + void loadExternalBeans() { + var appCtx = new GenericGroovyApplicationContext("org/springframework/context/groovy/applicationContext.groovy"); + + assertThat(appCtx.containsBean("foo")).isTrue(); + var foo = appCtx.getBean("foo"); + assertThat(foo).isEqualTo("hello"); + } + + @Test + void loadExternalBeansWithExplicitRefresh() { + var appCtx = new GenericGroovyApplicationContext(); + appCtx.load("org/springframework/context/groovy/applicationContext.groovy"); + appCtx.refresh(); + + assertThat(appCtx.containsBean("foo")).isTrue(); + var foo = appCtx.getBean("foo"); + assertThat(foo).isEqualTo("hello"); + } + + @Test + void holyGrailWiring() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + quest(HolyGrailQuest) + + knight(KnightOfTheRoundTable, "Bedivere") { + quest = ref("quest") + } + } + """).getBytes())); + + appCtx.refresh(); + + KnightOfTheRoundTable knight = (KnightOfTheRoundTable) appCtx.getBean("knight"); + knight.embarkOnQuest(); + } + + @Test + void abstractBeanSpecifyingClass() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + abstractKnight(KnightOfTheRoundTable) { bean -> + bean.'abstract' = true + leader = "King Arthur" + } + + lancelot("lancelot") { bean -> + bean.parent = ref("abstractKnight") + } + + abstractPerson(Bean1) { bean -> + bean.'abstract'=true + age = 45 + } + homerBean { bean -> + bean.parent = ref("abstractPerson") + person = "homer" + } + } + """).getBytes())); + appCtx.refresh(); + + KnightOfTheRoundTable lancelot = (KnightOfTheRoundTable) appCtx.getBean("lancelot"); + assertThat(lancelot.leader).isEqualTo("King Arthur"); + assertThat(lancelot.name).isEqualTo("lancelot"); + + Bean1 homerBean = (Bean1) appCtx.getBean("homerBean"); + + assertThat(homerBean.age).isEqualTo(45); + assertThat(homerBean.person).isEqualTo("homer"); + } + + @Test + void groovyBeanDefinitionReaderWithScript() throws Exception { + var script = """ +def appCtx = new org.springframework.context.support.GenericGroovyApplicationContext() +appCtx.reader.beans { +quest(org.springframework.context.groovy.HolyGrailQuest) {} + +knight(org.springframework.context.groovy.KnightOfTheRoundTable, "Bedivere") { quest = quest } +} +appCtx.refresh() +return appCtx +"""; + GenericGroovyApplicationContext appCtx = (GenericGroovyApplicationContext) new GroovyShell().evaluate(script); + + KnightOfTheRoundTable knight = (KnightOfTheRoundTable) appCtx.getBean("knight"); + knight.embarkOnQuest(); + } + + // test for GRAILS-5057 + @Test + void registerBeans() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + personA(AdvisedPerson) { + name = "Bob" + } + } + """).getBytes())); + + appCtx.refresh(); + assertThat(((AdvisedPerson)appCtx.getBean("personA")).name).isEqualTo("Bob"); + + appCtx = new GenericApplicationContext(); + reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + personA(AdvisedPerson) { + name = "Fred" + } + } + """).getBytes())); + + appCtx.refresh(); + assertThat(((AdvisedPerson)appCtx.getBean("personA")).name).isEqualTo("Fred"); + } + + @Test + void listOfBeansAsConstructorArg() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + someotherbean(SomeOtherClass, new File('somefile.txt')) + someotherbean2(SomeOtherClass, new File('somefile.txt')) + + somebean(SomeClass, [someotherbean, someotherbean2]) + } + """).getBytes())); + + assertThat(appCtx.containsBean("someotherbean")).isTrue(); + assertThat(appCtx.containsBean("someotherbean2")).isTrue(); + assertThat(appCtx.containsBean("somebean")).isTrue(); + } + + @Test + void beanWithListAndMapConstructor() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + bart(Bean1) { + person = "bart" + age = 11 + } + lisa(Bean1) { + person = "lisa" + age = 9 + } + + beanWithList(Bean5, [bart, lisa]) + + // test runtime references both as ref() and as plain name + beanWithMap(Bean6, [bart:bart, lisa:ref('lisa')]) + } + """).getBytes())); + appCtx.refresh(); + + Bean5 beanWithList = (Bean5) appCtx.getBean("beanWithList"); + assertThat(beanWithList.people).hasSize(2); + assertThat(beanWithList.people.get(0).person).isEqualTo("bart"); + + Bean6 beanWithMap = (Bean6) appCtx.getBean("beanWithMap"); + assertThat(beanWithMap.peopleByName.get("lisa").age).isEqualTo(9); + assertThat(beanWithMap.peopleByName.get("bart").person).isEqualTo("bart"); + } + + @Test + void anonymousInnerBeanViaBeanMethod() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + bart(Bean1) { + person = "bart" + age = 11 + } + lisa(Bean1) { + person = "lisa" + age = 9 + } + marge(Bean2) { + person = "marge" + bean1 = bean(Bean1) { + person = "homer" + age = 45 + props = [overweight:true, height:"1.8m"] + children = ["bart", "lisa"] + } + children = [bart, lisa] + } + } + """).getBytes())); + appCtx.refresh(); + + Bean2 marge = (Bean2) appCtx.getBean("marge"); + assertThat(marge.bean1.person).isEqualTo("homer"); + } + + @Test + void anonymousInnerBeanViaBeanMethodWithConstructorArgs() { + var appCtx = new GenericApplicationContext(); + var reader = new GroovyBeanDefinitionReader(appCtx); + reader.loadBeanDefinitions(new ByteArrayResource((""" + package org.springframework.context.groovy + beans { + bart(Bean1) { + person = "bart" + age = 11 + } + lisa(Bean1) { + person = "lisa" + age = 9 + } + marge(Bean2) { + person = "marge" + bean3 = bean(Bean3, "homer", lisa) { + person = "homer" + age = 45 + } + children = [bart, lisa] + } + } + """).getBytes())); + appCtx.refresh(); + + Bean2 marge = (Bean2) appCtx.getBean("marge"); + + assertThat(marge.bean3.person).isEqualTo("homer"); + assertThat(marge.bean3.bean1.person).isEqualTo("lisa"); + } + +} + +class HolyGrailQuest { + void start() { System.out.println("lets begin"); } +} + +class KnightOfTheRoundTable { + String name; + String leader; + + KnightOfTheRoundTable(String n) { + this.name = n; + } + + HolyGrailQuest quest; + + void embarkOnQuest() { + quest.start(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLeader() { + return leader; + } + + public void setLeader(String leader) { + this.leader = leader; + } + + public HolyGrailQuest getQuest() { + return quest; + } + + public void setQuest(HolyGrailQuest quest) { + this.quest = quest; + } +} + +// simple bean +class Bean1 { + String person; + int age; + Properties props = new Properties(); + List children = new ArrayList<>(); + public String getPerson() { + return person; + } + public void setPerson(String person) { + this.person = person; + } + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + public Properties getProps() { + return props; + } + public void setProps(Properties props) { + this.props.putAll(props); + } + public List getChildren() { + return children; + } + public void setChildren(List children) { + this.children = children; + } +} + +// bean referencing other bean +class Bean2 { + int age; + Bean1 bean1; + Bean3 bean3; + String person; + Bean1 parent; + List children = new ArrayList<>(); + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + public String getPerson() { + return person; + } + public void setPerson(String person) { + this.person = person; + } + public Bean1 getParent() { + return parent; + } + public void setParent(Bean1 parent) { + this.parent = parent; + } + public Bean1 getBean1() { + return bean1; + } + public void setBean1(Bean1 bean1) { + this.bean1 = bean1; + } + public Bean3 getBean3() { + return bean3; + } + public void setBean3(Bean3 bean3) { + this.bean3 = bean3; + } + public List getChildren() { + return children; + } + public void setChildren(List children) { + this.children = children; + } +} + +// bean with constructor args +class Bean3 { + Bean3(String person, Bean1 bean1) { + this.person = person; + this.bean1 = bean1; + } + String person; + Bean1 bean1; + int age; + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + public String getPerson() { + return person; + } + public void setPerson(String person) { + this.person = person; + } + public Bean1 getBean1() { + return bean1; + } + public void setBean1(Bean1 bean1) { + this.bean1 = bean1; + } +} + +// bean with factory method +class Bean4 { + private Bean4() {} + static Bean4 getInstance() { + return new Bean4(); + } + String person; + public String getPerson() { + return person; + } + public void setPerson(String person) { + this.person = person; + } +} + +// bean with List-valued constructor arg +class Bean5 { + Bean5(List people) { + this.people = people; + } + List people; +} + +// bean with Map-valued constructor arg +class Bean6 { + Bean6(Map peopleByName) { + this.peopleByName = peopleByName; + } + Map peopleByName; +} + +// a factory bean +class Bean1Factory { + Bean1 newInstance() { + return new Bean1(); + } +} + +class ScopeTestBean { +} + +class TestScope implements Scope { + + int instanceCount; + + @Override + public Object remove(String name) { + // do nothing + return null; + } + + @Override + public void registerDestructionCallback(String name, Runnable callback) { + } + + @Override + public String getConversationId() { + return "mock"; + } + + @Override + public Object get(String name, ObjectFactory objectFactory) { + instanceCount++; + return objectFactory.getObject(); + } + + @Override + public Object resolveContextualObject(String s) { + return null; // noop + } +} + +class BirthdayCardSender { + List peopleSentCards = new ArrayList<>(); + + public void onBirthday(AdvisedPerson person) { + peopleSentCards.add(person); + } +} + +@Component(value = "person") +class AdvisedPerson { + int age; + String name; + + public void birthday() { + ++age; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} + +class SomeClass { + public SomeClass(List soc) {} +} + +class SomeOtherClass { + public SomeOtherClass(File f) {} +} + +// a factory bean that takes arguments +class Bean1FactoryWithArgs { + Bean1 newInstance(String name) { + Bean1 bean = new Bean1(); + bean.person = name; + return bean; + } +}