Package restx.config.processor

Source Code of restx.config.processor.SettingsAnnotationProcessor

package restx.config.processor;

import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.samskivert.mustache.Template;
import restx.common.Mustaches;
import restx.common.processor.RestxAbstractProcessor;
import restx.config.Settings;
import restx.config.SettingsKey;

import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
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.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
*/
@SupportedAnnotationTypes({
        "restx.config.Settings"
})
@SupportedOptions({ "debug" })
public class SettingsAnnotationProcessor extends RestxAbstractProcessor {
    final Template settingsProviderTpl;
    final Template settingsConfigTpl;

    public SettingsAnnotationProcessor() {
        settingsProviderTpl = Mustaches.compile(SettingsAnnotationProcessor.class, "SettingsProvider.mustache");
        settingsConfigTpl = Mustaches.compile(SettingsAnnotationProcessor.class, "SettingsConfig.mustache");
    }

    @Override
    protected boolean processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) throws Exception {
        for (Element elem : roundEnv.getElementsAnnotatedWith(Settings.class)) {
            try {
                TypeElement typeElement = (TypeElement) elem;
                if (!typeElement.getKind().isInterface()) {
                    error(
                            String.format("only an interface can be annotated with @Settings - %s",
                                    typeElement.getSimpleName()), typeElement);
                    continue;
                }

                String fqcn = typeElement.getQualifiedName().toString();
                String pack = getPackage(typeElement).getQualifiedName().toString();
                String settingsSimpleType = typeElement.getSimpleName().toString();

                boolean shouldGenerateProvider = false;
                List<ImmutableMap<String,Object>> keys = new ArrayList<>();

                for (Element element : typeElement.getEnclosedElements()) {
                    if (element.getKind() == ElementKind.METHOD) {
                        ExecutableElement methodElem = (ExecutableElement) element;
                        if (!methodElem.getParameters().isEmpty()) {
                            error("invalid settings accessor method - it must not take any parameter", methodElem);
                            continue;
                        }

                        String accessorReturnType = methodElem.getReturnType().toString();
                        String targetType;
                        String prefix;
                        String suffix;
                        boolean guavaOptional = accessorReturnType.startsWith(Optional.class.getCanonicalName());
                        boolean java8Optional = accessorReturnType.startsWith("java.util.Optional");
                        if (guavaOptional || java8Optional) {
                            List<? extends TypeMirror> typeArguments = ((DeclaredType) methodElem.getReturnType()).getTypeArguments();
                            if (typeArguments.isEmpty()) {
                                error(String.format("unsupported return type %s for settings accessor method" +
                                                " - you must provide generic type when using Optional",
                                                accessorReturnType), methodElem);
                                continue;
                            } else {
                                targetType = typeArguments.get(0).toString();
                            }
                        } else {
                            targetType = accessorReturnType;
                        }
                        if (guavaOptional) {
                            prefix = "";
                            suffix = "";
                        } else if (java8Optional) {
                            prefix = "java.util.Optional.ofNullable(";
                            suffix = ".orNull())";
                        } else {
                            prefix = "";
                            suffix = ".get()";
                        }
                        String configAccessor;
                        switch (targetType) {
                            case "java.lang.String":
                                configAccessor = "getString";
                                break;
                            case "java.lang.Integer":
                            case "int":
                                configAccessor = "getInt";
                                break;
                            case "java.lang.Long":
                            case "long":
                                configAccessor = "getLong";
                                break;
                            case "java.lang.Boolean":
                            case "boolean":
                                configAccessor = "getBoolean";
                                break;
                            default:
                                error(String.format("unsupported return type %s for settings accessor method" +
                                                " - it must be one of [String, Integer, int, Long, long, Boolean, boolean]",
                                                accessorReturnType), methodElem);
                                continue;
                        }

                        SettingsKey settingsKey = element.getAnnotation(SettingsKey.class);

                        if (settingsKey == null) {
                            error(String.format(
                                    "all methods in a Settings interface must be annotated with @SettingsKey - %s",
                                            element.getSimpleName()), element);
                            continue;
                        }
                        shouldGenerateProvider |= !Strings.isNullOrEmpty(settingsKey.defaultValue())
                                                    || !Strings.isNullOrEmpty(settingsKey.doc());

                        keys.add(ImmutableMap.<String, Object>builder()
                                .put("accessorReturnType", accessorReturnType)
                                .put("configAccessor", configAccessor)
                                .put("accessorName", methodElem.getSimpleName().toString())
                                .put("key", settingsKey.key())
                                .put("prefix", prefix)
                                .put("suffix", suffix)
                                .put("doc", settingsKey.doc())
                                .put("defaultValue", settingsKey.defaultValue())
                                .build());
                    }
                }

                ImmutableMap<String, Object> ctx = ImmutableMap.<String, Object>builder()
                        .put("package", pack)
                        .put("settingsSimpleType", settingsSimpleType)
                        .put("settingsType", fqcn)
                        .put("keys", keys).build();

                generateJavaClass(pack + "." + settingsSimpleType + "Config", settingsConfigTpl, ctx, elem);
                if (shouldGenerateProvider) {
                    generateJavaClass(pack + "." + settingsSimpleType + "Provider", settingsProviderTpl, ctx, elem);
                }
            } catch (Exception e) {
                fatalError("error when processing " + elem, e, elem);
            }
        }
        return true;
    }
}
TOP

Related Classes of restx.config.processor.SettingsAnnotationProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.