Skip to content

Commit a6879b1

Browse files
Adding some beanbuilder code to the build
1 parent 6249539 commit a6879b1

17 files changed

+3573
-1
lines changed

build.gradle

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ configure(subprojects) { subproject ->
8585
archives sourcesJar
8686
archives javadocJar
8787
}
88+
ext {
89+
groovyVersion = '1.6.3'
90+
groovyDependencySpec = "org.codehaus.groovy:groovy-all:$groovyVersion"
91+
}
8892
}
8993

9094

@@ -165,6 +169,26 @@ project('spring-beans') {
165169
}
166170
}
167171

172+
project('spring-lang-groovy') {
173+
apply plugin: 'groovy'
174+
description 'Spring BeanBuilder'
175+
dependencies {
176+
groovy groovyDependencySpec
177+
compile project(':spring-beans')
178+
compile project(':spring-context')
179+
compile groovyDependencySpec
180+
testCompile project(':spring-test')
181+
}
182+
compileJava.enabled=false
183+
sourceSets {
184+
main {
185+
groovy {
186+
srcDir 'src/main/java'
187+
}
188+
}
189+
}
190+
}
191+
168192
project('spring-aop') {
169193
description = 'Spring AOP'
170194
dependencies {
@@ -222,7 +246,7 @@ project('spring-context') {
222246
exclude group: 'javax.jws', module: 'jsr181'
223247
}
224248
compile("org.beanshell:bsh:2.0b4", optional)
225-
compile("org.codehaus.groovy:groovy-all:1.6.3", optional)
249+
compile(groovyDependencySpec, optional)
226250
compile("org.jruby:jruby:1.4.0", optional)
227251
compile("org.hibernate:hibernate-validator:4.2.0.Final") { dep ->
228252
optional dep

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ include 'spring-instrument'
1212
include 'spring-instrument-tomcat'
1313
include 'spring-jdbc'
1414
include 'spring-jms'
15+
include 'spring-lang-groovy'
1516
include 'spring-orm'
1617
include 'spring-oxm'
1718
include 'spring-struts'
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright 2010 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.context.groovy
17+
18+
import groovy.xml.StreamingMarkupBuilder
19+
import org.apache.commons.logging.LogFactory
20+
import org.springframework.beans.factory.config.BeanDefinitionHolder
21+
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException
22+
import org.springframework.beans.factory.parsing.Location
23+
import org.springframework.beans.factory.parsing.Problem
24+
import org.springframework.beans.factory.xml.DefaultDocumentLoader
25+
import org.springframework.beans.factory.xml.DelegatingEntityResolver
26+
import org.springframework.beans.factory.xml.NamespaceHandler
27+
import org.springframework.beans.factory.xml.ParserContext
28+
import org.springframework.core.io.ByteArrayResource
29+
import org.springframework.util.xml.SimpleSaxErrorHandler
30+
import org.springframework.util.xml.XmlValidationModeDetector
31+
import org.w3c.dom.Element
32+
import org.xml.sax.EntityResolver
33+
import org.xml.sax.ErrorHandler
34+
import org.xml.sax.InputSource
35+
36+
/**
37+
* Used by GroovyBeanDefinitionReader to read a Spring namespace expression in the Groovy DSL
38+
*
39+
* @see GroovyBeanDefinitionReader
40+
*
41+
*/
42+
43+
class DynamicElementReader extends GroovyObjectSupport{
44+
45+
46+
private static final LOG = LogFactory.getLog(GroovyBeanDefinitionReader)
47+
48+
private Map xmlNamespaces
49+
private String rootNamespace
50+
ErrorHandler errorHandler = new SimpleSaxErrorHandler(LOG);
51+
int validationMode = XmlValidationModeDetector.VALIDATION_NONE
52+
EntityResolver entityResolver = new DelegatingEntityResolver(DynamicElementReader.class.getClassLoader())
53+
ParserContext parserContext
54+
NamespaceHandler namespaceHandler
55+
BeanConfiguration beanConfiguration
56+
boolean beanDecorator = false
57+
boolean firstCall = true
58+
59+
public DynamicElementReader(String namespace, Map namespaceMap=Collections.EMPTY_MAP, NamespaceHandler namespaceHandler = null, ParserContext parserContext = null) {
60+
super();
61+
this.xmlNamespaces = namespaceMap;
62+
this.rootNamespace = namespace
63+
this.namespaceHandler = namespaceHandler
64+
this.parserContext = parserContext
65+
}
66+
67+
void setClassLoader(ClassLoader classLoader) {
68+
entityResolver = new DelegatingEntityResolver(classLoader)
69+
}
70+
71+
/**
72+
* Hook that subclass or anonymous classes can overwrite to implement custom behavior after invocation
73+
* completes
74+
*/
75+
protected void afterInvocation() {
76+
// NOOP
77+
}
78+
79+
@Override
80+
public Object invokeMethod(String name, Object args) {
81+
boolean invokeAfterInterceptor = false
82+
if(firstCall) {
83+
invokeAfterInterceptor = true
84+
firstCall=false
85+
}
86+
if(name.equals("doCall")) {
87+
def callable = args[0]
88+
callable.resolveStrategy = Closure.DELEGATE_FIRST
89+
callable.delegate = this
90+
def result = callable.call()
91+
if(invokeAfterInterceptor) {
92+
afterInvocation()
93+
}
94+
return result
95+
}
96+
else {
97+
StreamingMarkupBuilder builder = new StreamingMarkupBuilder();
98+
def myNamespaces = xmlNamespaces
99+
def myNamespace = rootNamespace
100+
101+
def callable = {
102+
for(namespace in myNamespaces) {
103+
mkp.declareNamespace( [(namespace.key):namespace.value] )
104+
}
105+
if(args && (args[-1] instanceof Closure)) {
106+
args[-1].resolveStrategy = Closure.DELEGATE_FIRST
107+
args[-1].delegate = builder
108+
}
109+
delegate."$myNamespace"."$name"(*args)
110+
}
111+
112+
callable.resolveStrategy=Closure.DELEGATE_FIRST
113+
callable.delegate = builder
114+
def writable = builder.bind( callable )
115+
116+
def sw = new StringWriter()
117+
writable.writeTo(sw)
118+
119+
def documentLoader = new DefaultDocumentLoader()
120+
InputSource is = new InputSource(new StringReader(sw.toString()))
121+
Element element = documentLoader.loadDocument(is, entityResolver, errorHandler, validationMode, true).getDocumentElement()
122+
123+
parserContext?.delegate?.initDefaults element
124+
if(namespaceHandler && parserContext) {
125+
if(beanDecorator && beanConfiguration) {
126+
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanConfiguration.getBeanDefinition(), beanConfiguration.getName());
127+
holder = namespaceHandler.decorate(element,holder, parserContext)
128+
beanConfiguration.setBeanDefinition(holder.getBeanDefinition())
129+
}
130+
else {
131+
132+
def beanDefinition = namespaceHandler.parse(element, parserContext)
133+
if(beanDefinition) {
134+
beanConfiguration?.setBeanDefinition(beanDefinition)
135+
}
136+
}
137+
}
138+
else {
139+
throw new BeanDefinitionParsingException(new Problem("No namespace handler found for element ${sw}", new Location(parserContext?.readerContext?.resource ?: new ByteArrayResource(new byte[0]))))
140+
}
141+
if(invokeAfterInterceptor) {
142+
afterInvocation()
143+
}
144+
return element
145+
146+
}
147+
}
148+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2010 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.context.groovy;
17+
18+
19+
import org.springframework.context.ApplicationContext
20+
import org.springframework.core.io.ClassPathResource
21+
22+
class GroovyBeanDefinitionApplicationContext {
23+
24+
@Delegate
25+
private ApplicationContext applicationContext
26+
27+
GroovyBeanDefinitionApplicationContext(String resource) {
28+
this([resource] as String[])
29+
}
30+
31+
GroovyBeanDefinitionApplicationContext(String[] resources) {
32+
initializeApplicationContext resources
33+
}
34+
35+
GroovyBeanDefinitionApplicationContext(String resource, Class clazz) {
36+
this([resource] as String[], clazz)
37+
}
38+
39+
GroovyBeanDefinitionApplicationContext(String[] resources, Class clazz) {
40+
def classPathResources = resources.collect { new ClassPathResource(it, clazz) }
41+
initializeApplicationContext classPathResources
42+
}
43+
44+
private initializeApplicationContext(resources) {
45+
def bb = new GroovyBeanDefinitionReader()
46+
resources.each { bb.loadBeans it }
47+
applicationContext = bb.createApplicationContext()
48+
}
49+
50+
def propertyMissing(String propertyName) {
51+
applicationContext.getBean(propertyName)
52+
}
53+
}

0 commit comments

Comments
 (0)