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

mockit.internal.injection.InjectionProviders Maven / Gradle / Ivy

/*
 * Copyright (c) 2006 JMockit developers
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit.internal.injection;

import java.lang.reflect.*;
import java.util.*;
import javax.annotation.*;
import javax.inject.*;

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

public final class InjectionProviders
{
   @Nonnull private List injectables;
   @Nonnull private List consumedInjectionProviders;
   private Type typeOfInjectionPoint;

   InjectionProviders(@Nonnull LifecycleMethods lifecycleMethods) {
      injectables = Collections.emptyList();
      consumedInjectionProviders = new ArrayList<>();
   }

   boolean setInjectables(@SuppressWarnings("ParameterHidesMemberVariable") @Nonnull List injectables) {
      if (injectables.isEmpty()) {
         this.injectables = Collections.emptyList();
         return false;
      }

      this.injectables = new ArrayList<>(injectables);
      return true;
   }

   @Nonnull
   List addInjectables(@Nonnull List injectablesToAdd) {
      if (!injectablesToAdd.isEmpty()) {
         if (injectables.isEmpty()) {
            injectables = new ArrayList<>(injectablesToAdd);
         }
         else {
            injectables.addAll(injectablesToAdd);
         }
      }

      return injectables;
   }

   public void setTypeOfInjectionPoint(@Nonnull Type typeOfInjectionPoint) { this.typeOfInjectionPoint = typeOfInjectionPoint; }

   @Nullable
   public InjectionProvider getProviderByTypeAndOptionallyName(@Nonnull String nameOfInjectionPoint, @Nonnull TestedClass testedClass) {
      Type elementTypeOfIterable = getElementTypeIfIterable(typeOfInjectionPoint);

      if (elementTypeOfIterable != null) {
         return findInjectablesByTypeOnly(elementTypeOfIterable, testedClass);
      }

      return findInjectableByTypeAndOptionallyName(nameOfInjectionPoint, testedClass);
   }

   @Nullable
   private static Type getElementTypeIfIterable(@Nonnull Type injectableType) {
      if (injectableType instanceof ParameterizedType) {
         ParameterizedType parameterizedType = (ParameterizedType) injectableType;
         Class classOfInjectionPoint = (Class) parameterizedType.getRawType();

         if (Iterable.class.isAssignableFrom(classOfInjectionPoint)) {
            return parameterizedType.getActualTypeArguments()[0];
         }
      }

      return null;
   }

   @Nullable
   public InjectionProvider findNextInjectableForInjectionPoint(@Nonnull TestedClass testedClass) {
      for (InjectionProvider injectable : injectables) {
         if (hasTypeAssignableToInjectionPoint(injectable, testedClass) && !consumedInjectionProviders.contains(injectable)) {
            return injectable;
         }
      }

      return null;
   }

   private boolean hasTypeAssignableToInjectionPoint(@Nonnull InjectionProvider injectable, @Nonnull TestedClass testedClass) {
      Type declaredType = injectable.getDeclaredType();
      return isAssignableToInjectionPoint(declaredType, testedClass);
   }

   boolean isAssignableToInjectionPoint(@Nonnull Type injectableType, @Nonnull TestedClass testedClass) {
      if (testedClass.reflection.areMatchingTypes(typeOfInjectionPoint, injectableType)) {
         return true;
      }

      if (typeOfInjectionPoint instanceof ParameterizedType) {
         ParameterizedType parameterizedType = (ParameterizedType) typeOfInjectionPoint;
         Class classOfInjectionPoint = (Class) parameterizedType.getRawType();

         if (
            Iterable.class.isAssignableFrom(classOfInjectionPoint) ||
            INJECT_CLASS != null && Provider.class.isAssignableFrom(classOfInjectionPoint)
         ) {
            Type providedType = parameterizedType.getActualTypeArguments()[0];

            if (providedType.equals(injectableType)) {
               return true;
            }

            Class injectableClass = getClassType(injectableType);
            Class providedClass = getClassType(providedType);

            return providedClass.isAssignableFrom(injectableClass);
         }
      }

      return false;
   }

   @Nullable
   private InjectionProvider findInjectablesByTypeOnly(@Nonnull Type elementType, @Nonnull TestedClass testedClass) {
      GenericTypeReflection typeReflection = testedClass.reflection;
      MultiValuedProvider found = null;

      for (InjectionProvider injectable : injectables) {
         Type injectableType = injectable.getDeclaredType();
         Type elementTypeOfIterable = getElementTypeIfIterable(injectableType);

         if (elementTypeOfIterable != null && typeReflection.areMatchingTypes(elementType, elementTypeOfIterable)) {
            return injectable;
         }

         if (isAssignableToInjectionPoint(injectableType, testedClass)) {
            if (found == null) {
               found = new MultiValuedProvider(elementType);
            }

            found.addInjectable(injectable);
         }
      }

      return found;
   }

   @Nullable
   private InjectionProvider findInjectableByTypeAndOptionallyName(@Nonnull String nameOfInjectionPoint, @Nonnull TestedClass testedClass) {
      InjectionProvider foundInjectable = null;

      for (InjectionProvider injectable : injectables) {
         if (hasTypeAssignableToInjectionPoint(injectable, testedClass)) {
            if (nameOfInjectionPoint.equals(injectable.getName())) {
               return injectable;
            }

            if (foundInjectable == null) {
               foundInjectable = injectable;
            }
         }
      }

      return foundInjectable;
   }

   @Nullable
   InjectionProvider findInjectableByTypeAndName(@Nonnull String nameOfInjectionPoint, @Nonnull TestedClass testedClass) {
      for (InjectionProvider injectable : injectables) {
         if (hasTypeAssignableToInjectionPoint(injectable, testedClass) && nameOfInjectionPoint.equals(injectable.getName())) {
            return injectable;
         }
      }

      return null;
   }

   @Nullable
   Object getValueToInject(@Nonnull InjectionProvider injectionProvider, @Nullable Object currentTestClassInstance) {
      if (consumedInjectionProviders.contains(injectionProvider)) {
         return null;
      }

      Object value = injectionProvider.getValue(currentTestClassInstance);

      if (value != null) {
         consumedInjectionProviders.add(injectionProvider);
      }

      return value;
   }


   void resetConsumedInjectionProviders() { consumedInjectionProviders.clear(); }

   @Nonnull
   public List saveConsumedInjectionProviders() {
      List previouslyConsumed = consumedInjectionProviders;
      consumedInjectionProviders = new ArrayList<>();
      return previouslyConsumed;
   }

   public void restoreConsumedInjectionProviders(@Nonnull List previouslyConsumed) {
      consumedInjectionProviders = previouslyConsumed;
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy