• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package dagger.internal.codegen;
17 
18 import com.google.common.base.Function;
19 import com.google.common.base.Optional;
20 import com.google.common.base.Throwables;
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.ImmutableSet;
23 import com.google.common.collect.Iterables;
24 import dagger.internal.codegen.writer.ClassName;
25 import dagger.internal.codegen.writer.JavaWriter;
26 import dagger.internal.codegen.writer.TypeWriter;
27 import java.io.IOException;
28 import javax.annotation.processing.Filer;
29 import javax.lang.model.element.Element;
30 
31 import static com.google.common.base.Preconditions.checkNotNull;
32 
33 /**
34  * A template class that provides a framework for properly handling IO while generating source files
35  * from an annotation processor.  Particularly, it makes a best effort to ensure that files that
36  * fail to write successfully are deleted.
37  *
38  * @param <T> The input type from which source is to be generated.
39  * @author Gregory Kick
40  * @since 2.0
41  */
42 abstract class SourceFileGenerator<T> {
43   private final Filer filer;
44 
SourceFileGenerator(Filer filer)45   SourceFileGenerator(Filer filer) {
46     this.filer = checkNotNull(filer);
47   }
48 
generate(T input)49   final void generate(T input) throws SourceFileGenerationException {
50     ClassName generatedTypeName = nameGeneratedType(input);
51     ImmutableSet<Element> originatingElements =
52         ImmutableSet.<Element>copyOf(getOriginatingElements(input));
53     try {
54       ImmutableSet<JavaWriter> writers = write(generatedTypeName, input);
55       for (JavaWriter javaWriter : writers) {
56         try {
57           javaWriter.file(filer, originatingElements);
58         } catch (IOException e) {
59           throw new SourceFileGenerationException(getNamesForWriters(javaWriter.getTypeWriters()),
60               e, getElementForErrorReporting(input));
61         }
62       }
63     } catch (Exception e) {
64       // if the code above threw a SFGE, use that
65       Throwables.propagateIfPossible(e, SourceFileGenerationException.class);
66       // otherwise, throw a new one
67       throw new SourceFileGenerationException(ImmutableList.<ClassName>of(), e,
68           getElementForErrorReporting(input));
69     }
70   }
71 
getNamesForWriters(Iterable<TypeWriter> typeWriters)72   private static Iterable<ClassName> getNamesForWriters(Iterable<TypeWriter> typeWriters) {
73     return Iterables.transform(typeWriters, new Function<TypeWriter, ClassName>() {
74       @Override public ClassName apply(TypeWriter input) {
75         return input.name();
76       }
77     });
78   }
79 
80   /**
81    * Implementations should return the {@link ClassName} for the top-level type to be generated.
82    */
83   abstract ClassName nameGeneratedType(T input);
84 
85   /**
86    * Implementations should return {@link Element} instances from which the source is to be
87    * generated.
88    */
89   abstract Iterable<? extends Element> getOriginatingElements(T input);
90 
91   /**
92    * Returns an optional element to be used for reporting errors. This returns a single element
93    * rather than a collection to reduce output noise.
94    */
95   abstract Optional<? extends Element> getElementForErrorReporting(T input);
96 
97   /**
98    */
99   abstract ImmutableSet<JavaWriter> write(ClassName generatedTypeName, T input);
100 }
101