2015-09-02 2 views
1

У меня есть следующий класс, который расширяет класс Object, но добавленный метод здесь не может быть доступен подклассами любого объекта. Есть ли обходной путь или ограничение Groovy мета-программирования ограничения/ограничения?Добавленный метод Groovy Meta-Programming недоступен в подклассе

package groovy.runtime.metaclass.java.lang; 

class ObjectMetaClass extends DelegatingMetaClass { 
    static { 
     Object.metaClass.enableGlobally(); 
    } 

    ObjectMetaClass(MetaClass meta) { 
     super(meta); 
     meta.enableGlobally(); 
    } 

    Object invokeMethod(Object object, 
         String method, 
         Object[] arguments) { 
     if (method == 'bar') { 
      bar(*arguments); 
     } else { 
      super.invokeMethod object, method, arguments 
     } 
    } 

    Object bar(config, app) { 
     println("... ObjectMetaClass.bar(${config}, ${app})"); 
    } 
} 

в тестировании сценария:

o = new Object(); 
o.bar("profile.properties", "meta-app"); // works 

1.bar("profile.properties", "integer-app"); // does not works 
"aString".bar("profile.properties", "string-app"); // does not works 

ответ

2

У вас есть по крайней мере пару ключей: ExpandoMetaClass и Categories.

С ExpandoMetaClass

Object.metaClass.bar = {config, app -> 
    "... Object.bar(${config}, ${app})" 
} 

o = new Object(); 

assert o.bar("profile.properties", "meta-app") == '... Object.bar(profile.properties, meta-app)' 
assert 1.bar("profile.properties", "integer-app") == '... Object.bar(profile.properties, integer-app)' 
assert "aString".bar("profile.properties", "string-app") == '... Object.bar(profile.properties, string-app)' 

С Категория

class BarCategory { 
    static Object bar(Object self, config, app) { 
     "... Object.bar(${config}, ${app})" 
    } 
} 

use(BarCategory) { 
    o = new Object(); 

    assert o.bar("profile.properties", "meta-app") == '... Object.bar(profile.properties, meta-app)' 
    assert 1.bar("profile.properties", "integer-app") == '... Object.bar(profile.properties, integer-app)' 
    assert "aString".bar("profile.properties", "string-app") == '... Object.bar(profile.properties, string-app)' 
} 

o = new Object(); 

try { 
    o.bar("profile.properties", "meta-app") 
    assert false, 'You should not see this' 
} catch (MissingMethodException) {} 

try { 
    1.bar("profile.properties", "integer-app") 
    assert false, 'You should not see this' 
} catch (MissingMethodException) {} 

try { 
    "aString".bar("profile.properties", "string-app") 
    assert false, 'You should not see this' 
} catch (MissingMethodException) {} 

с категорией вы можете контролировать объем метода bar().

+0

Есть ли способ разместить Object.metaClass.bar = {..} где-нибудь, где он будет автоматически загружен, чтобы он не появлялся в каждом скрипте? Благодаря! Категория тоже отличная, но я попытался свести к минимуму необходимость изменения существующих скриптов, если это возможно. Опять же, спасибо –

+0

Помимо статического инициализатора класса (который не будет работать в вашем случае), я не знаю, как автоматически загружать метапрограммирование. Я считаю, что есть два пути. Один из них я не мог найти в данный момент, но другой использует категорию, которая автоматически загружается: http://docs.groovy-lang.org/docs/groovy-latest/html/documentation/#_extension_modules –