All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tomitribe.crest.help.HelpProcessor Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.tomitribe.crest.help;


import com.google.auto.service.AutoService;
import org.tomitribe.crest.api.Command;
import org.tomitribe.crest.api.Option;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@AutoService(Processor.class)
public class HelpProcessor extends AbstractProcessor {

    @Override
    public Set getSupportedAnnotationTypes() {
        final Set annotations = new LinkedHashSet();
        annotations.add(Command.class.getCanonicalName());
        return annotations;
    }

    @Override
    public boolean process(final Set annotations, final RoundEnvironment roundEnv) {

        final Map> all = roundEnv.getElementsAnnotatedWith(Command.class).stream()
                .filter(annotatedElement -> annotatedElement.getKind() == ElementKind.METHOD)
                .map(ExecutableElement.class::cast)
                .map(this::processCommand)
                .filter(Objects::nonNull)
                .collect(Collectors.groupingBy(CommandJavadoc::getName));

        all.values().forEach(this::writeAll);

        return true;
    }


    private void writeAll(final List list) {
        for (int i = 0; i < list.size(); i++) {
            final CommandJavadoc commandJavadoc = list.get(i);
            storeProperties(commandJavadoc.getResourceFileName(i), commandJavadoc.getProperties());
        }
    }

    private CommandJavadoc processCommand(final ExecutableElement executableElement) {
        final String commandName = getCommandName(executableElement);
        final String className = executableElement.getEnclosingElement().toString();

        final CommandJavadoc commandJavadoc = new CommandJavadoc(className, commandName);

        { // write method javadoc
            final String javadoc = processingEnv.getElementUtils().getDocComment(executableElement);
            if (javadoc != null) {
                commandJavadoc.setJavadoc(javadoc);
            }
        }

        // Add the parameter data
        for (final VariableElement parameter : executableElement.getParameters()) {
            final Option option = parameter.getAnnotation(Option.class);
            if (option == null) continue;
            for (final String optionName : option.value()) {
                commandJavadoc.getProperties().put(optionName, parameter.getSimpleName() + "");
            }
        }

        { // Record the arg names
            final List argNames = executableElement.getParameters().stream()
                    .map(Element::getSimpleName)
                    .map(Objects::toString)
                    .collect(Collectors.toList());

            commandJavadoc.setArgNames(argNames);
        }

        { // Record the arg types
            final List argTypes = executableElement.getParameters().stream()
                    .map(VariableElement.class::cast)
                    .map(Element::asType)
                    .map(TypeMirror::toString)
                    .collect(Collectors.toList());

            commandJavadoc.setArgTypes(argTypes);
        }

        return commandJavadoc;
    }

    private void storeProperties(final String resourceFile, final Properties properties) {
        try {
            final Filer filer = this.processingEnv.getFiler();
            final FileObject file = filer.createResource(StandardLocation.CLASS_OUTPUT, "", resourceFile);
            properties.store(file.openOutputStream(), null);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    private String getCommandName(final ExecutableElement executableElement) {
        final Command command = executableElement.getAnnotation(Command.class);

        return Stream.of(command.value(), executableElement.getSimpleName() + "")
                .filter(Objects::nonNull)
                .filter(s -> s.length() > 0)
                .findFirst()
                .orElseThrow(() -> new IllegalElementException("Illegal command with no name", executableElement));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy