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