1/*
2 * Copyright (c) 2007 Mockito contributors
3 * This program is made available under the terms of the MIT License.
4 */
5package org.mockito.internal.configuration;
6
7import org.mockito.*;
8import org.mockito.configuration.AnnotationEngine;
9import org.mockito.internal.configuration.injection.scanner.InjectMocksScanner;
10import org.mockito.internal.configuration.injection.scanner.MockScanner;
11
12import java.lang.annotation.Annotation;
13import java.lang.reflect.Field;
14import java.util.HashSet;
15import java.util.Set;
16
17import static org.mockito.internal.util.collections.Sets.newMockSafeHashSet;
18
19/**
20 * See {@link MockitoAnnotations}
21 */
22@SuppressWarnings({"deprecation", "unchecked"})
23public class InjectingAnnotationEngine implements AnnotationEngine {
24    private AnnotationEngine delegate = new DefaultAnnotationEngine();
25    private AnnotationEngine spyAnnotationEngine = new SpyAnnotationEngine();
26
27    /***
28     * Create a mock using {@link DefaultAnnotationEngine}
29     *
30     * @see org.mockito.internal.configuration.DefaultAnnotationEngine
31     * @see org.mockito.configuration.AnnotationEngine#createMockFor(java.lang.annotation.Annotation, java.lang.reflect.Field)
32     */
33    @Deprecated
34    public Object createMockFor(Annotation annotation, Field field) {
35        return delegate.createMockFor(annotation, field);
36    }
37
38    /**
39     * Process the fields of the test instance and create Mocks, Spies, Captors and inject them on fields
40     * annotated @InjectMocks.
41     *
42     * <p>
43     * This code process the test class and the super classes.
44     * <ol>
45     * <li>First create Mocks, Spies, Captors.</li>
46     * <li>Then try to inject them.</li>
47     * </ol>
48     *
49     * @param clazz Not used
50     * @param testInstance The instance of the test, should not be null.
51     *
52     * @see org.mockito.configuration.AnnotationEngine#process(Class, Object)
53     */
54    public void process(Class<?> clazz, Object testInstance) {
55        processIndependentAnnotations(testInstance.getClass(), testInstance);
56        processInjectMocks(testInstance.getClass(), testInstance);
57    }
58
59    private void processInjectMocks(final Class<?> clazz, final Object testInstance) {
60        Class<?> classContext = clazz;
61        while (classContext != Object.class) {
62            injectMocks(testInstance);
63            classContext = classContext.getSuperclass();
64        }
65    }
66
67    private void processIndependentAnnotations(final Class<?> clazz, final Object testInstance) {
68        Class<?> classContext = clazz;
69        while (classContext != Object.class) {
70            //this will create @Mocks, @Captors, etc:
71            delegate.process(classContext, testInstance);
72            //this will create @Spies:
73            spyAnnotationEngine.process(classContext, testInstance);
74
75            classContext = classContext.getSuperclass();
76        }
77    }
78
79
80    /**
81     * Initializes mock/spies dependencies for objects annotated with
82     * &#064;InjectMocks for given testClassInstance.
83     * <p>
84     * See examples in javadoc for {@link MockitoAnnotations} class.
85     *
86     * @param testClassInstance
87     *            Test class, usually <code>this</code>
88     */
89    public void injectMocks(final Object testClassInstance) {
90        Class<?> clazz = testClassInstance.getClass();
91        Set<Field> mockDependentFields = new HashSet<Field>();
92        Set<Object> mocks = newMockSafeHashSet();
93
94        while (clazz != Object.class) {
95            new InjectMocksScanner(clazz).addTo(mockDependentFields);
96            new MockScanner(testClassInstance, clazz).addPreparedMocks(mocks);
97            clazz = clazz.getSuperclass();
98        }
99
100        new DefaultInjectionEngine().injectMocksOnFields(mockDependentFields, mocks, testClassInstance);
101    }
102
103}
104