All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mockit.internal.startup.InstrumentationHolder Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking external APIs; JUnit (4 & 5) and TestNG test runners are supported. It also contains an advanced code coverage tool.

There is a newer version: 1.49
Show newest version
/*
 * Copyright (c) 2006 Rogério Liesenfeld
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit.internal.startup;

import java.lang.instrument.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.jar.*;

public final class InstrumentationHolder implements Instrumentation
{
   public static Instrumentation inst;
   private static InstrumentationHolder wrappedInst;
   public static String hostJREClassName;

   @SuppressWarnings("unused")
   public static void agentmain(String agentArgs, Instrumentation instrumentation)
   {
      set(instrumentation, null);
   }

   static void setHostJREClassName(String className)
   {
      hostJREClassName = className;

      Class regularHolderClass = getHolderClassFromSystemClassLoaderIfThisIsCustomClassLoader();

      if (regularHolderClass != null) {
         try {
            Field field = getField(regularHolderClass, "hostJREClassName");
            field.set(null, className);
         }
         catch (IllegalAccessException e) { throw new RuntimeException(e); }
      }
   }

   private static Field getField(Class aClass, String fieldName)
   {
      try { return aClass.getDeclaredField(fieldName); }
      catch (NoSuchFieldException e) { throw new RuntimeException(e); }
   }

   public static InstrumentationHolder get()
   {
      if (inst == null) {
         recoverInstrumentationFromHolderClassInSystemClassLoaderIfAvailable();
      }

      return wrappedInst;
   }

   private static void recoverInstrumentationFromHolderClassInSystemClassLoaderIfAvailable()
   {
      Class regularHolderClass = getHolderClassFromSystemClassLoaderIfThisIsCustomClassLoader();

      if (regularHolderClass != null) {
         inst = readStaticField(regularHolderClass, "inst");

         if (inst != null) {
            hostJREClassName = readStaticField(regularHolderClass, "hostJREClassName");
            invokeClearTransformersFromSystemCL(regularHolderClass);
            wrappedInst = new InstrumentationHolder();
         }
      }
   }

   private static Class getHolderClassFromSystemClassLoaderIfThisIsCustomClassLoader()
   {
      ClassLoader systemCL = ClassLoader.getSystemClassLoader();

      if (InstrumentationHolder.class.getClassLoader() == systemCL) {
         return null;
      }

      throw new UnsupportedOperationException("Attempted to redefine class loaded from custom class loader");
//      try { return Class.forName(InstrumentationHolder.class.getName(), true, systemCL); }
//      catch (ClassNotFoundException e) { return null; }
   }

   private static  T readStaticField(Class aClass, String fieldName)
   {
      Field field = getField(aClass, fieldName);

      try {
         @SuppressWarnings("unchecked") T value = (T) field.get(null);
         return value;
      }
      catch (IllegalAccessException e) { throw new RuntimeException(e); }
   }

   private static void invokeClearTransformersFromSystemCL(Class regularHolderClass)
   {
      try {
         Method method = regularHolderClass.getDeclaredMethod("clearTransformers");
         method.invoke(null);
      }
      catch (NoSuchMethodException e) { throw new RuntimeException(e); }
      catch (IllegalAccessException e) { throw new RuntimeException(e); }
      catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); }
   }

   public static void clearTransformers()
   {
      for (ClassFileTransformer transformer : transformers) {
         inst.removeTransformer(transformer);
      }

      transformers.clear();
   }

   boolean wasRecreated() { return transformers.isEmpty(); }

   static Instrumentation set(Instrumentation instrumentation, String hostJREClassName)
   {
      if (wrappedInst != null) {
         clearTransformers();
      }

      inst = instrumentation;
      wrappedInst = instrumentation == null ? null : new InstrumentationHolder();
      InstrumentationHolder.hostJREClassName = hostJREClassName;
      return wrappedInst;
   }

   public static List transformers;

   private InstrumentationHolder()
   {
      Class regularHolderClass = getHolderClassFromSystemClassLoaderIfThisIsCustomClassLoader();

      if (regularHolderClass == null) {
         transformers = new ArrayList();
      }
      else {
         transformers = readStaticField(regularHolderClass, "transformers");
      }
   }

   @Override
   public void addTransformer(ClassFileTransformer transformer, boolean canRetransform)
   {
      removePreviouslyAddedTransformersOfSameType(transformer);
      inst.addTransformer(transformer, canRetransform);
      transformers.add(transformer);
   }

   @Override
   public void addTransformer(ClassFileTransformer transformer)
   {
      removePreviouslyAddedTransformersOfSameType(transformer);
      inst.addTransformer(transformer);
      transformers.add(transformer);
   }

   private void removePreviouslyAddedTransformersOfSameType(ClassFileTransformer transformer)
   {
      Class transformerClass = transformer.getClass();
      ClassLoader transformerCL = transformerClass.getClassLoader();
      String transformerName = transformerClass.getName();

      for (Iterator itr = transformers.iterator(); itr.hasNext(); ) {
         ClassFileTransformer previouslyAdded = itr.next();
         Class previousTransformerClass = previouslyAdded.getClass();

         if (
            previousTransformerClass.getClassLoader() != transformerCL &&
            previousTransformerClass.getName().equals(transformerName)
         ) {
            inst.removeTransformer(previouslyAdded);
            itr.remove();
         }
      }
   }

   @Override
   public boolean removeTransformer(ClassFileTransformer transformer)
   {
      transformers.remove(transformer);
      return inst.removeTransformer(transformer);
   }

   @Override
   public void retransformClasses(Class... classes) throws UnmodifiableClassException
   {
      inst.retransformClasses(classes);
   }

   @Override
   public void redefineClasses(ClassDefinition... definitions)
      throws ClassNotFoundException, UnmodifiableClassException
   {
      inst.redefineClasses(definitions);
   }

   @Override
   public boolean isRetransformClassesSupported() { return true; }

   @Override
   public boolean isRedefineClassesSupported() { return true; }

   @Override
   public boolean isModifiableClass(Class theClass) { return inst.isModifiableClass(theClass); }

   @Override
   public Class[] getAllLoadedClasses() { return inst.getAllLoadedClasses(); }

   @Override
   public Class[] getInitiatedClasses(ClassLoader loader) { return inst.getInitiatedClasses(loader); }

   @Override
   public long getObjectSize(Object objectToSize) { return inst.getObjectSize(objectToSize); }

   @Override
   public void appendToBootstrapClassLoaderSearch(JarFile jarfile) {}

   @Override
   public void appendToSystemClassLoaderSearch(JarFile jarfile) {}

   @Override
   public boolean isNativeMethodPrefixSupported() { return false; }

   @Override
   public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy