interfacegroovymissingmethod

How to make a Groovy class looks as Map to Java code without implementing Map interface explicitly


I want to implement a custom Map-like class where most of the functionality is delegated to a nested Map delegate instance. And, I want this class to look like a Map to a "true" Java classes. Therefore I tried to do the following:

class ConfigurationMap implements Map {
    def inner = [:]

    def methodMissing(String methodName,methodArgs) {
        return inner.invokeMethod(methodName,methodArgs)
    }

    // my methods here
    ...

And of course, this doesn't work :-( Groovy demands the class to implement Map interface methods, despite at runtime they would be handled by missedMissing(). If I remove the implements clause:

class ConfigurationMap {
    def inner = [:]

    def methodMissing(String methodName,methodArgs) {
        return inner.invokeMethod(methodName,methodArgs)
    }

it works for Groovy (i.e. the instance truly behaves like a Map), but I cannot use it as a Map from Java code:

ConfigurationMap cm = ConfigParser.parseConfig("foo.cfg");
assertEquals(0,cm.size()); // size() method is not defined :-(

And advice to my on how can I keep my class short (i.e. do not implement Map explicitly) and still make the class look as Map to Java?


Solution

  • I think if you use the @Delegate annotation, that the compiled bytecode will work properly from Java.

    class ConfigurationMap implements Map {
        @Delegate Map inner = [:]
    
        def myMethod() {
            return true
        }
    }
    
    ConfigurationMap cm = new ConfigurationMap()
    cm.foo = "bar"
    assert "bar" == cm.foo
    assert true == cm.myMethod()