/* * Copyright (C) 2015 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.auto.common.BasicAnnotationProcessor.ProcessingStep; import com.google.auto.common.MoreElements; import com.google.common.collect.ImmutableSet; import com.google.common.collect.SetMultimap; import java.lang.annotation.Annotation; import javax.annotation.processing.Messager; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; /** * A {@link ProcessingStep} that is responsible for dealing with a component or production component * as part of the {@link ComponentProcessor}. */ abstract class AbstractComponentProcessingStep implements ProcessingStep { private final Class<? extends Annotation> componentAnnotation; private final Messager messager; private final ComponentHierarchyValidator componentHierarchyValidator; private final BindingGraphValidator bindingGraphValidator; private final ComponentDescriptor.Factory componentDescriptorFactory; private final BindingGraph.Factory bindingGraphFactory; private final ComponentGenerator componentGenerator; AbstractComponentProcessingStep( Class<? extends Annotation> componentAnnotation, Messager messager, ComponentHierarchyValidator componentHierarchyValidator, BindingGraphValidator bindingGraphValidator, ComponentDescriptor.Factory componentDescriptorFactory, BindingGraph.Factory bindingGraphFactory, ComponentGenerator componentGenerator) { this.componentAnnotation = componentAnnotation; this.messager = messager; this.componentHierarchyValidator = componentHierarchyValidator; this.bindingGraphValidator = bindingGraphValidator; this.componentDescriptorFactory = componentDescriptorFactory; this.bindingGraphFactory = bindingGraphFactory; this.componentGenerator = componentGenerator; } @Override public final ImmutableSet<Element> process( SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) { ImmutableSet.Builder<Element> rejectedElements = ImmutableSet.builder(); ComponentElementValidator componentElementValidator = componentElementValidator(elementsByAnnotation); for (Element element : elementsByAnnotation.get(componentAnnotation)) { TypeElement componentTypeElement = MoreElements.asType(element); try { if (componentElementValidator.validateComponent(componentTypeElement, messager)) { ComponentDescriptor componentDescriptor = componentDescriptorFactory.forComponent(componentTypeElement); ValidationReport<TypeElement> hierarchyReport = componentHierarchyValidator.validate(componentDescriptor); hierarchyReport.printMessagesTo(messager); if (hierarchyReport.isClean()) { BindingGraph bindingGraph = bindingGraphFactory.create(componentDescriptor); ValidationReport<TypeElement> graphReport = bindingGraphValidator.validate(bindingGraph); graphReport.printMessagesTo(messager); if (graphReport.isClean()) { generateComponent(bindingGraph); } } } } catch (TypeNotPresentException e) { rejectedElements.add(componentTypeElement); } } return rejectedElements.build(); } private void generateComponent(BindingGraph bindingGraph) { try { componentGenerator.generate(bindingGraph); } catch (SourceFileGenerationException e) { e.printMessageTo(messager); } } /** * Returns an object that can validate a type element annotated with the component type. */ protected abstract ComponentElementValidator componentElementValidator( SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation); /** * Validates a component type element. */ protected static abstract class ComponentElementValidator { /** * Validates a component type element. Prints any messages about the element to * {@code messager}. * * @throws TypeNotPresentException if any type required to validate the component cannot be * found */ abstract boolean validateComponent(TypeElement componentTypeElement, Messager messager); } }