/*
* 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.reflect.*;
import java.util.*;
import javax.annotation.*;
import mockit.*;
import mockit.internal.injection.field.*;
import mockit.internal.injection.full.*;
import static mockit.internal.util.AutoBoxing.*;
import static mockit.internal.util.DefaultValues.*;
abstract class TestedObject
{
@Nonnull final InjectionState injectionState;
@Nonnull private final String testedName;
@Nonnull final Tested metadata;
@Nullable private final FullInjection fullInjection;
@Nonnull private final TestedClass testedClass;
@Nullable private final TestedObjectCreation testedObjectCreation;
@Nullable private List<Field> targetFields;
boolean createAutomatically;
boolean requireDIAnnotation;
TestedObject(
@Nonnull InjectionState injectionState, @Nonnull Tested metadata,
@Nonnull String testedName, @Nonnull Type testedType, @Nonnull Class<?> testedClass)
{
this.injectionState = injectionState;
this.testedName = testedName;
this.metadata = metadata;
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);
}
}
boolean isAvailableDuringSetup() { return metadata.availableDuringSetup(); }
void instantiateWithInjectableValues(@Nonnull Object testClassInstance)
{
if (alreadyInstantiated(testClassInstance)) {
return;
}
Object testedObject = getExistingTestedInstanceIfApplicable(testClassInstance);
Class<?> testedObjectClass = testedClass.targetClass;
if (isNonInstantiableType(testedObjectClass, testedObject)) {
reusePreviouslyCreatedInstance(testClassInstance);
return;
}
injectionState.setTestedTypeReflection(testedClass.reflection);
if (testedObject == null && createAutomatically) {
if (reusePreviouslyCreatedInstance(testClassInstance)) {
return;
}
testedObject = createAndRegisterNewObject(testClassInstance);
}
else if (testedObject != null) {
registerTestedObject(testedObject);
testedObjectClass = testedObject.getClass();
}
if (testedObject != null && testedObjectClass.getClassLoader() != null) {
performFieldInjection(testedObjectClass, testedObject);
executeInitializationMethodsIfAny(testedObjectClass, testedObject);
}
}
boolean alreadyInstantiated(@Nonnull Object testClassInstance) { return false; }
@Nullable
abstract Object getExistingTestedInstanceIfApplicable(@Nonnull Object testClassInstance);
private 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)
{
Object previousInstance = injectionState.getTestedInstance(testedClass.declaredType, testedName);
if (previousInstance != null) {
setInstance(testClassInstance, previousInstance);
return true;
}
return false;
}
void setInstance(@Nonnull Object testClassInstance, @Nullable Object testedInstance) {}
@Nullable
private Object createAndRegisterNewObject(@Nonnull Object testClassInstance)
{
Object testedInstance = null;
if (testedObjectCreation != null) {
testedInstance = testedObjectCreation.create();
setInstance(testClassInstance, testedInstance);
registerTestedObject(testedInstance);
}
return testedInstance;
}
private void registerTestedObject(@Nonnull Object testedObject)
{
InjectionPoint injectionPoint = new InjectionPoint(testedClass.declaredType, testedName);
injectionState.saveTestedObject(injectionPoint, testedObject);
}
private void performFieldInjection(@Nonnull Class<?> targetClass, @Nonnull Object testedObject)
{
FieldInjection fieldInjection =
new FieldInjection(injectionState, testedClass, fullInjection, requireDIAnnotation);
if (targetFields == null) {
targetFields = fieldInjection.findAllTargetInstanceFieldsInTestedClassHierarchy(targetClass);
requireDIAnnotation = fieldInjection.isDIAnnotationRequired();
}
fieldInjection.injectIntoEligibleFields(targetFields, testedObject);
}
private void executeInitializationMethodsIfAny(@Nonnull Class<?> testedClass, @Nonnull Object testedObject)
{
if (createAutomatically) {
injectionState.lifecycleMethods.executeInitializationMethodsIfAny(testedClass, testedObject);
}
}
void clearIfAutomaticCreation(@Nonnull Object testClassInstance)
{
if (createAutomatically && !isAvailableDuringSetup()) {
setInstance(testClassInstance, null);
}
}
}