Home | History | Annotate | Download | only in configuration
      1 /*
      2  * Copyright (c) 2007 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockito.internal.configuration;
      6 
      7 import java.lang.annotation.Annotation;
      8 import java.lang.reflect.Field;
      9 import java.util.HashMap;
     10 import java.util.Map;
     11 import org.mockito.Captor;
     12 import org.mockito.Mock;
     13 import org.mockito.MockitoAnnotations;
     14 import org.mockito.exceptions.base.MockitoException;
     15 import org.mockito.plugins.AnnotationEngine;
     16 
     17 import static org.mockito.internal.exceptions.Reporter.moreThanOneAnnotationNotAllowed;
     18 import static org.mockito.internal.util.reflection.FieldSetter.setField;
     19 
     20 /**
     21  * Initializes fields annotated with @{@link org.mockito.Mock} or @{@link org.mockito.Captor}.
     22  *
     23  * <p>
     24  * The {@link #process(Class, Object)} method implementation <strong>does not</strong> process super classes!
     25  *
     26  * @see MockitoAnnotations
     27  */
     28 @SuppressWarnings("unchecked")
     29 public class IndependentAnnotationEngine implements AnnotationEngine, org.mockito.configuration.AnnotationEngine {
     30     private final Map<Class<? extends Annotation>, FieldAnnotationProcessor<?>> annotationProcessorMap = new HashMap<Class<? extends Annotation>, FieldAnnotationProcessor<?>>();
     31 
     32     public IndependentAnnotationEngine() {
     33         registerAnnotationProcessor(Mock.class, new MockAnnotationProcessor());
     34         registerAnnotationProcessor(Captor.class, new CaptorAnnotationProcessor());
     35     }
     36 
     37     private Object createMockFor(Annotation annotation, Field field) {
     38         return forAnnotation(annotation).process(annotation, field);
     39     }
     40 
     41     private <A extends Annotation> FieldAnnotationProcessor<A> forAnnotation(A annotation) {
     42         if (annotationProcessorMap.containsKey(annotation.annotationType())) {
     43             return (FieldAnnotationProcessor<A>) annotationProcessorMap.get(annotation.annotationType());
     44         }
     45         return new FieldAnnotationProcessor<A>() {
     46             public Object process(A annotation, Field field) {
     47                 return null;
     48             }
     49         };
     50     }
     51 
     52     private <A extends Annotation> void registerAnnotationProcessor(Class<A> annotationClass, FieldAnnotationProcessor<A> fieldAnnotationProcessor) {
     53         annotationProcessorMap.put(annotationClass, fieldAnnotationProcessor);
     54     }
     55 
     56     @Override
     57     public void process(Class<?> clazz, Object testInstance) {
     58         Field[] fields = clazz.getDeclaredFields();
     59         for (Field field : fields) {
     60             boolean alreadyAssigned = false;
     61             for(Annotation annotation : field.getAnnotations()) {
     62                 Object mock = createMockFor(annotation, field);
     63                 if (mock != null) {
     64                     throwIfAlreadyAssigned(field, alreadyAssigned);
     65                     alreadyAssigned = true;
     66                     try {
     67                         setField(testInstance, field,mock);
     68                     } catch (Exception e) {
     69                         throw new MockitoException("Problems setting field " + field.getName() + " annotated with "
     70                                 + annotation, e);
     71                     }
     72                 }
     73             }
     74         }
     75     }
     76 
     77     void throwIfAlreadyAssigned(Field field, boolean alreadyAssigned) {
     78         if (alreadyAssigned) {
     79             throw moreThanOneAnnotationNotAllowed(field.getName());
     80         }
     81     }
     82 
     83 }
     84