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

mockit.internal.injection.TestedObject 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 static mockit.internal.util.AutoBoxing.isWrapperOfPrimitiveType;
import static mockit.internal.util.DefaultValues.defaultValueForPrimitiveType;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.List;

import mockit.Tested;
import mockit.internal.injection.field.FieldInjection;
import mockit.internal.injection.full.FullInjection;

abstract class TestedObject {
    @NonNull
    private final InjectionState injectionState;
    @NonNull
    final Tested metadata;
    @NonNull
    private final String testedName;
    @Nullable
    private final FullInjection fullInjection;
    @NonNull
    private final TestedClass testedClass;
    @Nullable
    private final TestedObjectCreation testedObjectCreation;
    @Nullable
    private List targetFields;
    boolean createAutomatically;

    @Nullable
    static Tested getTestedAnnotationIfPresent(@NonNull Annotation annotation) {
        if (annotation instanceof Tested) {
            return (Tested) annotation;
        }

        return annotation.annotationType().getAnnotation(Tested.class);
    }

    TestedObject(@NonNull InjectionState injectionState, @NonNull Tested metadata, @NonNull Class testClass,
            @NonNull String testedName, @NonNull Type testedType, @NonNull Class testedClass) {
        this.injectionState = injectionState;
        this.metadata = metadata;
        this.testedName = testedName;
        fullInjection = metadata.fullyInitialized() ? new FullInjection(injectionState, testedClass, testedName) : null;

        if (testedClass.isInterface() || testedClass.isEnum() || testedClass.isPrimitive() || testedClass.isArray()) {
            testedObjectCreation = null;
            this.testedClass = new TestedClass(testedType, testedClass);
        } else {
            testedObjectCreation = new TestedObjectCreation(injectionState, fullInjection, testedType, testedClass);
            this.testedClass = testedObjectCreation.testedClass;
            injectionState.lifecycleMethods.findLifecycleMethods(testedClass);
        }

        this.testedClass.testClass = testClass;
    }

    boolean isAvailableDuringSetup() {
        return metadata.availableDuringSetup();
    }

    void instantiateWithInjectableValues(@NonNull Object testClassInstance) {
        if (alreadyInstantiated(testClassInstance)) {
            return;
        }

        Object testedObject = getExistingTestedInstanceIfApplicable(testClassInstance);
        Class testedObjectClass = testedClass.targetClass;
        InjectionPoint injectionPoint = new InjectionPoint(testedClass.declaredType, testedName);

        if (isNonInstantiableType(testedObjectClass, testedObject)) {
            reusePreviouslyCreatedInstance(testClassInstance, injectionPoint);
            return;
        }

        if (testedObject == null && createAutomatically) {
            if (reusePreviouslyCreatedInstance(testClassInstance, injectionPoint)) {
                return;
            }

            testedObject = createAndRegisterNewObject(testClassInstance, injectionPoint);
        } else if (testedObject != null) {
            registerTestedObject(injectionPoint, testedObject);
            testedObjectClass = testedObject.getClass();
        }

        if (testedObject != null && testedObjectClass.getClassLoader() != null) {
            performFieldInjection(testedObjectClass, testedObject);

            if (createAutomatically) {
                injectionState.lifecycleMethods.executeInitializationMethodsIfAny(testedObjectClass, testedObject);
            }
        }
    }

    boolean alreadyInstantiated(@NonNull Object testClassInstance) {
        return false;
    }

    @Nullable
    abstract Object getExistingTestedInstanceIfApplicable(@NonNull Object testClassInstance);

    static boolean isNonInstantiableType(@NonNull Class targetClass, @Nullable Object currentValue) {
        return targetClass.isPrimitive() && defaultValueForPrimitiveType(targetClass).equals(currentValue)
                || currentValue == null && (targetClass.isArray() || targetClass.isEnum() || targetClass.isAnnotation()
                        || isWrapperOfPrimitiveType(targetClass));
    }

    private boolean reusePreviouslyCreatedInstance(@NonNull Object testClassInstance,
            @NonNull InjectionPoint injectionPoint) {
        Object previousInstance = injectionState.getTestedInstance(injectionPoint, metadata.global());

        if (previousInstance != null) {
            setInstance(testClassInstance, previousInstance);
            return true;
        }

        return false;
    }

    abstract void setInstance(@NonNull Object testClassInstance, @Nullable Object testedInstance);

    @Nullable
    private Object createAndRegisterNewObject(@NonNull Object testClassInstance,
            @NonNull InjectionPoint injectionPoint) {
        Object testedInstance = null;

        if (testedObjectCreation != null) {
            testedInstance = testedObjectCreation.create(false, true);

            if (testedInstance != null) {
                setInstance(testClassInstance, testedInstance);
                registerTestedObject(injectionPoint, testedInstance);
            }
        }

        return testedInstance;
    }

    private void registerTestedObject(@NonNull InjectionPoint injectionPoint, @NonNull Object testedObject) {
        injectionState.saveTestedObject(injectionPoint, testedObject, metadata.global());
    }

    private void performFieldInjection(@NonNull Class targetClass, @NonNull Object testedObject) {
        FieldInjection fieldInjection = new FieldInjection(injectionState, fullInjection);

        if (targetFields == null) {
            targetFields = Injector.findAllTargetInstanceFieldsInTestedClassHierarchy(targetClass, testedClass);
        }

        fieldInjection.injectIntoEligibleFields(targetFields, testedObject, testedClass);
    }

    void clearIfAutomaticCreation(@NonNull Object testClassInstance, boolean duringTearDown) {
        if (createAutomatically && (duringTearDown || !isAvailableDuringSetup())) {
            setInstance(testClassInstance, null);

            if (fullInjection != null) {
                fullInjection.clear();
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy