/* * Copyright (c) 2006 Rogério Liesenfeld * This file is subject to the terms of the MIT license (see LICENSE.txt). */ package mockit.internal; import java.lang.instrument.*; import java.util.*; import java.util.Map.*; import javax.annotation.*; import mockit.internal.startup.*; import mockit.internal.state.*; import mockit.internal.util.*; public final class RedefinitionEngine { @Nonnull private Class<?> realClass; public RedefinitionEngine() {} public RedefinitionEngine(@Nonnull Class<?> realClass) { this.realClass = realClass; } public static void redefineClasses(@Nonnull ClassDefinition... definitions) { Startup.redefineMethods(definitions); MockFixture mockFixture = TestRun.mockFixture(); for (ClassDefinition def : definitions) { mockFixture.addRedefinedClass(def.getDefinitionClass(), def.getDefinitionClassFile()); } } public void redefineMethodsWhileRegisteringTheClass(@Nonnull byte[] modifiedClassfile) { redefineMethods(modifiedClassfile); addToMapOfRedefinedClasses(null, modifiedClassfile); TestRun.mockFixture().registerMockedClass(realClass); } private void addToMapOfRedefinedClasses(@Nullable String mockClassInternalName, @Nonnull byte[] modifiedClassfile) { TestRun.mockFixture().addRedefinedClass(mockClassInternalName, realClass, modifiedClassfile); } private void redefineMethods(@Nonnull byte[] modifiedClassfile) { Startup.redefineMethods(realClass, modifiedClassfile); } public void redefineMethods(@Nonnull Map<Class<?>, byte[]> modifiedClassfiles) { ClassDefinition[] classDefs = new ClassDefinition[modifiedClassfiles.size()]; int i = 0; for (Entry<Class<?>, byte[]> classAndBytecode : modifiedClassfiles.entrySet()) { realClass = classAndBytecode.getKey(); byte[] modifiedClassfile = classAndBytecode.getValue(); classDefs[i++] = new ClassDefinition(realClass, modifiedClassfile); addToMapOfRedefinedClasses(null, modifiedClassfile); } Startup.redefineMethods(classDefs); } public void restoreDefinition(@Nonnull Class<?> aClass, @Nullable byte[] previousDefinition) { if (previousDefinition == null) { restoreOriginalDefinition(aClass); } else { restoreToDefinition(aClass, previousDefinition); } } public void restoreOriginalDefinition(@Nonnull Class<?> aClass) { if (!GeneratedClasses.isGeneratedImplementationClass(aClass)) { realClass = aClass; byte[] realClassFile = ClassFile.createReaderOrGetFromCache(aClass).b; redefineMethods(realClassFile); } } public void restoreToDefinition(@Nonnull Class<?> aClass, @Nonnull byte[] definitionToRestore) { realClass = aClass; redefineMethods(definitionToRestore); } }