18da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal/*
28da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * Copyright 2010 Google Inc.
38da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal *
48da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * Licensed under the Apache License, Version 2.0 (the "License");
58da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * you may not use this file except in compliance with the License.
68da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * You may obtain a copy of the License at
78da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal *
88da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * http://www.apache.org/licenses/LICENSE-2.0
98da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal *
108da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * Unless required by applicable law or agreed to in writing, software
118da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * distributed under the License is distributed on an "AS IS" BASIS,
128da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * See the License for the specific language governing permissions and
148da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * limitations under the License.
158da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal */
168da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalpackage com.google.android.testing.mocking;
178da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
188da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javassist.CannotCompileException;
198da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
208da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport java.io.FileNotFoundException;
218da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport java.io.IOException;
228da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport java.io.OutputStream;
238da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport java.util.ArrayList;
248da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport java.util.HashSet;
258da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport java.util.List;
268da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport java.util.Set;
278da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
288da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.annotation.processing.AbstractProcessor;
298da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.annotation.processing.RoundEnvironment;
308da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.annotation.processing.SupportedAnnotationTypes;
318da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.annotation.processing.SupportedOptions;
328da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.annotation.processing.SupportedSourceVersion;
338da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.lang.model.SourceVersion;
348da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.lang.model.element.AnnotationMirror;
358da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.lang.model.element.AnnotationValue;
368da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.lang.model.element.Element;
378da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.lang.model.element.TypeElement;
388da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.tools.Diagnostic.Kind;
398da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalimport javax.tools.JavaFileObject;
408da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
418da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
428da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal/**
438da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * Annotation Processor to generate the mocks for Android Mock.
448da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal *
458da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * This processor will automatically create mocks for all classes
468da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * specified by {@link UsesMocks} annotations.
478da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal *
488da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal * @author swoodward@google.com (Stephen Woodward)
498da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal */
508da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal@SupportedAnnotationTypes("com.google.android.testing.mocking.UsesMocks")
518da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal@SupportedSourceVersion(SourceVersion.RELEASE_5)
528da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal@SupportedOptions({
538da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    UsesMocksProcessor.REGENERATE_FRAMEWORK_MOCKS,
548da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    UsesMocksProcessor.LOGFILE,
558da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    UsesMocksProcessor.BIN_DIR
568da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal})
578da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigalpublic class UsesMocksProcessor extends AbstractProcessor {
588da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  public static final String LOGFILE = "logfile";
598da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  public static final String REGENERATE_FRAMEWORK_MOCKS = "RegenerateFrameworkMocks";
608da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  public static final String BIN_DIR = "bin_dir";
618da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  private AndroidMockGenerator mockGenerator = new AndroidMockGenerator();
628da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  private AndroidFrameworkMockGenerator frameworkMockGenerator =
638da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      new AndroidFrameworkMockGenerator();
648da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  ProcessorLogger logger;
658da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
668da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  /**
678da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * Main entry point of the processor.  This is called by the Annotation framework.
688da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * {@link javax.annotation.processing.AbstractProcessor} for more details.
698da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   */
708da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  @Override
718da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment) {
728da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    try {
738da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      prepareLogger();
748da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      List<Class<?>> classesToMock = getClassesToMock(environment);
758da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      Set<GeneratedClassFile> mockedClassesSet = getMocksFor(classesToMock);
768da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      writeMocks(mockedClassesSet);
778da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    } catch (Exception e) {
788da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      logger.printMessage(Kind.ERROR, e);
798da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    } finally {
808da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      logger.close();
818da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    }
828da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    return false;
838da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
848da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
858da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  /**
868da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * Returns a Set of GeneratedClassFile objects which represent all of the classes to be mocked.
878da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   *
888da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @param classesToMock the list of classes which need to be mocked.
898da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @return a set of mock support classes to support the mocking of all the classes specified in
908da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   *         {@literal classesToMock}.
918da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   */
928da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  private Set<GeneratedClassFile> getMocksFor(List<Class<?>> classesToMock) throws IOException,
938da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      CannotCompileException {
948da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    logger.printMessage(Kind.NOTE, "Found " + classesToMock.size() + " classes to mock");
958da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    boolean regenerateFrameworkMocks = processingEnv.getOptions().get(
968da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        REGENERATE_FRAMEWORK_MOCKS) != null;
978da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    if (regenerateFrameworkMocks) {
988da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      logger.printMessage(Kind.NOTE, "Regenerating Framework Mocks on Request");
998da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    }
1008da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    Set<GeneratedClassFile> mockedClassesSet =
1018da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        getClassMocks(classesToMock, regenerateFrameworkMocks);
1028da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    logger.printMessage(Kind.NOTE, "Found " + mockedClassesSet.size()
1038da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        + " mocked classes to save");
1048da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    return mockedClassesSet;
1058da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
1068da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
1078da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  /**
1088da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @param environment the environment for this round of processing as provided to the main
1098da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   *        {@link #process(Set, RoundEnvironment)} method.
1108da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @return a List of Class objects for the classes that need to be mocked.
1118da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   */
1128da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  private List<Class<?>> getClassesToMock(RoundEnvironment environment) {
1138da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    logger.printMessage(Kind.NOTE, "Start Processing Annotations");
1148da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    List<Class<?>> classesToMock = new ArrayList<Class<?>>();
1158da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    classesToMock.addAll(
1168da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        findClassesToMock(environment.getElementsAnnotatedWith(UsesMocks.class)));
1178da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    return classesToMock;
1188da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
1198da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
1208da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  private void prepareLogger() {
1218da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    if (logger == null) {
1228da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      logger = new ProcessorLogger(processingEnv.getOptions().get(LOGFILE), processingEnv);
1238da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    }
1248da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
1258da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
1268da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  /**
1278da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * Finds all of the classes that should be mocked, based on {@link UsesMocks} annotations
1288da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * in the various source files being compiled.
1298da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   *
1308da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @param annotatedElements a Set of all elements holding {@link UsesMocks} annotations.
1318da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @return all of the classes that should be mocked.
1328da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   */
1338da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  List<Class<?>> findClassesToMock(Set<? extends Element> annotatedElements) {
1348da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    logger.printMessage(Kind.NOTE, "Processing " + annotatedElements);
1358da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    List<Class<?>> classList = new ArrayList<Class<?>>();
1368da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    for (Element annotation : annotatedElements) {
1378da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      List<? extends AnnotationMirror> mirrors = annotation.getAnnotationMirrors();
1388da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      for (AnnotationMirror mirror : mirrors) {
1398da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        if (mirror.getAnnotationType().toString().equals(UsesMocks.class.getName())) {
1408da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal          for (AnnotationValue annotationValue : mirror.getElementValues().values()) {
1418da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal            for (Object classFileName : (Iterable<?>) annotationValue.getValue()) {
1428da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal              String className = classFileName.toString();
1438da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal              if (className.endsWith(".class")) {
1448da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal                className = className.substring(0, className.length() - 6);
1458da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal              }
1468da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal              logger.printMessage(Kind.NOTE, "Adding Class to Mocking List: " + className);
1478da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal              try {
1488da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal                classList.add(Class.forName(className, false, getClass().getClassLoader()));
1498da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal              } catch (ClassNotFoundException e) {
1508da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal                logger.reportClasspathError(className, e);
1518da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal              }
1528da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal            }
1538da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal          }
1548da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        }
1558da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      }
1568da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    }
1578da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    return classList;
1588da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
1598da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
1608da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  /**
1618da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * Gets a set of GeneratedClassFiles to represent all of the support classes required to
1628da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * mock the List of classes provided in {@code classesToMock}.
1638da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @param classesToMock the list of classes to be mocked.
1648da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @param regenerateFrameworkMocks if true, then mocks for the framework classes will be created
1658da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   *        instead of pulled from the existing set of framework support classes.
1668da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @return a Set of {@link GeneratedClassFile} for all of the mocked classes.
1678da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   */
1688da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  Set<GeneratedClassFile> getClassMocks(List<Class<?>> classesToMock,
1698da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      boolean regenerateFrameworkMocks) throws IOException, CannotCompileException {
1708da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    Set<GeneratedClassFile> mockedClassesSet = new HashSet<GeneratedClassFile>();
1718da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    for (Class<?> clazz : classesToMock) {
1728da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      try {
1738da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        logger.printMessage(Kind.NOTE, "Mocking " + clazz);
1748da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        if (!AndroidMock.isAndroidClass(clazz) || regenerateFrameworkMocks) {
1758da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal          mockedClassesSet.addAll(getAndroidMockGenerator().createMocksForClass(clazz));
1768da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        } else {
1778da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal          mockedClassesSet.addAll(getAndroidFrameworkMockGenerator().getMocksForClass(clazz));
1788da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        }
1798da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      } catch (ClassNotFoundException e) {
1808da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        logger.reportClasspathError(clazz.getName(), e);
1818da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      } catch (NoClassDefFoundError e) {
1828da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        logger.reportClasspathError(clazz.getName(), e);
1838da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      }
1848da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    }
1858da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    return mockedClassesSet;
1868da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
1878da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
1888da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  private AndroidFrameworkMockGenerator getAndroidFrameworkMockGenerator() {
1898da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    return frameworkMockGenerator;
1908da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
1918da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
1928da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  /**
1938da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * Writes the provided mocks from {@code mockedClassesSet} to the bin folder alongside the
1948da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * .class files being generated by the javac call which invoked this annotation processor.
1958da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * In Eclipse, additional information is needed as the Eclipse annotation processor framework
1968da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * is missing key functionality required by this method.  Instead the classes are saved using
1978da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * a FileOutputStream and the -Abin_dir processor option must be set.
1988da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @param mockedClassesSet the set of mocks to be saved.
1998da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   */
2008da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  void writeMocks(Set<GeneratedClassFile> mockedClassesSet) {
2018da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    for (GeneratedClassFile clazz : mockedClassesSet) {
2028da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      OutputStream classFileStream;
2038da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      try {
2048da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        logger.printMessage(Kind.NOTE, "Saving " + clazz.getClassName());
2058da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        JavaFileObject classFile = processingEnv.getFiler().createClassFile(clazz.getClassName());
2068da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        classFileStream = classFile.openOutputStream();
2078da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        classFileStream.write(clazz.getContents());
2088da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        classFileStream.close();
2098da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      } catch (IOException e) {
2108da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        logger.printMessage(Kind.ERROR, "Internal Error saving mock: " + clazz.getClassName());
2118da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        logger.printMessage(Kind.ERROR, e);
2128da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      } catch (UnsupportedOperationException e) {
2138da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        // Eclipse annotation processing doesn't support class creation.
2148da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        logger.printMessage(Kind.NOTE, "Saving via Eclipse " + clazz.getClassName());
2158da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal        saveMocksEclipse(clazz, processingEnv.getOptions().get(BIN_DIR).toString().trim());
2168da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      }
2178da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    }
2188da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    logger.printMessage(Kind.NOTE, "Finished Processing Mocks");
2198da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
2208da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
2218da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  /**
2228da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * Workaround to save the mocks for Eclipse's annotation processing framework which doesn't
2238da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * support the JavaFileObject object.
2248da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @param clazz the class to save.
2258da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   * @param outputFolderName the output folder where the class will be saved.
2268da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal   */
2278da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  private void saveMocksEclipse(GeneratedClassFile clazz, String outputFolderName) {
2288da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    try {
2298da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      FileUtils.saveClassToFolder(clazz, outputFolderName);
2308da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    } catch (FileNotFoundException e) {
2318da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      logger.printMessage(Kind.ERROR, e);
2328da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    } catch (IOException e) {
2338da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal      logger.printMessage(Kind.ERROR, e);
2348da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    }
2358da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
2368da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal
2378da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  private AndroidMockGenerator getAndroidMockGenerator() {
2388da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal    return mockGenerator;
2398da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal  }
2408da3e6ec64b991f5aa1e6561941d130683eba753Luis Sigal}
241