Backend Development 7 min read

Using Groovy MetaClass to Dynamically Add Methods and Properties to Classes and Objects

This article demonstrates how Groovy's MetaClass can be used at runtime to add object methods, static methods, and properties to classes, and includes a complete Spock unit‑test example that verifies dynamic behavior with detailed code snippets and console output.

FunTester
FunTester
FunTester
Using Groovy MetaClass to Dynamically Add Methods and Properties to Classes and Objects

During a recent study session the author discovered that, contrary to the common belief that Java and Groovy classes have fixed members, Groovy's groovy.lang.MetaClass allows dynamic addition of methods and properties at runtime.

Adding Object Methods

The simplified syntax is object.metaClass.object_method = { closure } . Example:

def funTester = new FunTester()
funTester.metaClass.test = {
    logger.info("我是测试方法:{}", "test")
}
funTester.test()

Console output shows the custom method being invoked.

Adding Static Methods

The syntax for static methods is object.metaClass.static.object_method = { closure } . Example:

def funTester = new FunTester()
funTester.metaClass.test = {
    logger.info("我是测试方法:{}", "static.test")
}
funTester.test()

Console output confirms the static‑style method execution.

Adding Properties

Properties can be added with funTester.metaClass.setProperty("name", "FunTester") and retrieved via funTester.getProperty("name") :

funTester.metaClass.setProperty("name","FunTester")
logger.info(funTester.getProperty("name"))

The class FunTester itself is an empty placeholder used for these demonstrations.

Spock Unit Test

The article then presents a Spock test suite that exercises the dynamic additions. The test class imports logging, defines shared instances, and contains three feature methods:

"测试动态添加对象方法" verifies that a dynamically added object method returns 12 .

"测试动态添加静态方法" checks a dynamically added static method on the class.

"测试动态添加获取属性" attempts to set and get a dynamic property, demonstrating both a passing and a failing case.

package com.funtest.spock

import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import spock.lang.Shared

class Mop extends spock.lang.Specification {
    @Shared
    private static final Logger logger = LogManager.getLogger(Mop.class);

    def setup() { logger.info("测试方法开始了") }
    def cleanup() { logger.info("测试方法结束了") }
    def setupSpec() { /* dynamic metaClass manipulations */ }
    def cleanupSpec() { logger.info("测试类[${getClass().getName()}]结束了") }

    @Shared def fun = new Mop()

    def "测试动态添加对象方法"() {
        given:
        fun.metaClass.ob_method = { return 12 }
        expect:
        12 == fun.ob_method()
    }

    def "测试动态添加静态方法"() {
        given:
        Mop.metaClass.static.clas_method = { return 12 }
        expect:
        12 == Mop.clas_method()
    }

    def "测试动态添加获取属性"() {
        expect:
        fun.setName(name) == tt
        where:
        name        | tt
        "FunTester"| "FunTester"
        "Have Fun" | "Have Fun"
    }
}

The test run produces console logs, shows one failing assertion for the second data row, and summarizes the overall test results (5 tests, 2 failures).

unit testingdynamic programmingGroovySpockmetaclass
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.