paperparcel.PaperParcelProcessingStep.java Source code

Java tutorial

Introduction

Here is the source code for paperparcel.PaperParcelProcessingStep.java

Source

/*
 * Copyright (C) 2016 Bradley Campbell.
 *
 * 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 paperparcel;

import com.google.auto.common.BasicAnnotationProcessor;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;
import java.lang.annotation.Annotation;
import java.util.Set;
import javax.annotation.processing.Messager;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.UnknownTypeException;
import javax.tools.Diagnostic;

import static com.google.auto.common.MoreElements.asType;

/**
 * A {@link BasicAnnotationProcessor.ProcessingStep} that is responsible for dealing with all
 * {@link PaperParcel} annotated objects as part of the {@link PaperParcelProcessor}.
 */
final class PaperParcelProcessingStep implements BasicAnnotationProcessor.ProcessingStep {
    private final Messager messager;
    private final OptionsHolder optionsHolder;
    private final PaperParcelValidator paperParcelValidator;
    private final PaperParcelDescriptor.Factory paperParcelDescriptorFactory;
    private final PaperParcelGenerator paperParcelGenerator;

    PaperParcelProcessingStep(Messager messager, OptionsHolder optionsHolder,
            PaperParcelValidator paperParcelValidator, PaperParcelDescriptor.Factory paperParcelDescriptorFactory,
            PaperParcelGenerator paperParcelGenerator) {
        this.messager = messager;
        this.optionsHolder = optionsHolder;
        this.paperParcelValidator = paperParcelValidator;
        this.paperParcelDescriptorFactory = paperParcelDescriptorFactory;
        this.paperParcelGenerator = paperParcelGenerator;
    }

    @Override
    public Set<? extends Class<? extends Annotation>> annotations() {
        return ImmutableSet.of(PaperParcel.class);
    }

    @Override
    public Set<Element> process(SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
        for (Element element : elementsByAnnotation.get(PaperParcel.class)) {
            TypeElement paperParcelElement = asType(element);
            OptionsDescriptor options = Utils.getOptions(paperParcelElement).or(optionsHolder.getOptions());
            ValidationReport<TypeElement> validationReport = paperParcelValidator.validate(paperParcelElement,
                    options);
            validationReport.printMessagesTo(messager);
            if (validationReport.isClean()) {
                try {
                    generatePaperParcel(paperParcelDescriptorFactory.create(paperParcelElement, options));
                } catch (PaperParcelDescriptor.NonWritableFieldsException e) {
                    printMessages(e);
                } catch (PaperParcelDescriptor.NonReadableFieldsException e) {
                    printMessages(e);
                } catch (UnknownTypeException e) {
                    messager.printMessage(Diagnostic.Kind.ERROR,
                            String.format(ErrorMessages.FIELD_MISSING_TYPE_ADAPTER, e.getUnknownType().toString()),
                            (Element) e.getArgument());
                }
            }
        }
        return ImmutableSet.of();
    }

    private void generatePaperParcel(PaperParcelDescriptor descriptor) {
        try {
            paperParcelGenerator.generate(descriptor);
        } catch (SourceFileGenerationException e) {
            e.printMessageTo(messager);
        }
    }

    private void printMessages(PaperParcelDescriptor.NonWritableFieldsException e) {
        ImmutableSet<ExecutableElement> validConstructors = e.allNonWritableFieldsMap().keySet();
        ImmutableSet<ExecutableElement> invalidConstructors = e.unassignableConstructorParameterMap().keySet();

        if (validConstructors.size() > 0) {
            // Log errors for each non-writable field in each valid constructor
            for (ExecutableElement validConstructor : validConstructors) {
                ImmutableList<VariableElement> nonWritableFields = e.allNonWritableFieldsMap()
                        .get(validConstructor);
                for (VariableElement nonWritableField : nonWritableFields) {
                    String fieldName = nonWritableField.getSimpleName().toString();
                    messager.printMessage(Diagnostic.Kind.ERROR,
                            String.format(ErrorMessages.FIELD_NOT_WRITABLE,
                                    asType(nonWritableField.getEnclosingElement()).getQualifiedName(), fieldName,
                                    validConstructor.toString(), buildExcludeRulesChecklist()),
                            nonWritableField);
                }
            }

        } else {
            // Log errors for unassignable parameters in each invalid constructor
            for (ExecutableElement invalidConstructor : invalidConstructors) {
                ImmutableList<VariableElement> unassignableFields = e.unassignableConstructorParameterMap()
                        .get(invalidConstructor);
                for (VariableElement unassignableField : unassignableFields) {
                    String fieldName = unassignableField.getSimpleName().toString();
                    messager.printMessage(Diagnostic.Kind.ERROR,
                            String.format(ErrorMessages.UNMATCHED_CONSTRUCTOR_PARAMETER, fieldName,
                                    asType(invalidConstructor.getEnclosingElement()).getQualifiedName()),
                            invalidConstructor);
                }
            }
        }
    }

    private void printMessages(PaperParcelDescriptor.NonReadableFieldsException e) {
        for (VariableElement nonReadableField : e.nonReadableFields()) {
            String fieldName = nonReadableField.getSimpleName().toString();
            messager.printMessage(Diagnostic.Kind.ERROR,
                    String.format(ErrorMessages.FIELD_NOT_READABLE,
                            asType(nonReadableField.getEnclosingElement()).getQualifiedName(), fieldName,
                            buildExcludeRulesChecklist()),
                    nonReadableField);
        }
    }

    private String buildExcludeRulesChecklist() {
        StringBuilder sb = new StringBuilder();
        OptionsDescriptor options = optionsHolder.getOptions();

        for (Set<Modifier> modifiers : options.excludeModifiers()) {
            sb.append("- Adding the ");
            for (Modifier modifier : modifiers) {
                sb.append(modifier.toString());
                sb.append(" ");
            }
            sb.append(modifiers.size() == 1 ? "modifier\n" : "modifiers\n");
        }

        ImmutableList<String> excludeAnnotations = options.excludeAnnotationNames();
        for (String excludeAnnotation : excludeAnnotations) {
            sb.append("- Adding @");
            sb.append(excludeAnnotation);
            sb.append('\n');
        }

        if (options.excludeNonExposedFields()) {
            ImmutableList<String> exposeAnnotations = options.exposeAnnotationNames();
            for (String exposeAnnotation : exposeAnnotations) {
                sb.append("- Removing @");
                sb.append(exposeAnnotation);
                sb.append('\n');
            }
        }

        return sb.toString();
    }
}