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

mockit.internal.injection.LifecycleMethods 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.injection;

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.Map.*;
import javax.annotation.*;
import javax.servlet.*;

import mockit.internal.reflection.*;
import mockit.internal.state.*;
import static mockit.internal.injection.InjectionPoint.*;
import static mockit.internal.util.Utilities.*;

public final class LifecycleMethods
{
   @Nonnull private final List> classesSearched;
   @Nonnull private final Map, Method> initializationMethods;
   @Nonnull private final Map, Method> terminationMethods;
   @Nonnull private final Map, Object> objectsWithTerminationMethodsToExecute;
   @Nullable Object servletConfig;

   LifecycleMethods()
   {
      classesSearched = new ArrayList>();
      initializationMethods = new IdentityHashMap, Method>();
      terminationMethods = new IdentityHashMap, Method>();
      objectsWithTerminationMethodsToExecute = new IdentityHashMap, Object>();
   }

   public void findLifecycleMethods(@Nonnull Class testedClass)
   {
      if (testedClass.isInterface() || classesSearched.contains(testedClass)) {
         return;
      }

      boolean isServlet = isServlet(testedClass);
      Class classWithLifecycleMethods = testedClass;

      do {
         findLifecycleMethodsInSingleClass(isServlet, classWithLifecycleMethods);
         classWithLifecycleMethods = classWithLifecycleMethods.getSuperclass();
      }
      while (classWithLifecycleMethods != Object.class);

      classesSearched.add(testedClass);
   }

   private void findLifecycleMethodsInSingleClass(boolean isServlet, @Nonnull Class classWithLifecycleMethods)
   {
      Method initializationMethod = null;
      Method terminationMethod = null;
      int methodsFoundInSameClass = 0;

      for (Method method : classWithLifecycleMethods.getDeclaredMethods()) {
         if (method.isSynthetic()) {
            continue;
         }

         if (initializationMethod == null && isInitializationMethod(method, isServlet)) {
            initializationMethods.put(classWithLifecycleMethods, method);
            initializationMethod = method;
            methodsFoundInSameClass++;
         }
         else if (terminationMethod == null && isTerminationMethod(method, isServlet)) {
            terminationMethods.put(classWithLifecycleMethods, method);
            terminationMethod = method;
            methodsFoundInSameClass++;
         }

         if (methodsFoundInSameClass == 2) {
            break;
         }
      }
   }

   private static boolean isInitializationMethod(@Nonnull Method method, boolean isServlet)
   {
      if (hasLifecycleAnnotation(method, true)) {
         return true;
      }

      if (isServlet && "init".equals(method.getName())) {
         Class[] parameterTypes = method.getParameterTypes();
         return parameterTypes.length == 1 && parameterTypes[0] == ServletConfig.class;
      }

      return false;
   }

   private static boolean hasLifecycleAnnotation(@Nonnull Method method, boolean postConstruct)
   {
      try {
         Class lifecycleAnnotation = postConstruct ? PostConstruct.class : PreDestroy.class;

         if (method.isAnnotationPresent(lifecycleAnnotation)) {
            return true;
         }
      }
      catch (NoClassDefFoundError ignore) { /* can occur on JDK 9 */ }

      return false;
   }

   private static boolean isTerminationMethod(@Nonnull Method method, boolean isServlet)
   {
      return
         hasLifecycleAnnotation(method, false) ||
         isServlet && "destroy".equals(method.getName()) && method.getParameterTypes().length == 0;
   }

   public void executeInitializationMethodsIfAny(@Nonnull Class testedClass, @Nonnull Object testedObject)
   {
      Class superclass = testedClass.getSuperclass();

      if (superclass != Object.class) {
         executeInitializationMethodsIfAny(superclass, testedObject);
      }

      Method postConstructMethod = initializationMethods.get(testedClass);

      if (postConstructMethod != null) {
         executeInitializationMethod(testedObject, postConstructMethod);
      }

      Method preDestroyMethod = terminationMethods.get(testedClass);

      if (preDestroyMethod != null) {
         objectsWithTerminationMethodsToExecute.put(testedClass, testedObject);
      }
   }

   private void executeInitializationMethod(@Nonnull Object testedObject, @Nonnull Method initializationMethod)
   {
      Object[] args = NO_ARGS;

      if ("init".equals(initializationMethod.getName()) && initializationMethod.getParameterTypes().length == 1) {
         args = new Object[] {servletConfig};
      }

      TestRun.exitNoMockingZone();

      try {
         MethodReflection.invoke(testedObject, initializationMethod, args);
      }
      finally {
         TestRun.enterNoMockingZone();
      }
   }

   void executeTerminationMethodsIfAny()
   {
      try {
         for (Entry, Object> testedClassAndObject : objectsWithTerminationMethodsToExecute.entrySet()) {
            executeTerminationMethod(testedClassAndObject.getKey(), testedClassAndObject.getValue());
         }
      }
      finally {
         objectsWithTerminationMethodsToExecute.clear();
      }
   }

   private void executeTerminationMethod(@Nonnull Class testedClass, @Nonnull Object testedObject)
   {
      Method terminationMethod = terminationMethods.get(testedClass);
      TestRun.exitNoMockingZone();

      try {
         MethodReflection.invoke(testedObject, terminationMethod);
      }
      catch (RuntimeException ignore) {}
      catch (AssertionError ignore) {}
      finally {
         TestRun.enterNoMockingZone();
      }
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy