Как отменить изменения мета-классов после выполнения GroovyShell?

Например, если я выполняю скрипт Groovy, который изменяет мета-класс String, добавляя метод foo()

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();

но это не изменило.

3 ответа

Решение

Ты можешь использовать

GroovySystem.metaClassRegistry.removeMetaClass(String.class);

отменить все изменения, внесенные в мета-класс String.

В качестве альтернативы вы можете изменить только мета-класс определенного экземпляра String, таким образом, не все экземпляры String будут затронуты.

Вы также можете использовать MetaClassRegistryCleaner.

Прежде чем делать какие-либо изменения метакласса, вы можете сделать

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

И когда вы хотите сбросить метакласс, изменения в состояние, в котором они были ранее.

Ты можешь сделать

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

Таким образом, вы можете сбросить все изменения метакласса, сделанные за время действия.

Я понимаю, что это несколько более старый вопрос, но это первый результат в Google, когда я искал точно такую ​​же проблему.

Решение, которое я выбрал, состояло в том, чтобы вставить groovy в новый загрузчик классов (используя plexus-classworlds), поэтому, когда скрипт завершится, загрузчик классов будет удален (и поэтому любые изменения в метаклассе также будут удалены).

Другие вопросы по тегам