diff --git a/.springBeans b/.springBeans new file mode 100644 index 00000000000..6c6cb5a2848 --- /dev/null +++ b/.springBeans @@ -0,0 +1,13 @@ + + + 1 + + + + + + + + + + diff --git a/src/java/org/codehaus/groovy/grails/commons/metaclass/BaseApiProvider.java b/src/java/org/codehaus/groovy/grails/commons/metaclass/BaseApiProvider.java index bb6a75da825..c1de56d2f70 100644 --- a/src/java/org/codehaus/groovy/grails/commons/metaclass/BaseApiProvider.java +++ b/src/java/org/codehaus/groovy/grails/commons/metaclass/BaseApiProvider.java @@ -15,17 +15,20 @@ */ package org.codehaus.groovy.grails.commons.metaclass; -import groovy.lang.MetaMethod; +import groovy.lang.Closure; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.commons.lang.ArrayUtils; import org.codehaus.groovy.reflection.CachedClass; import org.codehaus.groovy.reflection.CachedMethod; import org.codehaus.groovy.runtime.metaclass.ReflectionMetaMethod; +import org.springframework.util.ReflectionUtils; /** * @@ -35,19 +38,32 @@ * */ public abstract class BaseApiProvider { - - protected List instanceMethods = new ArrayList(); + private static List EXCLUDED_METHODS = new ArrayList() {{ + add("setMetaClass"); + add("getMetaClass"); + }}; + private static Map METHOD_CLOSURES = new HashMap() {{ + put("setProperty", 2); + put("getProperty", 1); + put("invokeMethod", 2); + put("methodMissing", 2); + put("propertyMissing", 1); + + }}; + @SuppressWarnings("rawtypes") + protected List instanceMethods = new ArrayList(); protected List staticMethods = new ArrayList(); + @SuppressWarnings("unchecked") public void addApi(final Object apiInstance) { if(apiInstance != null) { Class currentClass = apiInstance.getClass(); while(currentClass != Object.class) { final Method[] declaredMethods = currentClass.getDeclaredMethods(); - for (Method method : declaredMethods) { + for (final Method method : declaredMethods) { final int modifiers = method.getModifiers(); - if(Modifier.isPublic(modifiers) && !Modifier.isAbstract(modifiers)) { + if(isNotExcluded(method, modifiers)) { if(Modifier.isStatic(modifiers)) { staticMethods.add(method); } @@ -67,7 +83,8 @@ public CachedClass[] getParameterTypes() { else return paramTypes; } - }); + }); + } } } @@ -75,6 +92,18 @@ public CachedClass[] getParameterTypes() { } } } + + private boolean isNotExcluded(Method method, final int modifiers) { + final String name = method.getName(); + + if(EXCLUDED_METHODS.contains(name)) return false; + + Integer parameterCount = METHOD_CLOSURES.get(name); + return Modifier.isPublic(modifiers) && + !Modifier.isAbstract(modifiers) && + !name.contains("$") && + !(parameterCount != null && (parameterCount == method.getParameterTypes().length)); + } } diff --git a/src/java/org/codehaus/groovy/grails/commons/metaclass/MetaClassEnhancer.groovy b/src/java/org/codehaus/groovy/grails/commons/metaclass/MetaClassEnhancer.groovy index 44270fc4f4f..61f1df74641 100644 --- a/src/java/org/codehaus/groovy/grails/commons/metaclass/MetaClassEnhancer.groovy +++ b/src/java/org/codehaus/groovy/grails/commons/metaclass/MetaClassEnhancer.groovy @@ -18,7 +18,9 @@ package org.codehaus.groovy.grails.commons.metaclass import java.lang.reflect.Method; -import groovy.lang.ExpandoMetaClass; +import org.codehaus.groovy.runtime.MethodClosure +import org.codehaus.groovy.runtime.metaclass.ReflectionMetaMethod; + import groovy.lang.MetaClass; import groovy.lang.MetaMethod; @@ -32,8 +34,9 @@ import groovy.lang.MetaMethod; class MetaClassEnhancer extends BaseApiProvider { public void enhance(MetaClass metaClass) { - for (MetaMethod method : instanceMethods) { - metaClass.registerInstanceMethod(method) + for (method in instanceMethods) { + if(method instanceof ReflectionMetaMethod) + metaClass.registerInstanceMethod(method) } for (Method method : staticMethods) { diff --git a/src/java/org/codehaus/groovy/grails/plugins/web/ServletsGrailsPlugin.groovy b/src/java/org/codehaus/groovy/grails/plugins/web/ServletsGrailsPlugin.groovy index 8c01f443c21..750f9e3a6a9 100644 --- a/src/java/org/codehaus/groovy/grails/plugins/web/ServletsGrailsPlugin.groovy +++ b/src/java/org/codehaus/groovy/grails/plugins/web/ServletsGrailsPlugin.groovy @@ -23,7 +23,6 @@ import javax.servlet.http.HttpServletResponse import javax.servlet.http.HttpSession import org.codehaus.groovy.grails.commons.metaclass.MetaClassEnhancer; -import org.codehaus.groovy.grails.plugins.web.api.AttributeAccessor; import org.codehaus.groovy.grails.plugins.web.api.ServletRequestApi; import org.springframework.web.util.WebUtils @@ -41,18 +40,62 @@ class ServletsGrailsPlugin { def dependsOn = [core:version] private MetaClassEnhancer requestEnhancer - private MetaClassEnhancer attrEnhancer + public ServletsGrailsPlugin() { this.requestEnhancer = new MetaClassEnhancer() requestEnhancer.addApi new ServletRequestApi() - this.attrEnhancer = new MetaClassEnhancer() - attrEnhancer.addApi new AttributeAccessor() - } def doWithDynamicMethods = { ctx -> + def getAttributeClosure = { String name -> + def mp = delegate.class.metaClass.getMetaProperty(name) + return mp ? mp.getProperty(delegate) : delegate.getAttribute(name) + } + + def setAttributeClosure = { String name, value -> + def mp = delegate.class.metaClass.getMetaProperty(name) + if (mp) { + mp.setProperty(delegate, value) + } + else { + delegate.setAttribute(name, value) + } + } + + def getAttributeSubscript = { String key -> + delegate.getAttribute(key) + } + def setAttributeSubScript = { String key, Object val -> + delegate.setAttribute(key, val) + } + // enables acces to servlet context with servletContext.foo syntax + ServletContext.metaClass.getProperty = getAttributeClosure + ServletContext.metaClass.setProperty = setAttributeClosure + ServletContext.metaClass.getAt = getAttributeSubscript + ServletContext.metaClass.putAt = setAttributeSubScript + + // enables access to session attributes using session.foo syntax + HttpSession.metaClass.getProperty = getAttributeClosure + HttpSession.metaClass.setProperty = setAttributeClosure + // enables access to session attributes with session["foo"] syntax + HttpSession.metaClass.getAt = getAttributeSubscript + // enables setting of session attributes with session["foo"] = "bar" syntax + HttpSession.metaClass.putAt = setAttributeSubScript + // enables access to request attributes with request["foo"] syntax + HttpServletRequest.metaClass.getAt = { String key -> + delegate.getAttribute(key) + } + // enables setting of request attributes with request["foo"] = "bar" syntax + HttpServletRequest.metaClass.putAt = { String key, Object val -> + delegate.setAttribute(key, val) + } + // enables access to request attributes using property syntax + HttpServletRequest.metaClass.getProperty = getAttributeClosure + HttpServletRequest.metaClass.setProperty = setAttributeClosure + requestEnhancer.enhance HttpServletRequest.metaClass - attrEnhancer.enhanceAll( [ServletContext.metaClass, HttpSession.metaClass] ) + + // allows the syntax response << "foo" HttpServletResponse.metaClass.leftShift = { Object o -> delegate.writer << o diff --git a/src/java/org/codehaus/groovy/grails/plugins/web/api/AttributeAccessor.groovy b/src/java/org/codehaus/groovy/grails/plugins/web/api/AttributeAccessor.groovy deleted file mode 100644 index c66c753737d..00000000000 --- a/src/java/org/codehaus/groovy/grails/plugins/web/api/AttributeAccessor.groovy +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.codehaus.groovy.grails.plugins.web.api - -/** -* API for classes that access attributes like property access (eg. request.getAttribute('foo') becomes request.foo) -* -* @author Graeme Rocher -* @since 1.4 -* -*/ - -class AttributeAccessor { - - def getProperty(instance, String name) { - def mp = instance.class.metaClass.getMetaProperty(name) - return mp ? mp.getProperty(instance) : instance.getAttribute(name) - } - - void setProperty(instance, String name, value) { - def mp = instance.class.metaClass.getMetaProperty(name) - if (mp) { - mp.setProperty(instance, value) - } - else { - instance.setAttribute(name, value) - } - } - - def getAt(instance, String name) { - getProperty(instance, name) - } - - def putAt(instance, String name, value) { - setProperty(instance, name, value) - } -} diff --git a/src/java/org/codehaus/groovy/grails/plugins/web/api/ServletRequestApi.groovy b/src/java/org/codehaus/groovy/grails/plugins/web/api/ServletRequestApi.groovy index b5dac6a66f5..87121b71468 100644 --- a/src/java/org/codehaus/groovy/grails/plugins/web/api/ServletRequestApi.groovy +++ b/src/java/org/codehaus/groovy/grails/plugins/web/api/ServletRequestApi.groovy @@ -28,7 +28,7 @@ import javax.servlet.http.HttpServletRequest; * */ -class ServletRequestApi extends AttributeAccessor{ +class ServletRequestApi { /** * @return retrieve the forwardURI for the request diff --git a/src/test/org/codehaus/groovy/grails/plugins/web/ServletsGrailsPluginTests.groovy b/src/test/org/codehaus/groovy/grails/plugins/web/ServletsGrailsPluginTests.groovy index a31b4f4190b..de6a895e680 100644 --- a/src/test/org/codehaus/groovy/grails/plugins/web/ServletsGrailsPluginTests.groovy +++ b/src/test/org/codehaus/groovy/grails/plugins/web/ServletsGrailsPluginTests.groovy @@ -1,10 +1,16 @@ package org.codehaus.groovy.grails.plugins.web +import groovy.lang.GroovySystem; + import org.codehaus.groovy.grails.commons.test.* import org.codehaus.groovy.grails.commons.metaclass.* import org.codehaus.groovy.grails.commons.spring.* import org.springframework.mock.web.* + +import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpSession; + import org.springframework.web.util.* class ServletsGrailsPluginTests extends AbstractGrailsPluginTests { @@ -37,7 +43,9 @@ class ServletsGrailsPluginTests extends AbstractGrailsPluginTests { void testServletContextObject() { def context = new MockServletContext() - context["foo"] = "bar" + println context.metaClass.getMetaMethod("getProperty") + println ServletContext.metaClass.getMetaMethod("getProperty") + context["foo"] = "bar" assertEquals "bar", context["foo"] context.foo = "fred" @@ -49,7 +57,9 @@ class ServletsGrailsPluginTests extends AbstractGrailsPluginTests { void testHttpSessionObject() { def session = new MockHttpSession() - assert session.creationTime + def httpSessionMetaClass = GroovySystem.getMetaClassRegistry().getMetaClass(HttpSession) + def metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(session.getClass()) + assert session.getProperty("creationTime") session["foo"] = "bar" assertEquals "bar", session["foo"] diff --git a/src/test/org/codehaus/groovy/grails/resolve/IvyDependencyManagerTests.groovy b/src/test/org/codehaus/groovy/grails/resolve/IvyDependencyManagerTests.groovy index 7d1cdc9909e..3548d0334a5 100644 --- a/src/test/org/codehaus/groovy/grails/resolve/IvyDependencyManagerTests.groovy +++ b/src/test/org/codehaus/groovy/grails/resolve/IvyDependencyManagerTests.groovy @@ -473,11 +473,11 @@ class IvyDependencyManagerTests extends GroovyTestCase { def grailsVersion = getCurrentGrailsVersion() manager.parseDependencies(IvyDependencyManager.getDefaultDependencies(grailsVersion)) - assertEquals 54, manager.listDependencies('runtime').size() - assertEquals 57, manager.listDependencies('test').size() - assertEquals 20, manager.listDependencies('build').size() + assertEquals 56, manager.listDependencies('runtime').size() + assertEquals 59, manager.listDependencies('test').size() + assertEquals 19, manager.listDependencies('build').size() assertEquals 2, manager.listDependencies('provided').size() - assertEquals 23, manager.listDependencies('docs').size() + assertEquals 22, manager.listDependencies('docs').size() // This should be a functional test since it relies on the Grails // JAR files being built. It also runs Ivy, which isn't ideal @@ -501,9 +501,9 @@ class IvyDependencyManagerTests extends GroovyTestCase { assertEquals 0, manager.listDependencies('runtime').size() assertEquals 3, manager.listDependencies('test').size() - assertEquals 20, manager.listDependencies('build').size() - assertEquals 56, manager.listDependencies('provided').size() - assertEquals 23, manager.listDependencies('docs').size() + assertEquals 19, manager.listDependencies('build').size() + assertEquals 58, manager.listDependencies('provided').size() + assertEquals 22, manager.listDependencies('docs').size() manager = new IvyDependencyManager("project", "0.1",settings) defaultDependencyClosure = IvyDependencyManager.getDefaultDependencies(grailsVersion) @@ -513,11 +513,11 @@ class IvyDependencyManagerTests extends GroovyTestCase { defaultDependencyClosure() } - assertEquals 54, manager.listDependencies('runtime').size() - assertEquals 57, manager.listDependencies('test').size() - assertEquals 20, manager.listDependencies('build').size() + assertEquals 56, manager.listDependencies('runtime').size() + assertEquals 59, manager.listDependencies('test').size() + assertEquals 19, manager.listDependencies('build').size() assertEquals 2, manager.listDependencies('provided').size() - assertEquals 23, manager.listDependencies('docs').size() + assertEquals 22, manager.listDependencies('docs').size() } def getCurrentGrailsVersion() {