2009-10-23 9 views
8

Na przykład, jeśli wykonać Groovy skrypt, który modyfikuje ciąg meta klasę, dodając foo() metodaJak cofnąć zmiany w klasie meta po uruchomieniu GroovyShell?

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

gdy tworzę nową powłokę potem i wykonać go, zmiany są nadal tam

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

Czy istnieje sposób na cofnięcie wszystkich zmian w klasie meta po uruchomieniu GroovyShell? Próbowałem

shell1.getClassLoader().clearCache(); 

i

shell1.resetLoadedClasses(); 

ale nie wprowadzić zmiany.

+0

Czy mogę to zrobić z niektórymi zakłóceniami klasy? – cretzel

Odpowiedz

11

Można użyć

GroovySystem.metaClassRegistry.removeMetaClass(String.class); 

cofnąć wszystkie zmiany wprowadzone do łańcucha meta klasy.

Alternatywnie można zmienić tylko klasę meta pewnej instancji String, w związku z czym nie wpłynie to na wszystkie wystąpienia ciągu znaków.

+1

Dzięki. Ale co, jeśli nie wiem, jakie zmiany meta klasy zostały dokonane. Pomyśl o aplikacji takiej jak Groovy Web Console, w której różni użytkownicy wykonują skrypty Groovy. Chcę, aby ci użytkownicy nie ingerowali. – cretzel

+0

Zobacz moją odpowiedź poniżej, która rozwiązuje twój problem polegający na tym, że nie wiesz, które metaclasy się zmieniły. –

0

Zdaję sobie sprawę, że jest to nieco starsze pytanie, ale jest to pierwszy wynik w Google, gdy szukałem dokładnie tego samego problemu.

Rozwiązaniem, które wybrałem było umieszczenie groovy w nowym programie ładującym klasy (przy użyciu Plexus-classworlds), więc po zakończeniu skryptu program ładujący klasy jest usuwany (a więc wszelkie zmiany w metaclass są również usuwane).

+0

Czy masz przykład kodu? –

+0

@JohnMercier nie pomógł powyżej mojej odpowiedzi? –

2

Można również użyć narzędzia MetaClassRegistryCleaner.

Przedtem pewne zmiany metaklasa można zrobić

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

A kiedy chcesz zresetować zmiany metaklasa do stanu byli wcześniej.

Można zrobić

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

W ten sposób można przywrócić wszystkie zmiany metaklasa dokonane w czasie trwania.

Powiązane problemy