home | career | drupal | java | mac | mysql | perl | scala | uml | unix

Groovy example source code file (ExpandoMetaClassTest.groovy)

This example Groovy source code file (ExpandoMetaClassTest.groovy) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Groovy tags/keywords

circle, circle, emct_class, emct_class, emct_getproperty, emct_superclass, missingmethodexception, missingmethodexception, object, runtimeexception, script, should, string, string

The Groovy ExpandoMetaClassTest.groovy source code

/*
 * Copyright 2004-2009 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 groovy.lang

/**
 * @author Graeme Rocher
 */
class ExpandoMetaClassTest extends GroovyTestCase {

    void testMethodsAfterAddingNewMethod() {
        EMCT_Class.metaClass.newMethod = {-> "foo" }

        def methods = EMCT_Class.metaClass.methods.findAll {it.name == "newMethod"}
        assert methods
        assertEquals 1, methods.size()

        EMCT_Class.metaClass.newMethod = {-> "foo" }

        methods = EMCT_Class.metaClass.methods.findAll {it.name == "newMethod"}
        assert methods
        assertEquals 1, methods.size()
    }

    void testPropertiesAfterAddingProperty() {
        EMCT_Class.metaClass.getNewProp = {-> "foo" }

        def props = EMCT_Class.metaClass.properties.findAll {it.name == "newProp"}
        assert props
        assertEquals 1, props.size()

        EMCT_Class.metaClass.setNewProp = {String txt -> }

        props = EMCT_Class.metaClass.properties.findAll {it.name == "newProp"}
        assert props
        assertEquals 1, props.size()
    }

    void testOverrideStaticMethod() {
        EMCT_Static.metaClass.'static'.f = { "first" }
        assertEquals "first", EMCT_Static.f("")

        EMCT_Static.metaClass.'static'.f = { "second" }
        assertEquals "second", EMCT_Static.f("")
    }


    void testOverrideMethod() {
        EMCT_Static.metaClass.f = { "first" }
        assertEquals "first", new EMCT_Static().f("")

        EMCT_Static.metaClass.f = { "second" }
        assertEquals "second", new EMCT_Static().f("")
    }


    void testStaticBeanStyleProperties() {
        def mc = new ExpandoMetaClass(EMCT_InvokeMethod.class, true, true)
        mc.initialize()
        GroovySystem.metaClassRegistry.setMetaClass(EMCT_InvokeMethod.class, mc)

        mc.'static'.getHello = {-> "bar!"}

        assertEquals "bar!", EMCT_InvokeMethod.hello
    }

    void testOverrideInvokeStaticMethod() {
        def mc = new ExpandoMetaClass(EMCT_InvokeMethod.class, true, true)
        mc.initialize()
        GroovySystem.metaClassRegistry.setMetaClass(EMCT_InvokeMethod.class, mc)

        mc.'static'.invokeMethod = {String methodName, args ->
            def metaMethod = mc.getStaticMetaMethod(methodName, args)
            def result = null
            if (metaMethod) result = metaMethod.invoke(delegate, args)
            else {
                result = "foo!"
            }
            result
        }

        assertEquals "bar!", EMCT_InvokeMethod.myStaticMethod()
        assertEquals "foo!", EMCT_InvokeMethod.dynamicMethod()
    }

    void testOverrideInvokeMethod() {
        def mc = new ExpandoMetaClass(EMCT_InvokeMethod.class, false, true)
        mc.initialize()

        assert mc.hasMetaMethod("invokeMe", [String] as Class[])

        mc.invokeMethod = {String name, args ->
            def mm = delegate.metaClass.getMetaMethod(name, args)
            mm ? mm.invoke(delegate, args) : "bar!!"
        }

        def t = new EMCT_InvokeMethod()
        t.metaClass = mc

        assertEquals "bar!!", t.doStuff()
        assertEquals "Foo!! hello", t.invokeMe("hello")
    }

    void testOverrideSetProperty() {
        def mc = new ExpandoMetaClass(EMCT_GetProperty.class, false, true)
        mc.initialize()

        assert mc.hasMetaProperty("name")

        def testValue = null
        mc.setProperty = {String name, value ->
            def mp = delegate.metaClass.getMetaProperty(name)

            if (mp) {mp.setProperty(delegate, value)} else {testValue = value}
        }

        def t = new EMCT_GetProperty()
        t.metaClass = mc

        t.name = "Bob"
        assertEquals "Bob", t.name

        t.foo = "bar"
        assertEquals "bar", testValue
    }

    void testOverrideGetProperty() {
        def mc = new ExpandoMetaClass(EMCT_GetProperty.class, false, true)
        mc.initialize()

        assert mc.hasMetaProperty("name")

        mc.getProperty = {String name ->
            def mp = delegate.metaClass.getMetaProperty(name)

            mp ? mp.getProperty(delegate) : "foo $name"
        }

        def t = new EMCT_GetProperty()
        t.metaClass = mc

        assertEquals "foo bar", t.getProperty("bar")
        assertEquals "foo bar", t.bar
        assertEquals "Fred", t.getProperty("name")
        assertEquals "Fred", t.name
    }

    void testBooleanGetterWithClosure() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class, false, true)
        metaClass.initialize()
        metaClass.isValid = {-> true}

        def t = new EMCT_Class()
        t.metaClass = metaClass

        assert t.isValid()
        assert t.valid
    }

    void testAllowAdditionOfProperties() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class, false, true)

        metaClass.getOne << {->
            "testme"
        }
        metaClass.initialize()
        try {
            metaClass.getTwo << {->
                "testagain"
            }
        }
        catch (RuntimeException e) {
            fail("Should have allowed addition of new method")
        }

        def t = new EMCT_Class()
        t.metaClass = metaClass

        assertEquals "testme", t.one
        assertEquals "testagain", t.two
    }

    void testAllowAdditionOfMethods() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class, false, true)

        metaClass.myMethod << {->
            "testme"
        }
        metaClass.initialize()
        try {
            metaClass.mySecondMethod << {->
                "testagain"
            }
        }
        catch (RuntimeException e) {
            fail("Should have allowed addition of new method")
        }

        def t = new EMCT_Class()
        t.metaClass = metaClass

        assertEquals "testme", t.myMethod()
        assertEquals "testagain", t.mySecondMethod()
    }

    void testForbiddenAdditionOfMethods() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        metaClass.myMethod << {
            "testme"
        }
        metaClass.initialize()

        def t = new EMCT_Class()

        try {
            metaClass.mySecondMethod << {
                "testagain"
            }
            fail("Should have thrown exception")
        }
        catch (RuntimeException e) {
            // expected
        }
    }

    void testPropertyGetterWithClosure() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        metaClass.getSomething = {-> "testme"}

        metaClass.initialize()

        def t = new EMCT_Class()
        t.metaClass = metaClass

        assertEquals "testme", t.getSomething()
        assertEquals "testme", t.something
    }

    void testPropertySetterWithClosure() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        def testSet = null
        metaClass.setSomething = {String txt -> testSet = txt}

        metaClass.initialize()

        def t = new EMCT_Class()
        t.metaClass = metaClass

        t.something = "testme"
        assertEquals "testme", testSet

        t.setSomething("test2")
        assertEquals "test2", testSet
    }

    void testNewMethodOverloading() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        metaClass.overloadMe << {String txt -> txt} << {Integer i -> i}

        metaClass.initialize()

        def t = new EMCT_Class()
        t.metaClass = metaClass

        assertEquals "test", t.overloadMe("test")
        assertEquals 10, t.overloadMe(10)
    }

    void testOverloadExistingMethodAfterInitialize() {
        def t = new EMCT_Class()

        assertEquals "test", t.doSomething("test")

        def metaClass = new ExpandoMetaClass(EMCT_Class.class, false, true)
        metaClass.initialize()

        metaClass.doSomething = {Integer i -> i + 1}

        t.metaClass = metaClass

        assertEquals "test", t.doSomething("test")
        assertEquals 11, t.doSomething(10)
    }

    void testOverloadExistingMethodBeforeInitialize() {
        def t = new EMCT_Class()

        assertEquals "test", t.doSomething("test")

        def metaClass = new ExpandoMetaClass(EMCT_Class.class, false, true)


        metaClass.doSomething = {Integer i -> i + 1}

        metaClass.initialize()

        t.metaClass = metaClass

        assertEquals "test", t.doSomething("test")
        assertEquals 11, t.doSomething(10)
    }

    void testNewPropertyMethod() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        metaClass.something = "testme"

        metaClass.initialize()

        def t = new EMCT_Class()
        t.metaClass = metaClass

        assertEquals "testme", t.getSomething()
        assertEquals "testme", t.something

        t.something = "test2"
        assertEquals "test2", t.something
        assertEquals "test2", t.getSomething()

        def t2 = new EMCT_Class()
        t2.metaClass = metaClass
        // now check that they're not sharing the same property!
        assertEquals "testme", t2.something
        assertEquals "test2", t.something

        t2.setSomething("test3")

        assertEquals "test3", t2.something
    }

    void testCheckFailOnExisting() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)
        try {
            metaClass.existing << {->
                "should fail. already exists!"
            }
            fail("Should have thrown exception when method already exists")
        }
        catch (Exception e) {
            // expected
        }
    }

    void testCheckFailOnExistingConstructor() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)
        try {
            metaClass.constructor << {->
                "should fail. already exists!"
            }
            fail("Should have thrown exception when method already exists")
        }
        catch (Exception e) {
            // expected
        }
    }

    void testCheckFailOnExistingStaticMethod() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)
        try {
            metaClass.'static'.existingStatic << {->
                "should fail. already exists!"
            }
            fail("Should have thrown exception when method already exists")
        }
        catch (Exception e) {
            // expected
        }
    }

    void testNewStaticMethod() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class, true)

        metaClass.'static'.myStaticMethod << {String txt ->
            "testme"
        }
        metaClass.initialize()

        assertEquals "testme", EMCT_Class.myStaticMethod("blah")
    }

    void testReplaceStaticMethod() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class, true)

        metaClass.'static'.existingStatic = {->
            "testme"
        }
        metaClass.initialize()

        assertEquals "testme", EMCT_Class.existingStatic()

    }

    void testNewZeroArgumentStaticMethod() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class, true)

        metaClass.'static'.myStaticMethod = {->
            "testme"
        }
        metaClass.initialize()

        assertEquals "testme", EMCT_Class.myStaticMethod()
    }

    void testNewInstanceMethod() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        metaClass.myMethod << {
            "testme"
        }
        metaClass.initialize()

        def t = new EMCT_Class()

        t.metaClass = metaClass

        assertEquals "testme", t.myMethod()
    }

    void testNewConstructor() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class, true)

        metaClass.constructor << {String txt ->
            def t = EMCT_Class.class.newInstance()
            t.name = txt
            return t
        }

        metaClass.initialize()

        def t = new EMCT_Class("testme")
        assert t
        assertEquals "testme", t.name

        GroovySystem.metaClassRegistry.removeMetaClass(EMCT_Class.class)
    }

    void testReplaceConstructor() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class, true)

        metaClass.constructor = {->
            "testme"
        }

        metaClass.initialize()

        def t = new EMCT_Class()
        assert t
        assertEquals "testme", t

        GroovySystem.metaClassRegistry.removeMetaClass(EMCT_Class.class)
    }

    void testReplaceInstanceMethod() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        metaClass.existing2 = {Object i ->
            "testme"
        }
        metaClass.initialize()

        def t = new EMCT_Class()
        t.metaClass = metaClass

        def var = 1
        assertEquals "testme", t.existing2(var)
    }

    void testBorrowMethodFromAnotherClass() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        def a = new EMCT_Another()
        metaClass.borrowMe = a.&another
        metaClass.borrowMeToo = a.&noArgs
        metaClass.initialize()

        def t = new EMCT_Class()
        t.metaClass = metaClass

        assertEquals "mine blah!", t.borrowMe("blah")
        assertEquals "mine blah+foo!", t.borrowMe("blah", "foo")
        // GROOVY-1993
        assertEquals "no args here!", t.borrowMeToo()
    }

    void testClosureWithOptionalArgs() {
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        metaClass.withOptional {
            String first, String second = "no param" ->
            "$first + $second"
        }

        def t = new EMCT_Class()
        t.metaClass = metaClass

        assertEquals("blah + no param", t.withOptional("blah"))
        assertEquals("blah + foo", t.withOptional("blah", "foo"))
    }

    void testBorrowByName() {
        println 'testBorrowByName'
        def metaClass = new ExpandoMetaClass(EMCT_Class.class)

        def a = new EMCT_Another()
        metaClass.borrowMe = a.&'another'
        metaClass.borrowMeToo = a.&'noArgs'
        metaClass.initialize()

        def t = new EMCT_Class()
        t.metaClass = metaClass

        assertEquals "mine blah!", t.borrowMe("blah")
        // GROOVY-1993
        assertEquals "no args here!", t.borrowMeToo()
    }

    void testAddIdenticalPropertyToChildAndParent() {
        ExpandoMetaClass.enableGlobally()
        doMethods(EMCT_SuperClass.class)
        doMethods(EMCT_ChildClass.class)

        def child = new EMCT_ChildClass()
        def parent = new EMCT_SuperClass()

        assert parent.errors == null
        parent.errors = [3, 2, 1, 0]
        assert parent.errors.size() == 4

        assert child.errors == null
        child.errors = [1, 2, 3]
        assert child.errors.size() == 3
        ExpandoMetaClass.disableGlobally()
    }

    void testMissingPropertyClosure() {
        assertScript """
            class Circle {
                String prop1 = 'value1'
            }

            ExpandoMetaClass emc = new ExpandoMetaClass(this.class, false)
            emc.methodMissing = {String name, args ->
                throw new MissingMethodException(name, Script, args)
            }
            emc.propertyMissing = {String name ->
                throw new MissingPropertyException(name, Script)
            }
            emc.initialize()
            this.metaClass = emc

            Circle circle = new Circle()
            // closure will try to access prop1 on script, which does not have such
            // a property, thus a MissingPropertyException will be thrown
            // causing the closure code to select the delegate to resolve the property
            Closure cl = {prop1}
            cl.delegate = circle
            assert cl.call()=='value1'
        """
    }

    void testMissingMethodClosure() {
        assertScript """
            class Circle {
                def m1(){1}
            }

            ExpandoMetaClass emc = new ExpandoMetaClass(this.class, false)
            emc.methodMissing = {String name, args ->
                throw new MissingMethodException(name, Script, args)
            }
            emc.propertyMissing = {String name ->
                throw new MissingPropertyException(name, Script)
            }
            emc.initialize()
           this.metaClass = emc

            Circle circle = new Circle()
            // closure will try to call m1 on script, which does not have such
            // a method, thus a MissingMethodException will be thrown
            // causing the closure code to select the delegate to call the method
            Closure cl = {m1()}
            cl.delegate = circle
            assert cl.call() == 1
        """
    }

    void testMissingMethodExceptionThrownFromMissingMethod() {
        assertScript """
           class Circle {
                def invokeMethodInvocations = 0
                def invokeMethod(String name, Object[] args) {
                    invokeMethodInvocations++;
                }
                def callNonExistingMethod() {
                  m1()
                }
            }

            ExpandoMetaClass emc = new ExpandoMetaClass(Circle.class, false)
            def exception = new MissingMethodException("m1", Circle, null)
            emc.methodMissing = {String name, args ->
                throw exception
            }
            emc.initialize()

            Circle circle = new Circle()
            circle.metaClass = emc

            assert circle.invokeMethodInvocations == 0
            def gotException=true
            try {
               circle.callNonExistingMethod()
               gotException=false
            } catch (MissingMethodException mme) {
               gotException=true
               assert mme == exception
            }
            assert gotException,"MissingMethodException expected, but got something else"

            assert circle.invokeMethodInvocations == 0
            gotException=true
            try {
               circle.m1()
               gotException=false
            } catch (MissingMethodException mme) {
               assert mme == exception
            }
            assert gotException,"MissingMethodException expected, but got something else"
        """
    }

    def doMethods(clazz) {
        def metaClass = clazz.metaClass

        metaClass.setErrors = {errors ->
            thingo = errors
        }

        metaClass.getErrors = {->
            return thingo
        }
    }

    void testGetProperty() {
        def x = new EMCT_SuperClass()
        def mc = x.metaClass
        mc.getProperty = {String name ->
            MetaProperty mp = mc.getMetaProperty(name)
            if (mp)
                mp.getProperty(delegate)
            else {
                if (thingo) {
                    thingo."$name"
                }
                else {
                    if (application) {
                        "non-null application"
                    }
                    else {
                        String methodName = "get${name[0].toUpperCase()}${name.substring(1)}"
                        mc."$methodName" = {
                            -> "$name"
                        }
                        delegate."$methodName"()
                    }
                }
            }
        }

        Map map = ["prop": "none"]
        x.thingo = map
        assertEquals map, x.thingo
        assertEquals("none", x.prop)
        x.thingo = null
        application = new Object()
        assertEquals("non-null application", x.prop)
        application = null
        assertEquals("prop", x.prop)
        application = new Object()
        assertEquals("prop", x.prop)
    }

    def application

    void testWithNull() {
        EMCT_SuperClass.metaClass = null
        ExpandoMetaClass.enableGlobally()
        def x = new EMCT_SuperClass()
        def mc = x.metaClass

        def request = new Object()
        request.metaClass {
            getFormat {
                -> "js"
            }
        }

        mc.render = {String txt ->
            txt
        }

        assertEquals("js", x.render(request.format))
        ExpandoMetaClass.disableGlobally()
    }

    void testInterfaceWithGetProperty() {
        EMCT_Implemented.metaClass.getProperty = {String name ->
            return "META " + delegate.class.metaClass.getMetaProperty(name).getProperty(delegate)
        }
        EMCT_InterfaceWithFormat.metaClass.getFormat = {
            -> "js"
        }
        def x = new EMCT_Implemented()
        assertEquals "META js", x.format
    }

    void testPickMethodForVarg() {
       // as of 1.6 a metaClass is often the HandleMetaclass, which delegates
       // methods to an underlaying meta class. hasMethod is a Method on EMC
       // that takes a Class[] vargs argument as last part. If that part is not
       // given, then hasMetaMethod will still work, but the code actually
       // invoking the method in EMC.invokeMehod(String,Object) has to correct the
       // arguments.
       assert "".metaClass.pickMethod("trim")
    }
    
    void testEMCMetaClassProperty() {
        // GROOVY-2516
        try {
            assert ExpandoMetaClass.class.metaClass instanceof MetaClass
        } finally {
            GroovySystem.metaClassRegistry.removeMetaClass(ExpandoMetaClass.class)
        }
    }
    
    void testDynamicAddedMethodWithGStringCall() {
        // GROOVY-4691
        assertScript """
          class A {
            def bar(x) {
              return {this."\$x"()}
            }
          }
          try {
            A.metaClass.foo = {->1}
            A.metaClass.methodMissing = { method, args -> 2}
          
            def a = new A()
            assert a.bar("foo")() == 1
            assert a.x() == 2
          } finally {
            GroovySystem.metaClassRegistry.removeMetaClass(A);
          }
        """
    }
}

interface EMCT_InterfaceWithFormat {

}

class EMCT_Implemented implements EMCT_InterfaceWithFormat {

}

class EMCT_SuperClass {
    def thingo
}

class EMCT_ChildClass extends EMCT_SuperClass {

}

class EMCT_InvokeMethod {
    def invokeMe(String boo) {"Foo!! $boo"}

    static myStaticMethod() {"bar!"}
}

class EMCT_GetProperty {
    String name = "Fred"
}

class EMCT_Class {
    String name

    def existing2(obj) {
        "hello2!"
    }

    def existing() {
        "hello!"
    }

    def doSomething(Object txt) {txt}

    static existingStatic() {
        "I exist"
    }
}

class EMCT_Another {
    def another(txt, additional = "") {
        "mine ${txt}${additional ? '+' + additional : ''}!"
    }

    def noArgs() {
        "no args here!"
    }
}

class EMCT_Child extends EMCT_Class {
    def aChildMethod() {
        "hello children"
    }
}

class EMCT_Static {}

Other Groovy examples (source code examples)

Here is a short list of links related to this Groovy ExpandoMetaClassTest.groovy source code file:

new blog posts

 

Copyright 1998-2013 Alvin Alexander, alvinalexander.com
All Rights Reserved.