执行 GroovyShell 后如何撤消元类更改?

问题描述 投票:0回答:4

例如,如果我执行 Groovy 脚本,该脚本修改 String 元类,添加方法 foo()

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

当我之后创建一个新的 shell 并执行它时,更改仍然存在

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

有没有办法在执行 GroovyShell 后撤消所有元类更改?我试过了

shell1.getClassLoader().clearCache();

shell1.resetLoadedClasses();

但这并没有带来改变。

groovy metaprogramming
4个回答
12
投票

你可以使用

GroovySystem.metaClassRegistry.removeMetaClass(String.class);

恢复对 String 元类所做的所有更改。

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


3
投票

您也可以使用 MetaClassRegistryCleaner。

在进行一些元类更改之前,您可以这样做

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

当您想要将元类更改重置为之前的状态时。

你可以做

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

通过这种方式,您可以重置在此期间所做的所有元类更改。


1
投票

我意识到这是一个有点老的问题,但这是我在搜索完全相同的问题时在 Google 上的第一个结果。

我选择的解决方案是将 groovy 放入新的类加载器中(通过使用 plexus-classworlds),因此当脚本完成时,类加载器将被释放(因此对元类的任何更改也会被释放)。


0
投票

这是相关的,但更关注 Groovy 代码,而不是 shell。我还没有在那里尝试过,但至少在代码库中

您可以将其设置为空 如果你正在做单元测试,那么你有一个@Before和@After,你可以在方便的地方进行,我会推荐@After

// how you modify a method, notice args types must be the same but you can also only do an array if you are not going to use it

ClasName.metaClass.nameOfMethod{String arg1, Boolean arg2, String arg3 = "default" ->
  println("Inside metaclass")
}



@After
void cleanUp()
{
   ClasName.metaClass = null
}
© www.soinside.com 2019 - 2024. All rights reserved.