/* * Copyright (C) 2014 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dagger.internal.codegen; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import dagger.internal.codegen.writer.ClassName; import dagger.internal.codegen.writer.JavaWriter; import dagger.internal.codegen.writer.TypeWriter; import java.io.IOException; import javax.annotation.processing.Filer; import javax.lang.model.element.Element; import static com.google.common.base.Preconditions.checkNotNull; /** * A template class that provides a framework for properly handling IO while generating source files * from an annotation processor. Particularly, it makes a best effort to ensure that files that * fail to write successfully are deleted. * * @param <T> The input type from which source is to be generated. * @author Gregory Kick * @since 2.0 */ abstract class SourceFileGenerator<T> { private final Filer filer; SourceFileGenerator(Filer filer) { this.filer = checkNotNull(filer); } final void generate(T input) throws SourceFileGenerationException { ClassName generatedTypeName = nameGeneratedType(input); ImmutableSet<Element> originatingElements = ImmutableSet.<Element>copyOf(getOriginatingElements(input)); try { ImmutableSet<JavaWriter> writers = write(generatedTypeName, input); for (JavaWriter javaWriter : writers) { try { javaWriter.file(filer, originatingElements); } catch (IOException e) { throw new SourceFileGenerationException(getNamesForWriters(javaWriter.getTypeWriters()), e, getElementForErrorReporting(input)); } } } catch (Exception e) { // if the code above threw a SFGE, use that Throwables.propagateIfPossible(e, SourceFileGenerationException.class); // otherwise, throw a new one throw new SourceFileGenerationException(ImmutableList.<ClassName>of(), e, getElementForErrorReporting(input)); } } private static Iterable<ClassName> getNamesForWriters(Iterable<TypeWriter> typeWriters) { return Iterables.transform(typeWriters, new Function<TypeWriter, ClassName>() { @Override public ClassName apply(TypeWriter input) { return input.name(); } }); } /** * Implementations should return the {@link ClassName} for the top-level type to be generated. */ abstract ClassName nameGeneratedType(T input); /** * Implementations should return {@link Element} instances from which the source is to be * generated. */ abstract Iterable<? extends Element> getOriginatingElements(T input); /** * Returns an optional element to be used for reporting errors. This returns a single element * rather than a collection to reduce output noise. */ abstract Optional<? extends Element> getElementForErrorReporting(T input); /** */ abstract ImmutableSet<JavaWriter> write(ClassName generatedTypeName, T input); }