Как отменить изменения мета-классов после выполнения 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), поэтому, когда скрипт завершится, загрузчик классов будет удален (и поэтому любые изменения в метаклассе также будут удалены).