Compare commits

...

5 Commits

Author SHA1 Message Date
Chris Beams b0acb588e5 Merge pull request #125 from jeffbrown/beanbuilder 12 years ago
Jeff Brown a0b3da716c fix test 12 years ago
Jeff Brown fbcdc573c2 GRAILS-4995 - Improve the handling of List and Map ctor args 12 years ago
Chris Beams c463fd0235 Add spring-lang-groovy to settings.gradle 12 years ago
Jeff Brown a6879b165e Adding some beanbuilder code to the build 12 years ago
  1. 26
      build.gradle
  2. 2
      settings.gradle
  3. 148
      spring-lang-groovy/src/main/groovy/org/springframework/context/groovy/DynamicElementReader.groovy
  4. 53
      spring-lang-groovy/src/main/groovy/org/springframework/context/groovy/GroovyBeanDefinitionApplicationContext.groovy
  5. 143
      spring-lang-groovy/src/main/java/org/springframework/context/groovy/BeanConfiguration.java
  6. 299
      spring-lang-groovy/src/main/java/org/springframework/context/groovy/DefaultBeanConfiguration.java
  7. 357
      spring-lang-groovy/src/main/java/org/springframework/context/groovy/DefaultRuntimeSpringConfiguration.java
  8. 975
      spring-lang-groovy/src/main/java/org/springframework/context/groovy/GroovyBeanDefinitionReader.java
  9. 160
      spring-lang-groovy/src/main/java/org/springframework/context/groovy/GroovyPropertyApplicationContext.java
  10. 232
      spring-lang-groovy/src/main/java/org/springframework/context/groovy/RuntimeSpringConfiguration.java
  11. 37
      spring-lang-groovy/src/test/groovy/org/springframework/context/groovy/DynamicElementReaderTests.groovy
  12. 41
      spring-lang-groovy/src/test/groovy/org/springframework/context/groovy/GroovyBeanDefinitionApplicationContextDynamicBeanPropertyTests.groovy
  13. 993
      spring-lang-groovy/src/test/groovy/org/springframework/context/groovy/GroovyBeanDefinitionReaderTests.groovy
  14. 125
      spring-lang-groovy/src/test/java/org/springframework/context/groovy/GroovyBeanDefinitionApplicationContextTests.java
  15. 4
      spring-lang-groovy/src/test/resources/org/springframework/context/groovy/applicationContext.groovy
  16. 3
      spring-lang-groovy/src/test/resources/org/springframework/context/groovy/applicationContext2.groovy
  17. 9
      spring-lang-groovy/src/test/resources/org/springframework/context/groovy/test.xml

26
build.gradle

@ -85,6 +85,10 @@ configure(subprojects) { subproject -> @@ -85,6 +85,10 @@ configure(subprojects) { subproject ->
archives sourcesJar
archives javadocJar
}
ext {
groovyVersion = '1.6.3'
groovyDependencySpec = "org.codehaus.groovy:groovy-all:$groovyVersion"
}
}
@ -165,6 +169,26 @@ project('spring-beans') { @@ -165,6 +169,26 @@ project('spring-beans') {
}
}
project('spring-lang-groovy') {
apply plugin: 'groovy'
description 'Spring BeanBuilder'
dependencies {
groovy groovyDependencySpec
compile project(':spring-beans')
compile project(':spring-context')
compile groovyDependencySpec
testCompile project(':spring-test')
}
compileJava.enabled=false
sourceSets {
main {
groovy {
srcDir 'src/main/java'
}
}
}
}
project('spring-aop') {
description = 'Spring AOP'
dependencies {
@ -222,7 +246,7 @@ project('spring-context') { @@ -222,7 +246,7 @@ project('spring-context') {
exclude group: 'javax.jws', module: 'jsr181'
}
compile("org.beanshell:bsh:2.0b4", optional)
compile("org.codehaus.groovy:groovy-all:1.6.3", optional)
compile(groovyDependencySpec, optional)
compile("org.jruby:jruby:1.4.0", optional)
compile("org.hibernate:hibernate-validator:4.2.0.Final") { dep ->
optional dep

2
settings.gradle

@ -12,6 +12,7 @@ include 'spring-instrument' @@ -12,6 +12,7 @@ include 'spring-instrument'
include 'spring-instrument-tomcat'
include 'spring-jdbc'
include 'spring-jms'
include 'spring-lang-groovy'
include 'spring-orm'
include 'spring-oxm'
include 'spring-struts'
@ -20,3 +21,4 @@ include 'spring-tx' @@ -20,3 +21,4 @@ include 'spring-tx'
include 'spring-web'
include 'spring-webmvc'
include 'spring-webmvc-portlet'
include 'spring-lang-groovy'

148
spring-lang-groovy/src/main/groovy/org/springframework/context/groovy/DynamicElementReader.groovy

@ -0,0 +1,148 @@ @@ -0,0 +1,148 @@
/*
* Copyright 2010 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
*
* http://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 groovy.xml.StreamingMarkupBuilder
import org.apache.commons.logging.LogFactory
import org.springframework.beans.factory.config.BeanDefinitionHolder
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException
import org.springframework.beans.factory.parsing.Location
import org.springframework.beans.factory.parsing.Problem
import org.springframework.beans.factory.xml.DefaultDocumentLoader
import org.springframework.beans.factory.xml.DelegatingEntityResolver
import org.springframework.beans.factory.xml.NamespaceHandler
import org.springframework.beans.factory.xml.ParserContext
import org.springframework.core.io.ByteArrayResource
import org.springframework.util.xml.SimpleSaxErrorHandler
import org.springframework.util.xml.XmlValidationModeDetector
import org.w3c.dom.Element
import org.xml.sax.EntityResolver
import org.xml.sax.ErrorHandler
import org.xml.sax.InputSource
/**
* Used by GroovyBeanDefinitionReader to read a Spring namespace expression in the Groovy DSL
*
* @see GroovyBeanDefinitionReader
*
*/
class DynamicElementReader extends GroovyObjectSupport{
private static final LOG = LogFactory.getLog(GroovyBeanDefinitionReader)
private Map xmlNamespaces
private String rootNamespace
ErrorHandler errorHandler = new SimpleSaxErrorHandler(LOG);
int validationMode = XmlValidationModeDetector.VALIDATION_NONE
EntityResolver entityResolver = new DelegatingEntityResolver(DynamicElementReader.class.getClassLoader())
ParserContext parserContext
NamespaceHandler namespaceHandler
BeanConfiguration beanConfiguration
boolean beanDecorator = false
boolean firstCall = true
public DynamicElementReader(String namespace, Map namespaceMap=Collections.EMPTY_MAP, NamespaceHandler namespaceHandler = null, ParserContext parserContext = null) {
super();
this.xmlNamespaces = namespaceMap;
this.rootNamespace = namespace
this.namespaceHandler = namespaceHandler
this.parserContext = parserContext
}
void setClassLoader(ClassLoader classLoader) {
entityResolver = new DelegatingEntityResolver(classLoader)
}
/**
* Hook that subclass or anonymous classes can overwrite to implement custom behavior after invocation
* completes
*/
protected void afterInvocation() {
// NOOP
}
@Override
public Object invokeMethod(String name, Object args) {
boolean invokeAfterInterceptor = false
if(firstCall) {
invokeAfterInterceptor = true
firstCall=false
}
if(name.equals("doCall")) {
def callable = args[0]
callable.resolveStrategy = Closure.DELEGATE_FIRST
callable.delegate = this
def result = callable.call()
if(invokeAfterInterceptor) {
afterInvocation()
}
return result
}
else {
StreamingMarkupBuilder builder = new StreamingMarkupBuilder();
def myNamespaces = xmlNamespaces
def myNamespace = rootNamespace
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)
def documentLoader = new DefaultDocumentLoader()
InputSource is = new InputSource(new StringReader(sw.toString()))
Element element = documentLoader.loadDocument(is, entityResolver, errorHandler, validationMode, true).getDocumentElement()
parserContext?.delegate?.initDefaults element
if(namespaceHandler && parserContext) {
if(beanDecorator && beanConfiguration) {
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanConfiguration.getBeanDefinition(), beanConfiguration.getName());
holder = namespaceHandler.decorate(element,holder, parserContext)
beanConfiguration.setBeanDefinition(holder.getBeanDefinition())
}
else {
def beanDefinition = namespaceHandler.parse(element, parserContext)
if(beanDefinition) {
beanConfiguration?.setBeanDefinition(beanDefinition)
}
}
}
else {
throw new BeanDefinitionParsingException(new Problem("No namespace handler found for element ${sw}", new Location(parserContext?.readerContext?.resource ?: new ByteArrayResource(new byte[0]))))
}
if(invokeAfterInterceptor) {
afterInvocation()
}
return element
}
}
}

53
spring-lang-groovy/src/main/groovy/org/springframework/context/groovy/GroovyBeanDefinitionApplicationContext.groovy

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
/*
* Copyright 2010 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
*
* http://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.springframework.context.ApplicationContext
import org.springframework.core.io.ClassPathResource
class GroovyBeanDefinitionApplicationContext {
@Delegate
private ApplicationContext applicationContext
GroovyBeanDefinitionApplicationContext(String resource) {
this([resource] as String[])
}
GroovyBeanDefinitionApplicationContext(String[] resources) {
initializeApplicationContext resources
}
GroovyBeanDefinitionApplicationContext(String resource, Class clazz) {
this([resource] as String[], clazz)
}
GroovyBeanDefinitionApplicationContext(String[] resources, Class clazz) {
def classPathResources = resources.collect { new ClassPathResource(it, clazz) }
initializeApplicationContext classPathResources
}
private initializeApplicationContext(resources) {
def bb = new GroovyBeanDefinitionReader()
resources.each { bb.loadBeans it }
applicationContext = bb.createApplicationContext()
}
def propertyMissing(String propertyName) {
applicationContext.getBean(propertyName)
}
}

143
spring-lang-groovy/src/main/java/org/springframework/context/groovy/BeanConfiguration.java

@ -0,0 +1,143 @@ @@ -0,0 +1,143 @@
/*
* Copyright 2010 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
*
* http://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.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
/**
* An interface that represent a runtime bean configuration
*
* Credit must go to Solomon Duskis and the
* article: http://jroller.com/page/Solomon?entry=programmatic_configuration_in_spring
*
*/
public interface BeanConfiguration {
String AUTOWIRE_BY_TYPE = "byType";
String AUTOWIRE_BY_NAME = "byName";
/**
*
* @return The name of the bean
*/
String getName();
/**
*
* @return True if the bean is singleton
*/
boolean isSingleton();
/**
*
* @return The Spring bean definition instance
*/
AbstractBeanDefinition getBeanDefinition();
/**
* Adds a property value to this bean
* @param propertyName The name of the property
* @param propertyValue The value of the property
*
* @return Returns this bean configuration
*/
BeanConfiguration addProperty(String propertyName, Object propertyValue);
/**
* Sets the name of the method to call when destroying the bean
*
* @param methodName The method name
* @return This bean configuration
*/
BeanConfiguration setDestroyMethod(String methodName);
/**
* Sets the names of the beans this bean configuration depends on
*
* @param dependsOn Bean names it depends on
* @return This bean configuration
*/
BeanConfiguration setDependsOn(String[] dependsOn);
/**
*
* @param beanName
* @return This BeanConfiguration
*/
BeanConfiguration setFactoryBean(String beanName);
/**
*
* @param methodName
* @return This BeanConfiguration
*/
BeanConfiguration setFactoryMethod(String methodName);
/**
* Sets the autowire type, either "byType" or "byName"
*
* @param type The type
* @return This BeanConfiguration
*/
BeanConfiguration setAutowire(String type);
/**
* Sets the name of the bean in the app ctx
* @param beanName The bean name
*/
void setName(String beanName);
/**
* Returns true if the bean config has the name property set
* @param name The name of the property
* @return True if it does have a property with the given name
*/
boolean hasProperty(String name);
/**
* Returns the value of the given property or throws a MissingPropertyException
*
* @param name The name of the property
* @return The value of the property
*/
Object getPropertyValue(String name);
/**
* Sets a property value on the bean configuration
*
* @param property The name of the property
* @param newValue The value
*/
void setPropertyValue(String property, Object newValue);
/**
* Sets the BeanConfiguration as an Abstract bean definition
* @param isAbstract Whether its abstract or not
* @return This BeanConfiguration object
*/
BeanConfiguration setAbstract(boolean isAbstract);
/**
* Sets the name of the parent bean
*
* @param name Either a string which is the name of the bean, a RuntimeBeanReference or a BeanConfiguration
*/
void setParent(Object name);
void setBeanDefinition(BeanDefinition definition);
}

299
spring-lang-groovy/src/main/java/org/springframework/context/groovy/DefaultBeanConfiguration.java

@ -0,0 +1,299 @@ @@ -0,0 +1,299 @@
/*
* Copyright 2010 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
*
* http://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 groovy.lang.GroovyObjectSupport;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import java.util.*;
/**
* Default implementation of the BeanConfiguration interface
*
* Credit must go to Solomon Duskis and the
* article: http://jroller.com/page/Solomon?entry=programmatic_configuration_in_spring
*
*/
public class DefaultBeanConfiguration extends GroovyObjectSupport implements BeanConfiguration {
private static final String AUTOWIRE = "autowire";
private static final String CONSTRUCTOR_ARGS = "constructorArgs";
private static final String DESTROY_METHOD = "destroyMethod";
private static final String FACTORY_BEAN = "factoryBean";
private static final String FACTORY_METHOD = "factoryMethod";
private static final String INIT_METHOD = "initMethod";
private static final String BY_NAME = "byName";
private static final String PARENT = "parent";
private static final String BY_TYPE = "byType";
private static final String BY_CONSTRUCTOR = "constructor";
private static final List DYNAMIC_PROPS = new ArrayList(){ {
add(AUTOWIRE);
add(CONSTRUCTOR_ARGS);
add(DESTROY_METHOD);
add(FACTORY_BEAN);
add(FACTORY_METHOD);
add(INIT_METHOD);
add(BY_NAME);
add(BY_TYPE);
add(BY_CONSTRUCTOR);
} };
private String parentName;
public Object getProperty(String property) {
AbstractBeanDefinition bd = getBeanDefinition();
if(wrapper.isReadableProperty(property)) {
return wrapper.getPropertyValue(property);
}
else if(DYNAMIC_PROPS.contains(property)) {
return null;
}
return super.getProperty(property);
}
public void setProperty(String property, Object newValue) {
if(PARENT.equals(property)) {
setParent(newValue);
}
else {
AbstractBeanDefinition bd = getBeanDefinition();
if(AUTOWIRE.equals(property)) {
if(BY_NAME.equals(newValue)) {
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
}
else if(BY_TYPE.equals(newValue)) {
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
}
else if(Boolean.TRUE.equals(newValue)) {
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
}
else if(BY_CONSTRUCTOR.equals(newValue)) {
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
}
}
// constructorArgs
else if(CONSTRUCTOR_ARGS.equals(property) && newValue instanceof List) {
ConstructorArgumentValues cav = new ConstructorArgumentValues();
List args = (List)newValue;
for (Iterator i = args.iterator(); i.hasNext();) {
Object e = i.next();
cav.addGenericArgumentValue(e);
}
bd.setConstructorArgumentValues(cav);
}
// destroyMethod
else if(DESTROY_METHOD.equals(property)) {
if(newValue != null)
bd.setDestroyMethodName(newValue.toString());
}
// factoryBean
else if(FACTORY_BEAN.equals(property)) {
if(newValue != null)
bd.setFactoryBeanName(newValue.toString());
}
// factoryMethod
else if(FACTORY_METHOD.equals(property)) {
if(newValue != null)
bd.setFactoryMethodName(newValue.toString());
}
// initMethod
else if(INIT_METHOD.equals(property)) {
if(newValue != null)
bd.setInitMethodName(newValue.toString());
}
else if(wrapper.isWritableProperty(property)) {
wrapper.setPropertyValue(property, newValue);
}
// autowire
else {
super.setProperty(property, newValue);
}
}
}
private Class clazz;
private String name;
private boolean singleton = true;
private AbstractBeanDefinition definition;
private Collection constructorArgs = Collections.EMPTY_LIST;
private BeanWrapper wrapper;
public DefaultBeanConfiguration(String name, Class clazz) {
this.name = name;
this.clazz = clazz;
}
public DefaultBeanConfiguration(String name, Class clazz, boolean prototype) {
this(name,clazz,Collections.EMPTY_LIST);
this.singleton = !prototype;
}
public DefaultBeanConfiguration(String name) {
this(name,null,Collections.EMPTY_LIST);
}
public DefaultBeanConfiguration(Class clazz2) {
this.clazz = clazz2;
}
public DefaultBeanConfiguration(String name2, Class clazz2, Collection args) {
this.name = name2;
this.clazz = clazz2;
this.constructorArgs = args;
}
public DefaultBeanConfiguration(String name2, boolean prototype) {
this(name2,null,Collections.EMPTY_LIST);
this.singleton = !prototype;
}
public DefaultBeanConfiguration(Class clazz2, Collection constructorArguments) {
this.clazz = clazz2;
this.constructorArgs = constructorArguments;
}
public String getName() {
return this.name;
}
public boolean isSingleton() {
return this.singleton ;
}
public AbstractBeanDefinition getBeanDefinition() {
if (definition == null)
definition = createBeanDefinition();
return definition;
}
public void setBeanDefinition(BeanDefinition definition) {
this.definition = (AbstractBeanDefinition)definition;
}
protected AbstractBeanDefinition createBeanDefinition() {
AbstractBeanDefinition bd = new GenericBeanDefinition();
if(constructorArgs.size() > 0) {
ConstructorArgumentValues cav = new ConstructorArgumentValues();
for (Object constructorArg : constructorArgs) {
cav.addGenericArgumentValue(constructorArg);
}
bd.setConstructorArgumentValues(cav);
}
bd.setBeanClass(clazz);
bd.setScope(singleton ? AbstractBeanDefinition.SCOPE_SINGLETON : AbstractBeanDefinition.SCOPE_PROTOTYPE);
if(parentName != null) {
bd.setParentName(parentName);
}
wrapper = new BeanWrapperImpl(bd);
return bd;
}
public BeanConfiguration addProperty(String propertyName, Object propertyValue) {
if(propertyValue instanceof BeanConfiguration) {
propertyValue = ((BeanConfiguration)propertyValue).getBeanDefinition();
}
getBeanDefinition()
.getPropertyValues()
.addPropertyValue(propertyName,propertyValue);
return this;
}
public BeanConfiguration setDestroyMethod(String methodName) {
getBeanDefinition().setDestroyMethodName(methodName);
return this;
}
public BeanConfiguration setDependsOn(String[] dependsOn) {
getBeanDefinition().setDependsOn(dependsOn);
return this;
}
public BeanConfiguration setFactoryBean(String beanName) {
getBeanDefinition().setFactoryBeanName(beanName);
return this;
}
public BeanConfiguration setFactoryMethod(String methodName) {
getBeanDefinition().setFactoryMethodName(methodName);
return this;
}
public BeanConfiguration setAutowire(String type) {
if("byName".equals(type)) {
getBeanDefinition().setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
}
else if("byType".equals(type)){
getBeanDefinition().setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
return this;
}
public void setName(String beanName) {
this.name = beanName;
}
public Object getPropertyValue(String name) {
PropertyValue propertyValue = getBeanDefinition()
.getPropertyValues()
.getPropertyValue(name);
if(propertyValue== null) {
return null;
}
else {
return propertyValue
.getValue();
}
}
public boolean hasProperty(String name) {
return getBeanDefinition().getPropertyValues().contains(name);
}
public void setPropertyValue(String property, Object newValue) {
getBeanDefinition().getPropertyValues().addPropertyValue(property, newValue);
}
public BeanConfiguration setAbstract(boolean isAbstract) {
getBeanDefinition().setAbstract(isAbstract);
return this;
}
public void setParent(Object obj) {
if(obj == null) throw new IllegalArgumentException("Parent bean cannot be set to a null runtime bean reference!");
if(obj instanceof String)
this.parentName = (String)obj;
else if(obj instanceof RuntimeBeanReference) {
this.parentName = ((RuntimeBeanReference)obj).getBeanName();
}
else if(obj instanceof BeanConfiguration) {
this.parentName = ((BeanConfiguration)obj).getName();
}
getBeanDefinition().setParentName(parentName);
setAbstract(false);
}
}

357
spring-lang-groovy/src/main/java/org/springframework/context/groovy/DefaultRuntimeSpringConfiguration.java

@ -0,0 +1,357 @@ @@ -0,0 +1,357 @@
/*
* Copyright 2010 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
*
* http://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 groovy.lang.GroovySystem;
import groovy.lang.MetaClass;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.Assert;
import java.util.*;
/**
* A programmable runtime Spring configuration that allows a spring ApplicationContext
* to be constructed at runtime
*
* Credit must go to Solomon Duskis and the
* article: http://jroller.com/page/Solomon?entry=programmatic_configuration_in_spring
*
*/
public class DefaultRuntimeSpringConfiguration implements
RuntimeSpringConfiguration {
private static final Log LOG = LogFactory.getLog(DefaultRuntimeSpringConfiguration.class);
protected GenericApplicationContext context;
private Map<String, BeanConfiguration> beanConfigs = new HashMap<String, BeanConfiguration>();
private Map<String, BeanDefinition> beanDefinitions = new HashMap<String, BeanDefinition>();
private List<String> beanNames = new ArrayList<String>();
protected ApplicationContext parent;
protected ClassLoader classLoader;
protected Map<String, List> aliases = new HashMap<String, List>();
protected ListableBeanFactory beanFactory;
public DefaultRuntimeSpringConfiguration() {
super();
}
/**
* Creates the ApplicationContext instance. Subclasses can override to customise the used ApplicationContext
*
* @param parent The parent ApplicationContext instance. Can be null.
*
* @return An instance of GenericApplicationContext
*/
protected GenericApplicationContext createApplicationContext(ApplicationContext parent) {
if(parent != null && beanFactory!=null) {
if(beanFactory instanceof DefaultListableBeanFactory) {
return new GroovyPropertyApplicationContext((DefaultListableBeanFactory) beanFactory,parent);
}
else {
throw new IllegalArgumentException("ListableBeanFactory set must be a subclass of DefaultListableBeanFactory");
}
}
else if(beanFactory!=null) {
if(beanFactory instanceof DefaultListableBeanFactory) {
return new GroovyPropertyApplicationContext((DefaultListableBeanFactory) beanFactory);
}
else {
throw new IllegalArgumentException("ListableBeanFactory set must be a subclass of DefaultListableBeanFactory");
}
}
else if(parent !=null) {
return new GroovyPropertyApplicationContext(parent);
}
else {
return new GroovyPropertyApplicationContext();
}
}
public DefaultRuntimeSpringConfiguration(ApplicationContext parent) {
this(parent, null);
}
public DefaultRuntimeSpringConfiguration(ApplicationContext parent, ClassLoader cl) {
super();
this.parent = parent;
this.classLoader = cl;
}
private void setClassLoaderOnContext(ClassLoader cl) {
this.context.setClassLoader(cl);
this.context.getBeanFactory().setBeanClassLoader(cl);
}
/**
* Initialises the ApplicationContext instance
*/
protected void initialiseApplicationContext() {
if(this.context == null) {
this.context = createApplicationContext(this.parent);
if(classLoader != null) {
setClassLoaderOnContext(classLoader);
}
Assert.notNull(context);
}
}
public BeanConfiguration addSingletonBean(String name, Class clazz) {
BeanConfiguration bc = new DefaultBeanConfiguration(name,clazz);
registerBeanConfiguration(name, bc);
return bc;
}
public BeanConfiguration addPrototypeBean(String name, Class clazz) {
BeanConfiguration bc = new DefaultBeanConfiguration(name,clazz,true);
registerBeanConfiguration(name, bc);
return bc;
}
public ApplicationContext getApplicationContext() {
initialiseApplicationContext();
registerBeansWithContext(context);
context.refresh();
return context;
}
public ApplicationContext getUnrefreshedApplicationContext() {
initialiseApplicationContext();
return context;
}
public BeanConfiguration addSingletonBean(String name) {
BeanConfiguration bc = new DefaultBeanConfiguration(name);
registerBeanConfiguration(name, bc);
return bc;
}
public BeanConfiguration createSingletonBean(Class clazz) {
return new DefaultBeanConfiguration(clazz);
}
public BeanConfiguration addSingletonBean(String name, Class clazz, Collection args) {
BeanConfiguration bc = new DefaultBeanConfiguration(name,clazz,args);
registerBeanConfiguration(name, bc);
return bc;
}
public BeanConfiguration addPrototypeBean(String name) {
BeanConfiguration bc = new DefaultBeanConfiguration(name,true);
registerBeanConfiguration(name, bc);
return bc;
}
private void registerBeanConfiguration(String name, BeanConfiguration bc) {
beanConfigs.put(name,bc);
beanNames.add(name);
}
public BeanConfiguration createSingletonBean(Class clazz, Collection constructorArguments) {
return new DefaultBeanConfiguration(clazz, constructorArguments);
}
public BeanConfiguration createPrototypeBean(String name) {
return new DefaultBeanConfiguration(name,true);
}
public BeanConfiguration createSingletonBean(String name) {
return new DefaultBeanConfiguration(name);
}
public void addBeanConfiguration(String beanName, BeanConfiguration beanConfiguration) {
beanConfiguration.setName(beanName);
registerBeanConfiguration(beanName, beanConfiguration);
}
public void addBeanDefinition(String name, BeanDefinition bd) {
beanDefinitions.put(name,bd);
beanNames.add(name);
}
public boolean containsBean(String name) {
return beanNames .contains(name);
}
public BeanConfiguration getBeanConfig(String name) {
return beanConfigs.get(name);
}
public AbstractBeanDefinition createBeanDefinition(String name) {
if(containsBean(name)) {
if(beanDefinitions.containsKey(name))
return (AbstractBeanDefinition)beanDefinitions.get(name);
else if(beanConfigs.containsKey(name))
return beanConfigs.get(name).getBeanDefinition();
}
return null;
}
public void registerPostProcessor(BeanFactoryPostProcessor processor) {
initialiseApplicationContext();
this.context.addBeanFactoryPostProcessor(processor);
}
public List getBeanNames() {
return beanNames;
}
public void registerBeansWithContext(GenericApplicationContext applicationContext) {
registerBeansWithRegistry(applicationContext);
}
public void registerBeansWithRegistry(BeanDefinitionRegistry registry) {
registerUnrefreshedBeansWithRegistry(registry);
registerBeanConfigsWithRegistry(registry);
registerBeanDefinitionsWithRegistry(registry);
}
private void registerUnrefreshedBeansWithRegistry(BeanDefinitionRegistry registry) {
if(context != null) {
for(String beanName : context.getBeanDefinitionNames()) {
registry.registerBeanDefinition(beanName, context.getBeanDefinition(beanName));
}
}
}
private void registerBeanConfigsWithRegistry(BeanDefinitionRegistry registry) {
for (Object o : beanConfigs.values()) {
BeanConfiguration bc = (BeanConfiguration) o;
String beanName = bc.getName();
if (LOG.isDebugEnabled()) {
LOG.debug("[RuntimeConfiguration] Registering bean [" + beanName + "]");
if (LOG.isTraceEnabled()) {
PropertyValue[] pvs = bc.getBeanDefinition()
.getPropertyValues()
.getPropertyValues();
for (PropertyValue pv : pvs) {
LOG.trace("[RuntimeConfiguration] With property [" + pv.getName() + "] set to [" + pv.getValue() + "]");
}
}
}
if (registry.containsBeanDefinition(beanName)) {
removeBeanDefinition(registry, beanName);
}
registry.registerBeanDefinition(beanName,
bc.getBeanDefinition());
registerBeanAliases(registry, beanName);
}
}
private void registerBeanDefinitionsWithRegistry(BeanDefinitionRegistry registry) {
for (Object key : beanDefinitions.keySet()) {
BeanDefinition bd = beanDefinitions.get(key);
if (LOG.isDebugEnabled()) {
LOG.debug("[RuntimeConfiguration] Registering bean [" + key + "]");
if (LOG.isTraceEnabled()) {
PropertyValue[] pvs = bd.getPropertyValues().getPropertyValues();
for (PropertyValue pv : pvs) {
LOG.trace("[RuntimeConfiguration] With property [" + pv.getName() + "] set to [" + pv.getValue() + "]");
}
}
}
final String beanName = key.toString();
if (registry.containsBeanDefinition(beanName)) {
removeBeanDefinition(registry, beanName);
}
registry.registerBeanDefinition(beanName, bd);
registerBeanAliases(registry, beanName);
}
}
public void registerBeansWithConfig(RuntimeSpringConfiguration targetSpringConfig) {
if(targetSpringConfig!=null) {
ApplicationContext ctx = targetSpringConfig.getUnrefreshedApplicationContext();
if(ctx instanceof BeanDefinitionRegistry) {
final BeanDefinitionRegistry registry = (BeanDefinitionRegistry) ctx;
registerUnrefreshedBeansWithRegistry(registry);
registerBeansWithRegistry(registry);
}
for (Map.Entry<String, BeanConfiguration> beanEntry : beanConfigs.entrySet()) {
targetSpringConfig.addBeanConfiguration(beanEntry.getKey(), beanEntry.getValue());
}
}
}
private void registerBeanAliases(BeanDefinitionRegistry beanDefinitionRegistry, String beanName) {
List beanAliases = (List)aliases.get(beanName);
if(beanAliases != null && !beanAliases.isEmpty()) {
for (Object beanAliase : beanAliases) {
String alias = (String) beanAliase;
beanDefinitionRegistry.registerAlias(beanName, alias);
}
}
}
private void removeBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
MetaClass mc = GroovySystem.getMetaClassRegistry().getMetaClass(registry.getClass());
if(mc.respondsTo(registry, "removeBeanDefinition").size()>0) {
mc.invokeMethod(registry,"removeBeanDefinition",new Object[]{beanName});
}
}
/**
* Adds an abstract bean and returns the BeanConfiguration instance
*
* @param name The name of the bean
* @return The BeanConfiguration object
*/
public BeanConfiguration addAbstractBean(String name) {
BeanConfiguration bc = new DefaultBeanConfiguration(name);
bc.setAbstract(true);
registerBeanConfiguration(name, bc);
return bc;
}
public void addAlias(String alias, String beanName) {
List beanAliases = this.aliases.get(beanName);
if(beanAliases == null) {
beanAliases = new ArrayList();
this.aliases.put(beanName, beanAliases);
}
beanAliases.add(alias);
}
public BeanDefinition getBeanDefinition(String beanName) {
return this.beanDefinitions.get(beanName);
}
public void setBeanFactory(ListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}

975
spring-lang-groovy/src/main/java/org/springframework/context/groovy/GroovyBeanDefinitionReader.java

@ -0,0 +1,975 @@ @@ -0,0 +1,975 @@
/*
* Copyright 2010 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
*
* http://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 groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.GString;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyObjectSupport;
import groovy.lang.GroovyShell;
import groovy.lang.MetaClass;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.beans.factory.parsing.EmptyReaderEventListener;
import org.springframework.beans.factory.parsing.FailFastProblemReporter;
import org.springframework.beans.factory.parsing.Location;
import org.springframework.beans.factory.parsing.NullSourceExtractor;
import org.springframework.beans.factory.parsing.Problem;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver;
import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.NamespaceHandlerResolver;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.Assert;
/**
* <p>Runtime bean configuration wrapper. Like a Groovy builder, but more of a DSL for
* Spring configuration. Allows syntax like:</p>
*
* <pre>
* import org.hibernate.SessionFactory
* import org.apache.commons.dbcp.BasicDataSource
*
* GroovyBeanDefinitionReader builder = new GroovyBeanDefinitionReader()
* builder.beans {
* dataSource(BasicDataSource) { // <--- invokeMethod
* driverClassName = "org.hsqldb.jdbcDriver"
* url = "jdbc:hsqldb:mem:grailsDB"
* username = "sa" // <-- setProperty
* password = ""
* settings = [mynew:"setting"]
* }
* sessionFactory(SessionFactory) {
* dataSource = dataSource // <-- getProperty for retrieving refs
* }
* myService(MyService) {
* nestedBean = { AnotherBean bean-> // <-- setProperty with closure for nested bean
* dataSource = dataSource
* }
* }
* }
* </pre>
* <p>
* You can also use the Spring IO API to load resources containing beans defined as a Groovy
* script using either the constructors or the loadBeans(Resource[] resources) method
* </p>
*
*/
public class GroovyBeanDefinitionReader extends GroovyObjectSupport {
private static final Log LOG = LogFactory.getLog(GroovyBeanDefinitionReader.class);
private static final String CREATE_APPCTX = "createApplicationContext";
private static final String REGISTER_BEANS = "registerBeans";
private static final String BEANS = "beans";
private static final String REF = "ref";
private RuntimeSpringConfiguration springConfig;
private BeanConfiguration currentBeanConfig;
private Map<String, DeferredProperty> deferredProperties = new HashMap<String, DeferredProperty>();
private ApplicationContext parentCtx;
private Map binding = Collections.EMPTY_MAP;
private ClassLoader classLoader = null;
private NamespaceHandlerResolver namespaceHandlerResolver;
private Map<String, NamespaceHandler> namespaceHandlers = new HashMap<String, NamespaceHandler>();
private XmlBeanDefinitionReader xmlBeanDefinitionReader;
private Map<String, String> namespaces = new HashMap<String, String>();
private Resource beanBuildResource = new ByteArrayResource(new byte[0]);
private XmlReaderContext readerContext;
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
public GroovyBeanDefinitionReader() {
this(null,null);
}
public GroovyBeanDefinitionReader(ClassLoader classLoader) {
this(null, classLoader);
}
public GroovyBeanDefinitionReader(ApplicationContext parent) {
this(parent, null);
}
public GroovyBeanDefinitionReader(ApplicationContext parent,ClassLoader classLoader) {
this(parent,null, classLoader);
}
public GroovyBeanDefinitionReader(ApplicationContext parentCtx, RuntimeSpringConfiguration springConfig, ClassLoader classLoader) {
this.springConfig = springConfig == null ? createRuntimeSpringConfiguration(parentCtx, classLoader) : springConfig;
this.parentCtx = parentCtx;
this.classLoader = classLoader;
initializeSpringConfig();
}
public void setResourcePatternResolver(ResourcePatternResolver resourcePatternResolver) {
Assert.notNull(resourcePatternResolver, "The argument [resourcePatternResolver] cannot be null");
this.resourcePatternResolver = resourcePatternResolver;
}
protected void initializeSpringConfig() {
this.xmlBeanDefinitionReader = new XmlBeanDefinitionReader((GenericApplicationContext)springConfig.getUnrefreshedApplicationContext());
initializeGroovyBeanDefinitionReaderForClassLoader(this.classLoader);
}
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader == null ? getClass().getClassLoader() : classLoader;
initializeGroovyBeanDefinitionReaderForClassLoader(classLoader);
}
protected void initializeGroovyBeanDefinitionReaderForClassLoader(ClassLoader classLoader) {
xmlBeanDefinitionReader.setBeanClassLoader(classLoader);
this.namespaceHandlerResolver = new DefaultNamespaceHandlerResolver(this.classLoader);
this.readerContext = new XmlReaderContext(beanBuildResource,new FailFastProblemReporter(),new EmptyReaderEventListener(),new NullSourceExtractor(),xmlBeanDefinitionReader,namespaceHandlerResolver);
}
public void setNamespaceHandlerResolver(NamespaceHandlerResolver namespaceHandlerResolver) {
this.namespaceHandlerResolver = namespaceHandlerResolver;
}
protected RuntimeSpringConfiguration createRuntimeSpringConfiguration(ApplicationContext parent, ClassLoader classLoader) {
return new DefaultRuntimeSpringConfiguration(parent, classLoader);
}
public Log getLog() {
return LOG;
}
/**
* Imports Spring bean definitions from either XML or Groovy sources into the current bean builder instance
*
* @param resourcePattern The resource pattern
*/
public void importBeans(String resourcePattern) {
try {
Resource[] resources =resourcePatternResolver.getResources(resourcePattern);
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
if(resource.getFilename().endsWith(".groovy")) {
loadBeans(resource);
}
else if(resource.getFilename().endsWith(".xml")) {
SimpleBeanDefinitionRegistry beanRegistry = new SimpleBeanDefinitionRegistry();
XmlBeanDefinitionReader beanReader = new XmlBeanDefinitionReader(beanRegistry);
beanReader.loadBeanDefinitions(resource);
String[] beanNames = beanRegistry.getBeanDefinitionNames();
for (int j = 0; j < beanNames.length; j++) {
String beanName = beanNames[j];
springConfig.addBeanDefinition(beanName, beanRegistry.getBeanDefinition(beanName));
}
}
}
} catch (IOException e) {
LOG.error("Error loading beans for resource pattern: " + resourcePattern, e);
}
}
/**
* Defines an Spring namespace definition to use
*
* @param definition The definition
*/
public void xmlns(Map<String, String> definition) {
Assert.notNull(namespaceHandlerResolver, "You cannot define a Spring namespace without a [namespaceHandlerResolver] set");
if(!definition.isEmpty()) {
for(Map.Entry<String,String> entry : definition.entrySet()) {
String namespace = entry.getKey();
String uri = null;
if(entry.getValue() != null) {
uri = entry.getValue();
}
if(uri==null) {
throw new IllegalArgumentException("Namespace definition cannot supply a null URI");
}
final NamespaceHandler namespaceHandler = namespaceHandlerResolver.resolve(uri);
if(namespaceHandler == null) {
throw new BeanDefinitionParsingException(new Problem("No namespace handler found for URI: " + uri, new Location(this.readerContext.getResource())));
}
namespaceHandlers.put(namespace, namespaceHandler);
namespaces.put(namespace, uri);
}
}
}
/**
* Retrieves the parent ApplicationContext
* @return The parent ApplicationContext
*/
public ApplicationContext getParentCtx() {
return parentCtx;
}
/**
* Retrieves the RuntimeSpringConfiguration instance used the the GroovyBeanDefinitionReader
* @return The RuntimeSpringConfiguration instance
*/
public RuntimeSpringConfiguration getSpringConfig() {
return springConfig;
}
/**
* Retrieves a BeanDefinition for the given name
* @param name The bean definition
* @return The BeanDefinition instance
*/
public BeanDefinition getBeanDefinition(String name) {
if(!getSpringConfig().containsBean(name))
return null;
return getSpringConfig().getBeanConfig(name).getBeanDefinition();
}
/**
* Retrieves all BeanDefinitions for this GroovyBeanDefinitionReader
*
* @return A map of BeanDefinition instances with the bean id as the key
*/
public Map<String, BeanDefinition> getBeanDefinitions() {
Map<String, BeanDefinition> beanDefinitions = new HashMap<String, BeanDefinition>();
final List beanNames = getSpringConfig().getBeanNames();
for (Object beanName1 : beanNames) {
String beanName = (String) beanName1;
BeanDefinition bd = getSpringConfig()
.getBeanConfig(beanName)
.getBeanDefinition();
beanDefinitions.put(beanName, bd);
}
return beanDefinitions;
}
/**
* Sets the runtime Spring configuration instance to use. This is not necessary to set
* and is configured to default value if not, but is useful for integrating with other
* spring configuration mechanisms @see org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator
*
* @param springConfig The spring config
*/
public void setSpringConfig(RuntimeSpringConfiguration springConfig) {
this.springConfig = springConfig;
initializeSpringConfig();
}
/**
* This class is used to defer the adding of a property to a bean definition until later
* This is for a case where you assign a property to a list that may not contain bean references at
* that point of asignment, but may later hence it would need to be managed
*
* @author Graeme Rocher
*/
private class DeferredProperty {
private BeanConfiguration config;
private String name;
private Object value;
DeferredProperty(BeanConfiguration config, String name, Object value) {
this.config = config;
this.name = name;
this.value = value;
}
public void setInBeanConfig() {
this.config.addProperty(name, value);
}
}
/**
* A RuntimeBeanReference that takes care of adding new properties to runtime references
*
* @author Graeme Rocher
* @since 0.4
*
*/
private class ConfigurableRuntimeBeanReference extends RuntimeBeanReference implements GroovyObject {
private MetaClass metaClass;
private BeanConfiguration beanConfig;
public ConfigurableRuntimeBeanReference(String beanName, BeanConfiguration beanConfig) {
this(beanName, beanConfig, false);
}
public ConfigurableRuntimeBeanReference(String beanName, BeanConfiguration beanConfig, boolean toParent) {
super(beanName, toParent);
this.beanConfig = beanConfig;
if(beanConfig == null)
throw new IllegalArgumentException("Argument [beanConfig] cannot be null");
this.metaClass = InvokerHelper.getMetaClass(this);
}
public MetaClass getMetaClass() {
return this.metaClass;
}
public Object getProperty(String property) {
if(property.equals("beanName"))
return getBeanName();
else if(property.equals("source"))
return getSource();
else if(this.beanConfig != null) {
return new WrappedPropertyValue(property,beanConfig.getPropertyValue(property));
}
else
return this.metaClass.getProperty(this, property);
}
/**
* Wraps a BeanConfiguration property an ensures that any RuntimeReference additions to it are
* deferred for resolution later
*
* @author Graeme Rocher
* @since 0.4
*
*/
private class WrappedPropertyValue extends GroovyObjectSupport {
private Object propertyValue;
private String propertyName;
public WrappedPropertyValue(String propertyName, Object propertyValue) {
this.propertyValue = propertyValue;
this.propertyName = propertyName;
}
public void leftShift(Object value) {
InvokerHelper.invokeMethod(propertyValue, "leftShift", value);
updateDeferredProperties(value);
}
public boolean add(Object value) {
boolean retval = (Boolean) InvokerHelper.invokeMethod(propertyValue, "add", value);
updateDeferredProperties(value);
return retval;
}
public boolean addAll(Collection values) {
boolean retval = (Boolean) InvokerHelper.invokeMethod(propertyValue, "addAll", values);
for (Object value : values) {
updateDeferredProperties(value);
}
return retval;
}
public Object invokeMethod(String name, Object args) {
return InvokerHelper.invokeMethod(propertyValue, name, args);
}
public Object getProperty(String name) {
return InvokerHelper.getProperty(propertyValue, name);
}
public void setProperty(String name, Object value) {
InvokerHelper.setProperty(propertyValue, name, value);
}
private void updateDeferredProperties(Object value) {
if (value instanceof RuntimeBeanReference) {
deferredProperties.put(beanConfig.getName(), new DeferredProperty(beanConfig, propertyName, propertyValue));
}
}
}
public Object invokeMethod(String name, Object args) {
return this.metaClass.invokeMethod(this, name, args);
}
public void setMetaClass(MetaClass metaClass) {
this.metaClass = metaClass;
}
public void setProperty(String property, Object newValue) {
if(!addToDeferred(beanConfig,property, newValue)) {
beanConfig.setPropertyValue(property, newValue);
}
}
}
/**
* Takes a resource pattern as (@see org.springframework.core.io.support.PathMatchingResourcePatternResolver)
* This allows you load multiple bean resources in this single builder
*
* eg loadBeans("classpath:*Beans.groovy")
*
* @param resourcePattern The resource pattern
* @throws IOException When the path cannot be matched
*/
public void loadBeans(String resourcePattern) throws IOException {
loadBeans(new PathMatchingResourcePatternResolver().getResources(resourcePattern));
}
/**
* Loads a single Resource into the bean builder
*
* @param resource The resource to load
* @throws IOException When an error occurs
*/
public void loadBeans(Resource resource) throws IOException {
this.beanBuildResource = resource;
loadBeans(new Resource[]{resource});
}
/**
* Loads a set of given beans
* @param resources The resources to load
* @throws IOException Thrown if there is an error reading one of the passes resources
*/
public void loadBeans(Resource[] resources) throws IOException {
Closure beans = new Closure(this){
public Object call(Object[] args) {
invokeBeanDefiningClosure((Closure)args[0]);
return null;
}
};
Binding b = new Binding() {
@Override
public void setVariable(String name, Object value) {
if(currentBeanConfig!=null) {
setPropertyOnBeanConfig(name, value);
}
else {
super.setVariable(name, value);
}
}
};
b.setVariable("beans", beans);
for (Resource resource : resources) {
try {
GroovyShell shell = classLoader != null ? new GroovyShell(classLoader, b) : new GroovyShell(b);
shell.evaluate(resource.getInputStream());
}
catch (Throwable e) {
throw new BeanDefinitionParsingException(new Problem("Error evaluating bean definition script: " + e.getMessage(), new Location(resource), null, e));
}
}
}
/**
* Register a set of beans with the given bean registry. Most
* application contexts are bean registries.
*/
public void registerBeans(BeanDefinitionRegistry registry) {
finalizeDeferredProperties();
if (registry instanceof GenericApplicationContext) {
GenericApplicationContext ctx = (GenericApplicationContext) registry;
ctx.setClassLoader(this.classLoader);
ctx.getBeanFactory().setBeanClassLoader(this.classLoader);
}
springConfig.registerBeansWithRegistry(registry);
}
/**
* Registers bean definitions with another instance of RuntimeSpringConfiguration, overriding any beans in the target.
*
* @param targetSpringConfig The RuntimeSpringConfiguration object
*/
public void registerBeans(RuntimeSpringConfiguration targetSpringConfig) {
this.springConfig.registerBeansWithConfig(targetSpringConfig);
}
/**
* This method overrides method invocation to create beans for each method name that
* takes a class argument
*/
public Object invokeMethod(String name, Object arg) {
Object[] args = (Object[])arg;
if(CREATE_APPCTX.equals(name)) {
return createApplicationContext();
}
else if(REGISTER_BEANS.equals(name) && args.length == 1 && args[0] instanceof GenericApplicationContext) {
registerBeans((GenericApplicationContext)args[0]);
return null;
}
else if(BEANS.equals(name) && args.length == 1 && args[0] instanceof Closure) {
return beans((Closure)args[0]);
}
else if(REF.equals(name)) {
String refName;
if(args[0] == null)
throw new IllegalArgumentException("Argument to ref() is not a valid bean or was not found");
if(args[0] instanceof RuntimeBeanReference) {
refName = ((RuntimeBeanReference)args[0]).getBeanName();
}
else {
refName = args[0].toString();
}
boolean parentRef = false;
if(args.length > 1) {
if(args[1] instanceof Boolean) {
parentRef = (Boolean) args[1];
}
}
return new RuntimeBeanReference(refName, parentRef);
}
else if(namespaceHandlers.containsKey(name) && args.length > 0 && (args[0] instanceof Closure)) {
DynamicElementReader reader = createDynamicElementReader(name, true);
reader.invokeMethod("doCall",args);
}
else if(args.length > 0 && args[0] instanceof Closure) {
// abstract bean definition
return invokeBeanDefiningMethod(name, args);
}
else if(args.length > 0 && args[0] instanceof Class || args.length > 0 && args[0] instanceof RuntimeBeanReference || args.length > 0 &&args[0] instanceof Map) {
return invokeBeanDefiningMethod(name, args);
}
else if (args.length > 1 && args[args.length -1] instanceof Closure) {
return invokeBeanDefiningMethod(name, args);
}
ApplicationContext ctx = springConfig.getUnrefreshedApplicationContext();
MetaClass mc = DefaultGroovyMethods.getMetaClass(ctx);
if(!mc.respondsTo(ctx, name, args).isEmpty()){
return mc.invokeMethod(ctx,name, args);
}
return this;
}
/**
* Defines a set of beans for the given block or closure.
*
* @param c The block or closure
* @return This GroovyBeanDefinitionReader instance
*/
public GroovyBeanDefinitionReader beans(Closure c) {
return invokeBeanDefiningClosure(c);
}
/**
* Creates an ApplicationContext from the current state of the GroovyBeanDefinitionReader
* @return The ApplicationContext instance
*/
public ApplicationContext createApplicationContext() {
finalizeDeferredProperties();
return springConfig.getApplicationContext();
}
protected void finalizeDeferredProperties() {
for (Object o : deferredProperties.values()) {
DeferredProperty dp = (DeferredProperty) o;
if (dp.value instanceof List) {
dp.value = manageListIfNecessary(dp.value);
}
else if (dp.value instanceof Map) {
dp.value = manageMapIfNecessary(dp.value);
}
dp.setInBeanConfig();
}
deferredProperties.clear();
}
protected boolean addToDeferred(BeanConfiguration beanConfig,String property, Object newValue) {
if(newValue instanceof List) {
deferredProperties.put(currentBeanConfig.getName()+property,new DeferredProperty(currentBeanConfig, property, newValue));
return true;
}
else if(newValue instanceof Map) {
deferredProperties.put(currentBeanConfig.getName()+property,new DeferredProperty(currentBeanConfig, property, newValue));
return true;
}
return false;
}
/**
* This method is called when a bean definition node is called
*
* @param name The name of the bean to define
* @param args The arguments to the bean. The first argument is the class name, the last argument is sometimes a closure. All
* the arguments in between are constructor arguments
* @return The bean configuration instance
*/
protected BeanConfiguration invokeBeanDefiningMethod(String name, Object[] args) {
boolean hasClosureArgument = args[args.length - 1] instanceof Closure;
if(args[0] instanceof Class) {
Class beanClass = args[0] instanceof Class ? (Class)args[0] : args[0].getClass();
if(args.length >= 1) {
if(hasClosureArgument) {
if(args.length-1 != 1) {
currentBeanConfig = springConfig.addSingletonBean(name, beanClass, resolveConstructorArguments(args,1,args.length-1));
}
else {
currentBeanConfig = springConfig.addSingletonBean(name, beanClass);
}
}
else {
currentBeanConfig = springConfig.addSingletonBean(name, beanClass, resolveConstructorArguments(args,1,args.length));
}
}
}
else if(args[0] instanceof RuntimeBeanReference) {
currentBeanConfig = springConfig.addSingletonBean(name);
currentBeanConfig.setFactoryBean(((RuntimeBeanReference)args[0]).getBeanName());
}
else if(args[0] instanceof Map) {
// named constructor arguments
if(args.length > 1 && args[1] instanceof Class) {
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length-1 : args.length);
currentBeanConfig = springConfig.addSingletonBean(name, (Class)args[1], constructorArgs);
Map namedArgs = (Map)args[0];
for (Object o : namedArgs.keySet()) {
String propName = (String) o;
setProperty(propName, namedArgs.get(propName));
}
}
// factory method syntax
else {
currentBeanConfig = springConfig.addSingletonBean(name);
//First arg is the map containing factoryBean : factoryMethod
Map.Entry factoryBeanEntry = (Map.Entry)((Map)args[0]).entrySet().iterator().next();
// If we have a closure body, that will be the last argument.
// In between are the constructor args
int constructorArgsTest = hasClosureArgument?2:1;
// If we have more than this number of args, we have constructor args
if(args.length > constructorArgsTest){
//factory-method requires args
int endOfConstructArgs = hasClosureArgument? args.length-1 : args.length;
currentBeanConfig = springConfig.addSingletonBean(name, null, resolveConstructorArguments(args, 1, endOfConstructArgs));
} else {
currentBeanConfig = springConfig.addSingletonBean(name);
}
currentBeanConfig.setFactoryBean(factoryBeanEntry.getKey().toString());
currentBeanConfig.setFactoryMethod(factoryBeanEntry.getValue().toString());
}
}
else if(args[0] instanceof Closure) {
currentBeanConfig = springConfig.addAbstractBean(name);
}
else {
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length-1 : args.length);
currentBeanConfig = new DefaultBeanConfiguration(name, null, constructorArgs);
springConfig.addBeanConfiguration(name,currentBeanConfig);
}
if(hasClosureArgument) {
Closure callable = (Closure)args[args.length-1];
callable.setDelegate(this);
callable.setResolveStrategy(Closure.DELEGATE_FIRST);
callable.call(new Object[]{currentBeanConfig});
}
BeanConfiguration beanConfig = currentBeanConfig;
currentBeanConfig = null;
return beanConfig;
}
protected List resolveConstructorArguments(Object[] args, int start, int end) {
Object[] constructorArgs = subarray(args, start, end);
filterGStringReferences(constructorArgs);
for(int i = 0; i < constructorArgs.length; i++) {
if(constructorArgs[i] instanceof List) {
constructorArgs[i] = manageListIfNecessary(constructorArgs[i]);
} else if(constructorArgs[i] instanceof Map){
constructorArgs[i] = manageMapIfNecessary(constructorArgs[i]);
}
}
List constructorArgsList = Arrays.asList(constructorArgs);
return constructorArgsList;
}
protected Object[] subarray(Object[] args, int i, int j) {
if(j > args.length) throw new IllegalArgumentException("Upper bound can't be greater than array length");
Object[] b = new Object[j-i];
int n = 0;
for (int k = i; k < j; k++,n++) {
b[n] = args[k];
}
return b;
}
protected void filterGStringReferences(Object[] constructorArgs) {
for (int i = 0; i < constructorArgs.length; i++) {
Object constructorArg = constructorArgs[i];
if(constructorArg instanceof GString) constructorArgs[i] = constructorArg.toString();
}
}
/**
* When an methods argument is only a closure it is a set of bean definitions
*
* @param callable The closure argument
* @return This GroovyBeanDefinitionReader instance
*/
protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) {
callable.setDelegate(this);
// callable.setResolveStrategy(Closure.DELEGATE_FIRST);
callable.call();
finalizeDeferredProperties();
return this;
}
/**
* This method overrides property setting in the scope of the GroovyBeanDefinitionReader to set
* properties on the current BeanConfiguration
*/
public void setProperty(String name, Object value) {
if(currentBeanConfig != null) {
setPropertyOnBeanConfig(name, value);
}
}
/**
* Defines an inner bean definition
*
* @param type The bean type
* @return The bean definition
*/
public AbstractBeanDefinition bean(Class type) {
return springConfig.createSingletonBean(type).getBeanDefinition();
}
/**
* Defines an inner bean definition
*
* @param type The bean type
* @param args The constructors arguments and closure configurer
* @return The bean definition
*/
public AbstractBeanDefinition bean(Class type, Object...args) {
BeanConfiguration current = currentBeanConfig;
try {
Closure callable = null;
Collection constructorArgs = null;
if(args != null && args.length > 0) {
int index = args.length;
Object lastArg = args[index-1];
if(lastArg instanceof Closure) {
callable = (Closure) lastArg;
index--;
}
if(index > -1) {
constructorArgs = resolveConstructorArguments(args, 0, index);
}
}
currentBeanConfig = constructorArgs != null ? springConfig.createSingletonBean(type,constructorArgs) : springConfig.createSingletonBean(type);
if(callable != null) {
callable.call(new Object[]{currentBeanConfig});
}
return currentBeanConfig.getBeanDefinition();
}
finally {
currentBeanConfig = current;
}
}
protected void setPropertyOnBeanConfig(String name, Object value) {
if(value instanceof GString)value = value.toString();
if(addToDeferred(currentBeanConfig, name, value)) {
return;
}
else if(value instanceof Closure) {
BeanConfiguration current = currentBeanConfig;
try {
Closure callable = (Closure)value;
Class parameterType = callable.getParameterTypes()[0];
if(parameterType.equals(Object.class)) {
currentBeanConfig = springConfig.createSingletonBean("");
callable.call(new Object[]{currentBeanConfig});
}
else {
currentBeanConfig = springConfig.createSingletonBean(parameterType);
callable.call(null);
}
value = currentBeanConfig.getBeanDefinition();
}
finally {
currentBeanConfig = current;
}
}
currentBeanConfig.addProperty(name, value);
}
/**
* Checks whether there are any runtime refs inside a Map and converts
* it to a ManagedMap if necessary
*
* @param value The current map
* @return A ManagedMap or a normal map
*/
protected Object manageMapIfNecessary(Object value) {
Map map = (Map)value;
boolean containsRuntimeRefs = false;
for (Object e : map.values()) {
if (e instanceof RuntimeBeanReference) {
containsRuntimeRefs = true;
break;
}
}
if(containsRuntimeRefs) {
Map managedMap = new ManagedMap();
managedMap.putAll(map);
return managedMap;
}
return value;
}
/**
* Checks whether there are any runtime refs inside the list and
* converts it to a ManagedList if necessary
*
* @param value The object that represents the list
* @return Either a new list or a managed one
*/
protected Object manageListIfNecessary(Object value) {
List list = (List)value;
boolean containsRuntimeRefs = false;
for (Object e : list) {
if (e instanceof RuntimeBeanReference) {
containsRuntimeRefs = true;
break;
}
}
if(containsRuntimeRefs) {
List tmp = new ManagedList();
tmp.addAll((List)value);
value = tmp;
}
return value;
}
/**
* This method overrides property retrieval in the scope of the GroovyBeanDefinitionReader to either:
*
* a) Retrieve a variable from the bean builder's binding if it exists
* b) Retrieve a RuntimeBeanReference for a specific bean if it exists
* c) Otherwise just delegate to super.getProperty which will resolve properties from the GroovyBeanDefinitionReader itself
*/
public Object getProperty(String name) {
if(binding.containsKey(name)) {
return binding.get(name);
}
else {
if(namespaceHandlers.containsKey(name)) {
return createDynamicElementReader(name, currentBeanConfig!=null);
}
if(springConfig.containsBean(name)) {
BeanConfiguration beanConfig = springConfig.getBeanConfig(name);
if(beanConfig != null) {
return new ConfigurableRuntimeBeanReference(name, springConfig.getBeanConfig(name) ,false);
}
else
return new RuntimeBeanReference(name,false);
}
// this is to deal with the case where the property setter is the last
// statement in a closure (hence the return value)
else if(currentBeanConfig != null) {
if(currentBeanConfig.hasProperty(name))
return currentBeanConfig.getPropertyValue(name);
else {
DeferredProperty dp = deferredProperties.get(currentBeanConfig.getName()+name);
if(dp!=null) {
return dp.value;
}
else {
return super.getProperty(name);
}
}
}
else {
return super.getProperty(name);
}
}
}
protected DynamicElementReader createDynamicElementReader(String namespace, final boolean decorator) {
NamespaceHandler handler = namespaceHandlers.get(namespace);
ParserContext parserContext = new ParserContext(readerContext, new BeanDefinitionParserDelegate(readerContext));
final DynamicElementReader dynamicElementReader = new DynamicElementReader(namespace, this.namespaces, handler, parserContext) {
@Override
protected void afterInvocation() {
if(!decorator) {
currentBeanConfig = null;
}
}
};
dynamicElementReader.setClassLoader(classLoader);
if(currentBeanConfig!=null) {
dynamicElementReader.setBeanConfiguration(currentBeanConfig);
}
else if(!decorator) {
currentBeanConfig = new DefaultBeanConfiguration(namespace);
dynamicElementReader.setBeanConfiguration(currentBeanConfig);
}
dynamicElementReader.setBeanDecorator(decorator);
return dynamicElementReader;
}
/**
* Sets the binding (the variables available in the scope of the GroovyBeanDefinitionReader)
* @param b The Binding instance
*/
public void setBinding(Binding b) {
this.binding = b.getVariables();
}
}

160
spring-lang-groovy/src/main/java/org/springframework/context/groovy/GroovyPropertyApplicationContext.java

@ -0,0 +1,160 @@ @@ -0,0 +1,160 @@
/*
* Copyright 2010 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
*
* http://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 groovy.lang.GroovyObject;
import groovy.lang.GroovySystem;
import groovy.lang.MetaClass;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.ui.context.Theme;
import org.springframework.ui.context.ThemeSource;
import org.springframework.ui.context.support.UiApplicationContextUtils;
/**
* An ApplicationContext that extends StaticApplicationContext and implements GroovyObject such that beans can be retrieved with the dot
* de-reference syntax instead of using getBean('name')
*
*/
public class GroovyPropertyApplicationContext extends GenericApplicationContext implements GroovyObject {
protected MetaClass metaClass;
private BeanWrapper ctxBean = new BeanWrapperImpl(this);
private ThemeSource themeSource;
public GroovyPropertyApplicationContext(DefaultListableBeanFactory defaultListableBeanFactory) {
super(defaultListableBeanFactory);
this.metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
}
public GroovyPropertyApplicationContext(DefaultListableBeanFactory defaultListableBeanFactory, ApplicationContext applicationContext) {
super(defaultListableBeanFactory, applicationContext);
this.metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
}
public GroovyPropertyApplicationContext(org.springframework.context.ApplicationContext parent) throws org.springframework.beans.BeansException {
super(parent);
this.metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
}
public GroovyPropertyApplicationContext() throws org.springframework.beans.BeansException {
this.metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
}
public MetaClass getMetaClass() {
return this.metaClass;
}
public Object getProperty(String property) {
if(containsBean(property)) {
return getBean(property);
}
else if(ctxBean.isReadableProperty(property)) {
return ctxBean.getPropertyValue(property);
}
return null;
}
public Object invokeMethod(String name, Object args) {
return metaClass.invokeMethod(this, name, args);
}
public void setMetaClass(MetaClass metaClass) {
this.metaClass = metaClass;
}
/**
* Initialize the theme capability.
*/
protected void onRefresh() {
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}
public Theme getTheme(String themeName) {
return this.themeSource.getTheme(themeName);
}
public void setProperty(String property, Object newValue) {
if(newValue instanceof BeanDefinition) {
if(containsBean(property)) {
removeBeanDefinition(property);
}
registerBeanDefinition(property, (BeanDefinition)newValue);
}
else {
metaClass.setProperty(this, property, newValue);
}
}
/**
* Register a singleton bean with the underlying bean factory.
* <p>For more advanced needs, register with the underlying BeanFactory directly.
* @see #getDefaultListableBeanFactory
*/
public void registerSingleton(String name, Class clazz) throws BeansException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(clazz);
getDefaultListableBeanFactory().registerBeanDefinition(name, bd);
}
/**
* Register a singleton bean with the underlying bean factory.
* <p>For more advanced needs, register with the underlying BeanFactory directly.
* @see #getDefaultListableBeanFactory
*/
public void registerSingleton(String name, Class clazz, MutablePropertyValues pvs) throws BeansException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(clazz);
bd.setPropertyValues(pvs);
getDefaultListableBeanFactory().registerBeanDefinition(name, bd);
}
/**
* Register a prototype bean with the underlying bean factory.
* <p>For more advanced needs, register with the underlying BeanFactory directly.
* @see #getDefaultListableBeanFactory
*/
public void registerPrototype(String name, Class clazz) throws BeansException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE);
bd.setBeanClass(clazz);
getDefaultListableBeanFactory().registerBeanDefinition(name, bd);
}
/**
* Register a prototype bean with the underlying bean factory.
* <p>For more advanced needs, register with the underlying BeanFactory directly.
* @see #getDefaultListableBeanFactory
*/
public void registerPrototype(String name, Class clazz, MutablePropertyValues pvs) throws BeansException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE);
bd.setBeanClass(clazz);
bd.setPropertyValues(pvs);
getDefaultListableBeanFactory().registerBeanDefinition(name, bd);
}
}

232
spring-lang-groovy/src/main/java/org/springframework/context/groovy/RuntimeSpringConfiguration.java

@ -0,0 +1,232 @@ @@ -0,0 +1,232 @@
/*
* Copyright 2010 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
*
* http://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.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import java.util.Collection;
import java.util.List;
/**
* A programmable runtime Spring configuration that allows a spring ApplicationContext
* to be constructed at runtime
*
* Credit must go to Solomon Duskis and the
* article: http://jroller.com/page/Solomon?entry=programmatic_configuration_in_spring
*
*/
public interface RuntimeSpringConfiguration {
/**
* Adds a singleton bean definition
*
* @param name The name of the bean
* @param clazz The class of the bean
* @return A BeanConfiguration instance
*/
public BeanConfiguration addSingletonBean(String name, Class clazz);
public ApplicationContext getUnrefreshedApplicationContext();
/**
* Adds a prototype bean definition
*
* @param name The name of the bean
* @param clazz The class of the bean
* @return A BeanConfiguration instance
*/
public BeanConfiguration addPrototypeBean(String name, Class clazz);
/**
* Retrieves the application context from the current state
*
* @return The ApplicationContext instance
*/
ApplicationContext getApplicationContext();
/**
* Adds an empty singleton bean configuration
* @param name The name of the singleton bean
*
* @return A BeanConfiguration instance
*/
public BeanConfiguration addSingletonBean(String name);
/**
* Adds an empty prototype bean configuration
*
* @param name The name of the prototype bean
* @return A BeanConfiguration instance
*/
public BeanConfiguration addPrototypeBean(String name);
/**
* Creates a singleton bean configuration. Differs from addSingletonBean in that
* it doesn't add the bean to the list of bean references. Hence should be used for
* creating nested beans
*
* @param clazz
* @return A BeanConfiguration instance
*/
public BeanConfiguration createSingletonBean(Class clazz);
/**
* Creates a new singleton bean and adds it to the list of bean references
*
* @param name The name of the bean
* @param clazz The class of the bean
* @param args The constructor arguments of the bean
* @return A BeanConfiguration instance
*/
public BeanConfiguration addSingletonBean(String name, Class clazz, Collection args);
/**
* Creates a singleton bean configuration. Differs from addSingletonBean in that
* it doesn't add the bean to the list of bean references. Hence should be used for
* creating nested beans
*
* @param clazz The bean class
* @param constructorArguments The constructor arguments
* @return A BeanConfiguration instance
*/
public BeanConfiguration createSingletonBean(Class clazz, Collection constructorArguments);
/**
* Creates a new prototype bean configuration. Differs from addPrototypeBean in that
* it doesn't add the bean to the list of bean references to be created via the getApplicationContext()
* method, hence can be used for creating nested beans
*
* @param name The bean name
* @return A BeanConfiguration instance
*
*/
public BeanConfiguration createPrototypeBean(String name);
/**
* Creates a new singleton bean configuration. Differs from addSingletonBean in that
* it doesn't add the bean to the list of bean references to be created via the getApplicationContext()
* method, hence can be used for creating nested beans
*
* @param name The bean name
* @return A BeanConfiguration instance
*
*/
public BeanConfiguration createSingletonBean(String name);
/**
* Adds a bean configuration to the list of beans to be created
*
* @param beanName The name of the bean in the context
* @param beanConfiguration The BeanConfiguration instance
*/
void addBeanConfiguration(String beanName, BeanConfiguration beanConfiguration);
/**
* Adds a Spring BeanDefinition. Differs from BeanConfiguration which is a factory class
* for creating BeanDefinition instances
* @param name The name of the bean
* @param bd The BeanDefinition instance
*/
public void addBeanDefinition(String name, BeanDefinition bd);
/**
* Returns whether the runtime spring config contains the specified bean
*
* @param name The bean name
* @return True if it does
*/
public boolean containsBean(String name);
/**
* Returns the BeanConfiguration for the specified name
* @param name The name of the bean configuration
* @return The BeanConfiguration
*/
public BeanConfiguration getBeanConfig(String name);
/**
* Creates and returns the BeanDefinition that is regsitered within the given name or returns null
*
* @param name The name of the bean definition
* @return A BeanDefinition
*/
public AbstractBeanDefinition createBeanDefinition(String name);
/**
* Registers a bean factory post processor with the context
*
* @param processor The BeanFactoryPostProcessor instance
*/
public void registerPostProcessor(BeanFactoryPostProcessor processor);
List getBeanNames();
/**
* Registers the beans held within this RuntimeSpringConfiguration instance with the given ApplicationContext
*
* @param applicationContext The ApplicationContext instance
*/
void registerBeansWithContext(GenericApplicationContext applicationContext);
/**
* Registers the beans held within this RuntimeSpringConfiguration instance with the given BeanDefinitionRegistry
*
* @param registry The BeanDefinitionRegistry instance
*/
void registerBeansWithRegistry(BeanDefinitionRegistry registry);
/**
* Registers the beans held within this RuntimeSpringConfiguration instance with the given RuntimeSpringConfiguration
*
* @param targetSpringConfig The RuntimeSpringConfiguration instance
*/
void registerBeansWithConfig(RuntimeSpringConfiguration targetSpringConfig);
/**
* Adds an abstract bean definition to the bean factory and returns the BeanConfiguration object
*
* @param name The name of the bean
* @return The BeanConfiguration object
*/
BeanConfiguration addAbstractBean(String name);
/**
* Adds an alias to a given bean name
*
* @param alias The alias
* @param beanName The bean
*/
void addAlias(String alias, String beanName);
/**
* Obtains a BeanDefinition instance for the given beanName
*
* @param beanName The beanName
* @return The BeanDefinition or null if it doesn't exit
*/
BeanDefinition getBeanDefinition(String beanName);
/**
* Sets the BeanFactory implementation to use
* @param beanFactory The BeanFactory implementation
*/
void setBeanFactory(ListableBeanFactory beanFactory);
}

37
spring-lang-groovy/src/test/groovy/org/springframework/context/groovy/DynamicElementReaderTests.groovy

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
/*
* Copyright 2010 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
*
* http://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.springframework.context.groovy.DynamicElementReader;
import org.w3c.dom.Element
public class DynamicElementReaderTests extends GroovyTestCase{
void testReadMethodToElement() {
def elementReader = new DynamicElementReader("jee", [jee:"http://www.springframework.org/schema/jee"])
try {
elementReader.'jndi-lookup'(id:"dataSource", 'jndi-name':"jdbc/petstore")
}
catch (e) {
assertEquals """Configuration problem: No namespace handler found for element <jee:jndi-lookup id='dataSource' jndi-name='jdbc/petstore' xmlns:jee='http://www.springframework.org/schema/jee'/>
Offending resource: resource loaded from byte array""", e.message
}
}
}

41
spring-lang-groovy/src/test/groovy/org/springframework/context/groovy/GroovyBeanDefinitionApplicationContextDynamicBeanPropertyTests.groovy

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
/*
* Copyright 2010 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
*
* http://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.springframework.beans.factory.NoSuchBeanDefinitionException
public class GroovyBeanDefinitionApplicationContextDynamicBeanPropertyTests extends GroovyTestCase {
void testAccessDynamicBeanProperties() {
def ctx = new GroovyBeanDefinitionApplicationContext(
"org/springframework/context/groovy/applicationContext.groovy");
def framework = ctx.framework
assertNotNull 'could not find framework bean', framework
assertEquals 'Grails', framework
}
void testAccessingNonExistentBeanViaDynamicProperty() {
def ctx = new GroovyBeanDefinitionApplicationContext(
"org/springframework/context/groovy/applicationContext.groovy");
def err = shouldFail(NoSuchBeanDefinitionException) {
ctx.someNonExistentBean
}
assertEquals "No bean named 'someNonExistentBean' is defined", err
}
}

993
spring-lang-groovy/src/test/groovy/org/springframework/context/groovy/GroovyBeanDefinitionReaderTests.groovy

@ -0,0 +1,993 @@ @@ -0,0 +1,993 @@
/*
* Copyright 2010 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
*
* http://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.springframework.aop.SpringProxy
import org.springframework.beans.factory.ObjectFactory
import org.springframework.beans.factory.config.Scope
import org.springframework.context.ApplicationContext
import org.springframework.context.support.GenericApplicationContext
import org.springframework.mock.jndi.SimpleNamingContextBuilder
import org.springframework.stereotype.Component
class GroovyBeanDefinitionReaderTests extends GroovyTestCase {
void testImportSpringXml() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
importBeans "classpath:org/springframework/context/groovy/test.xml"
}
def ctx = beanReader.createApplicationContext()
def foo = ctx.getBean("foo")
assertEquals "hello", foo
}
void testImportBeansFromGroovy() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
importBeans "file:src/test/resources/org/springframework/context/groovy/applicationContext.groovy"
}
def ctx = beanReader.createApplicationContext()
def foo = ctx.getBean("foo")
assertEquals "hello", foo
}
void testInheritPropertiesFromAbstractBean() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
myB(Bean1){
person = "wombat"
}
myAbstractA(Bean2){ bean ->
bean.'abstract' = true
age = 10
bean1 = myB
}
myConcreteB {
it.parent = myAbstractA
}
}
def ctx = beanReader.createApplicationContext()
def bean = ctx.getBean("myConcreteB")
assertEquals 10, bean.age
assertNotNull bean.bean1
}
void testContextComponentScanSpringTag() {
if(notYetImplemented()) return
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
xmlns grailsContext:"http://grails.org/schema/context"
grailsContext.'component-scan'( 'base-package' :"**" )
}
def appCtx = beanReader.createApplicationContext()
def p = appCtx.getBean("person")
assertTrue( p instanceof AdvisedPerson )
assertNotNull p
}
void testUseSpringNamespaceAsMethod() {
if(notYetImplemented()) return
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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 grails.spring.AdvisedPerson.birthday()) and this(person)"
}
}
}
}
def appCtx = beanReader.createApplicationContext()
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
}
void testUseTwoSpringNamespaces() {
def beanReader = new GroovyBeanDefinitionReader()
TestScope scope = new TestScope()
GenericApplicationContext appCtx = beanReader.getSpringConfig().getUnrefreshedApplicationContext()
appCtx.getBeanFactory().registerScope("test", scope)
beanReader.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 = beanReader.createApplicationContext()
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
beanReader = new GroovyBeanDefinitionReader()
appCtx = beanReader.getSpringConfig().getUnrefreshedApplicationContext()
appCtx.getBeanFactory().registerScope("test", scope)
beanReader.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 = beanReader.createApplicationContext()
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
}
void testSpringAOPSupport() {
if(notYetImplemented()) return
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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 grails.spring.AdvisedPerson.birthday()) and this(person)"
}
}
}
def appCtx = beanReader.createApplicationContext()
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
}
void testSpringScopedProxyBean() {
def beanReader = new GroovyBeanDefinitionReader()
GenericApplicationContext appCtx = beanReader.getSpringConfig().getUnrefreshedApplicationContext()
TestScope scope = new TestScope()
appCtx.getBeanFactory().registerScope("test", scope)
beanReader.beans {
xmlns aop:"http://www.springframework.org/schema/aop"
scopedList(ArrayList) { bean ->
bean.scope = "test"
aop.'scoped-proxy'()
}
}
appCtx = beanReader.createApplicationContext()
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
}
void testSpringNamespaceBean() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
xmlns util: 'http://www.springframework.org/schema/util'
util.list(id: 'foo') {
value 'one'
value 'two'
}
}
def ctx = beanReader.createApplicationContext()
assert ['one', 'two'] == ctx.getBean('foo')
}
void testNamedArgumentConstructor() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
holyGrail(HolyGrailQuest)
knights(KnightOfTheRoundTable, "Camelot", leader:"lancelot", quest: holyGrail)
}
def ctx = beanReader.createApplicationContext()
KnightOfTheRoundTable knights = ctx.getBean("knights")
HolyGrailQuest quest = ctx.getBean("holyGrail")
assertEquals "Camelot", knights.name
assertEquals "lancelot", knights.leader
assertEquals quest, knights.quest
}
void testAbstractBeanDefinition() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
abstractBean {
leader = "Lancelot"
}
quest(HolyGrailQuest)
knights(KnightOfTheRoundTable, "Camelot") { bean ->
bean.parent = abstractBean
quest = quest
}
}
def ctx = beanReader.createApplicationContext()
def knights = ctx.knights
assert knights
shouldFail(org.springframework.beans.factory.BeanIsAbstractException) {
ctx.abstractBean
}
assertEquals "Lancelot", knights.leader
}
void testAbstractBeanDefinitionWithClass() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
abstractBean(KnightOfTheRoundTable) { bean ->
bean.'abstract' = true
leader = "Lancelot"
}
quest(HolyGrailQuest)
knights("Camelot") { bean ->
bean.parent = abstractBean
quest = quest
}
}
def ctx = beanReader.createApplicationContext()
shouldFail(org.springframework.beans.factory.BeanIsAbstractException) {
ctx.abstractBean
}
def knights = ctx.knights
assert knights
assertEquals "Lancelot", knights.leader
}
void testScopes() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
myBean(ScopeTest) { bean ->
bean.scope = "prototype"
}
myBean2(ScopeTest)
}
def ctx = beanReader.createApplicationContext()
def b1 = ctx.myBean
def b2 = ctx.myBean
assert b1 != b2
b1 = ctx.myBean2
b2 = ctx.myBean2
assertEquals b1, b2
}
void testSimpleBean() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
bean1(Bean1) {
person = "homer"
age = 45
props = [overweight:true, height:"1.8m"]
children = ["bart", "lisa"]
}
}
def ctx = beanReader.createApplicationContext()
assert ctx.containsBean("bean1")
def bean1 = ctx.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)
}
void testBeanWithParentRef() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
homer(Bean1) {
person = "homer"
age = 45
props = [overweight:true, height:"1.8m"]
children = ["bart", "lisa"]
}
}
beanReader = new GroovyBeanDefinitionReader(beanReader.createApplicationContext())
beanReader.beans {
bart(Bean2) {
person = "bart"
parent = ref("homer", true)
}
}
def ctx = beanReader.createApplicationContext()
assert ctx != null
assert ctx.containsBean("bart")
def bart = ctx.getBean("bart")
assertEquals "homer",bart.parent?.person
}
void testWithAnonymousInnerBean() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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]
}
}
def ctx = beanReader.createApplicationContext()
def marge = ctx.getBean("marge")
assertEquals "homer", marge.bean1.person
}
void testWithUntypedAnonymousInnerBean() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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]
}
}
def ctx = beanReader.createApplicationContext()
def marge = ctx.getBean("marge")
assertEquals "homer", marge.bean1.person
}
void testBeanReferences() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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]
}
}
def ctx = beanReader.createApplicationContext()
def homer = ctx.getBean("homer")
def marge = ctx.getBean("marge")
def bart = ctx.getBean("bart")
def lisa = ctx.getBean("lisa")
assertEquals homer, marge.bean1
assertEquals 2, marge.children.size()
assertTrue marge.children.contains(bart)
assertTrue marge.children.contains(lisa)
}
void testBeanWithConstructor() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
homer(Bean1) {
person = "homer"
age = 45
}
marge(Bean3, "marge", homer) {
age = 40
}
}
def ctx = beanReader.createApplicationContext()
def marge = ctx.getBean("marge")
assertEquals "marge", marge.person
assertEquals "homer", marge.bean1.person
assertEquals 40, marge.age
}
void testBeanWithFactoryMethod() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
homer(Bean1) {
person = "homer"
age = 45
}
def marge = marge(Bean4) {
person = "marge"
}
marge.factoryMethod = "getInstance"
}
def ctx = beanReader.createApplicationContext()
def marge = ctx.getBean("marge")
assert "marge", marge.person
}
void testBeanWithFactoryMethodUsingClosureArgs() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
homer(Bean1) {
person = "homer"
age = 45
}
marge(Bean4) { bean ->
bean.factoryMethod = "getInstance"
person = "marge"
}
}
def ctx = beanReader.createApplicationContext()
def marge = ctx.getBean("marge")
assert "marge", marge.person
}
void testBeanWithFactoryMethodWithConstructorArgs() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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"
}
}
def ctx = beanReader.createApplicationContext()
def homer = ctx.getBean("homer")
assert "homer", homer.person
assert 45, homer.age
assert "marge", ctx.getBean("marge").person
assert "mcBain", ctx.getBean("mcBain").person
}
void testGetBeanDefinitions() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
jeff(Bean1) {
person = 'jeff'
}
graeme(Bean1) {
person = 'graeme'
}
guillaume(Bean1) {
person = 'guillaume'
}
}
def beanDefinitions = beanReader.beanDefinitions
assertNotNull 'beanDefinitions was null', beanDefinitions
assertEquals 'beanDefinitions was the wrong size', 3, beanDefinitions.size()
assertNotNull 'beanDefinitions did not contain jeff', beanDefinitions['jeff']
assertNotNull 'beanDefinitions did not contain guillaume', beanDefinitions['guillaume']
assertNotNull 'beanDefinitions did not contain graeme', beanDefinitions['graeme']
}
void testBeanWithFactoryBean() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
myFactory(Bean1Factory)
homer(myFactory) { bean ->
bean.factoryMethod = "newInstance"
person = "homer"
age = 45
}
}
def ctx = beanReader.createApplicationContext()
def homer = ctx.getBean("homer")
assertEquals "homer", homer.person
}
void testBeanWithFactoryBeanAndMethod() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
myFactory(Bean1Factory)
homer(myFactory:"newInstance") { bean ->
person = "homer"
age = 45
}
}
def ctx = beanReader.createApplicationContext()
def homer = ctx.getBean("homer")
assertEquals "homer", homer.person
}
void testLoadExternalBeans() {
def pr = new org.springframework.core.io.support.PathMatchingResourcePatternResolver()
def r = pr.getResource("file:src/test/resources/org/springframework/context/groovy/applicationContext.groovy")
def beanReader = new GroovyBeanDefinitionReader()
beanReader.loadBeans(r)
def ctx = beanReader.createApplicationContext()
assert ctx.containsBean("foo")
def foo = ctx.getBean("foo")
}
void testHolyGrailWiring() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
quest(HolyGrailQuest)
knight(KnightOfTheRoundTable, "Bedivere") {
quest = ref("quest")
}
}
def ctx = beanReader.createApplicationContext()
def knight = ctx.getBean("knight")
knight.embarkOnQuest()
}
void testAbstractBeanSpecifyingClass() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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"
}
}
def ctx = beanReader.createApplicationContext()
def lancelot = ctx.getBean("lancelot")
assertEquals "King Arthur", lancelot.leader
assertEquals "lancelot", lancelot.name
def homerBean = ctx.getBean("homerBean")
assertEquals 45, homerBean.age
assertEquals "homer", homerBean.person
}
void testGroovyBeanDefinitionReaderWithScript() {
def script = '''
def beanReader = new org.springframework.context.groovy.GroovyBeanDefinitionReader()
beanReader.beans {
quest(org.springframework.context.groovy.HolyGrailQuest) {}
knight(org.springframework.context.groovy.KnightOfTheRoundTable, "Bedivere") { quest = quest }
}
beanReader.createApplicationContext()
'''
def ctx = new GroovyShell().evaluate(script)
def knight = ctx.getBean('knight')
knight.embarkOnQuest()
}
// test for GRAILS-5057
void testRegisterBeans() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
personA(AdvisedPerson) {
name = "Bob"
}
}
def appCtx = beanReader.createApplicationContext()
assertEquals "Bob", appCtx.getBean("personA").name
beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
personA(AdvisedPerson) {
name = "Fred"
}
}
beanReader.registerBeans(appCtx)
assertEquals "Fred", appCtx.getBean("personA").name
}
void testListOfBeansAsConstructorArg() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.beans {
someotherbean(SomeOtherClass, new File('somefile.txt'))
someotherbean2(SomeOtherClass, new File('somefile.txt'))
somebean(SomeClass, [someotherbean, someotherbean2])
}
def ctx = beanReader.createApplicationContext()
assert ctx.containsBean('someotherbean')
assert ctx.containsBean('someotherbean2')
assert ctx.containsBean('somebean')
}
void testBeanWithListAndMapConstructor() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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')])
}
def ctx = beanReader.createApplicationContext()
def beanWithList = ctx.getBean("beanWithList")
assertEquals 2, beanWithList.people.size()
assertEquals "bart", beanWithList.people[0].person
def beanWithMap = ctx.getBean("beanWithMap")
assertEquals 9, beanWithMap.peopleByName.lisa.age
assertEquals "bart", beanWithMap.peopleByName.bart.person
}
void testAnonymousInnerBeanViaBeanMethod() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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]
}
}
def ctx = beanReader.createApplicationContext()
def marge = ctx.getBean("marge")
assertEquals "homer", marge.bean1.person
}
void testAnonymousInnerBeanViaBeanMethodWithConstructorArgs() {
def beanReader = new GroovyBeanDefinitionReader()
beanReader.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]
}
}
def ctx = beanReader.createApplicationContext()
def marge = ctx.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<Bean1> people) {
this.people = people
}
List<Bean1> people
}
// bean with Map-valued constructor arg
class Bean6 {
Bean6(Map<String, Bean1> peopleByName) {
this.peopleByName = peopleByName
}
Map<String, Bean1> peopleByName
}
// a factory bean
class Bean1Factory {
Bean1 newInstance() {
return new Bean1()
}
}
class ScopeTest {}
class TestScope implements Scope {
int instanceCount
public Object remove(String name) {
// do nothing
}
public void registerDestructionCallback(String name, Runnable callback) {
}
public String getConversationId() {
return "mock"
}
public Object get(String name, ObjectFactory<?> objectFactory) {
instanceCount++
objectFactory.getObject()
}
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<SomeOtherClass> soc) {}
}
class SomeOtherClass {
public SomeOtherClass(File f) {}
}
// a factory bean that takes arguments
class Bean1FactoryWithArgs {
Bean1 newInstance(String name) {
new Bean1(person:name)
}
}

125
spring-lang-groovy/src/test/java/org/springframework/context/groovy/GroovyBeanDefinitionApplicationContextTests.java

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
/*
* Copyright 2010 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
*
* http://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 junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
public class GroovyBeanDefinitionApplicationContextTests extends TestCase {
/*
NOTE: The code in this test case includes casts that look a bit funky...
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources);
Important to note is that the cast is only necessary because this test is being compiled along
with GroovyBeanDefinitionApplicationContext. This is related to a limitation in the compiler with respect
to AST transformations, in this case @Delegate. The problem will not show up when building via
gradle or other build tools. The problem may show up in an IDE where the IDE doesn't "think"
that GroovyBeanDefinitionApplicationContext is a ApplicationContext.
Normal users of GroovyBeanDefinitionApplicationContext will not need to impose this cast
because the compiled GroovyBeanDefinitionApplicationContext class will in fact implement ApplicationContext.
*/
public void testLoadingMultipleConfigFiles() {
String[] resources = new String[] {
"org/springframework/context/groovy/applicationContext2.groovy",
"org/springframework/context/groovy/applicationContext.groovy" };
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources);
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
Object company = ctx.getBean("company");
assertNotNull("could not find company bean", company);
assertEquals("SpringSource", company);
}
public void testLoadingConfigFile() {
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(
"org/springframework/context/groovy/applicationContext.groovy");
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
}
public void testLoadingConfigFileRelativeToClass() {
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(
"applicationContext.groovy", GroovyBeanDefinitionApplicationContextTests.class);
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
}
public void testLoadingMultipleConfigFilesRelativeToClass() {
String[] resources = new String[] {
"applicationContext2.groovy",
"applicationContext.groovy" };
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources, GroovyBeanDefinitionApplicationContextTests.class);
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
Object company = ctx.getBean("company");
assertNotNull("could not find company bean", company);
assertEquals("SpringSource", company);
}
public void testLoadingConfigFileWithFileReference() {
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(
"file:src/test/resources/org/springframework/context/groovy/applicationContext.groovy");
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
}
public void testLoadingMultipleConfigFilesWithFileReferences() {
String[] resources = new String[] {
"file:src/test/resources/org/springframework/context/groovy/applicationContext2.groovy",
"file:src/test/resources/org/springframework/context/groovy/applicationContext.groovy" };
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources);
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
Object company = ctx.getBean("company");
assertNotNull("could not find company bean", company);
assertEquals("SpringSource", company);
}
public void testLoadingMultipleConfigFilesWithFileAndClasspathReferences() {
String[] resources = new String[] {
"file:src/test/resources/org/springframework/context/groovy/applicationContext2.groovy",
"classpath:org/springframework/context/groovy/applicationContext.groovy" };
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources);
Object framework = ctx.getBean("framework");
assertNotNull("could not find framework bean", framework);
assertEquals("Grails", framework);
Object company = ctx.getBean("company");
assertNotNull("could not find company bean", company);
assertEquals("SpringSource", company);
}
}

4
spring-lang-groovy/src/test/resources/org/springframework/context/groovy/applicationContext.groovy

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
beans {
framework String, 'Grails'
foo String, 'hello'
}

3
spring-lang-groovy/src/test/resources/org/springframework/context/groovy/applicationContext2.groovy

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
beans {
company String, 'SpringSource'
}

9
spring-lang-groovy/src/test/resources/org/springframework/context/groovy/test.xml

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="foo" class="java.lang.String">
<constructor-arg value="hello" />
</bean>
</beans>
Loading…
Cancel
Save