2009-10-23 55 views
8

例如,如果我执行Groovy脚本,其修改字符串的元类,添加一个方法foo()如何在执行GroovyShell后撤消元类更改?

GroovyShell shell1 = new GroovyShell(); 
shell1.evaluate("String.metaClass.foo = {-> delegate.toUpperCase()}"); 

当我创建之后,一个新的外壳,并执行它,这些变化仍然存在

GroovyShell shell2 = new GroovyShell(); 
Object result = shell2.evaluate("'a'.foo()"); 

有没有办法在执行GroovyShell后取消所有元类更改?我试图

shell1.getClassLoader().clearCache(); 

shell1.resetLoadedClasses(); 

但这并没有做出改变。

+0

我可以用一些类加载器搞定吗? – cretzel 2009-11-13 08:14:24

回答

11

您可以使用

GroovySystem.metaClassRegistry.removeMetaClass(String.class); 

恢复到字符串元类的所有更改。

或者,您只能更改某个String实例的元类,因此并非所有String实例都会受到影响。

+1

谢谢。但是,如果我不知道什么元类更改已经完成了。想想像Groovy Web控制台这样的应用程序,其中不同的用户执行Groovy脚本。我希望这些用户不要干预。 – cretzel 2009-11-04 12:53:20

+0

看到我的答案在下面,它解决了你不知道哪些元类已经改变的问题。 – 2016-02-12 14:29:33

0

我意识到这是一个稍微老的问题,但这是Google在搜索完全相同的问题时的第一个结果。我选择的解决方案是将groovy放到一个新的类加载器中(通过使用plexus-classworlds),所以当脚本完成时,类加载器被放置(以及对元类的任何改变也被处置)。

+0

你有这样的代码示例吗? – 2015-04-23 13:54:36

+0

@JohnMercier没有我的回答上面的帮助? – 2016-04-21 05:21:38

2

你也可以使用MetaClassRegistryCleaner。

之前做一些变化元类,你可以做

MetaClassRegistryCleaner registryCleaner = MetaClassRegistryCleaner.createAndRegister() 
GroovySystem.metaClassRegistry.addMetaClassRegistryChangeEventListener(registryCleaner) 

而且当你要重置元类的变化,他们是较早的状态。

你可以做

registryCleaner.clean() 
GroovySystem.metaClassRegistry.removeMetaClassRegistryChangeEventListener(registryCleaner) 

这样,您就可以将所有的时间期间所做的元类的变化。