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

com.yanzhenjie.andserver.processor.ResolverProcessor Maven / Gradle / Ivy

/*
 * Copyright 2018 Zhenjie Yan.
 *
 * 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 com.yanzhenjie.andserver.processor;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.yanzhenjie.andserver.annotation.AppInfo;
import com.yanzhenjie.andserver.annotation.Resolver;
import com.yanzhenjie.andserver.processor.util.Constants;
import com.yanzhenjie.andserver.processor.util.Logger;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.Validate;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;

/**
 * Created by Zhenjie Yan on 2018/9/11.
 */
public class ResolverProcessor extends BaseProcessor {

    private Filer mFiler;
    private Elements mElements;
    private Logger mLog;

    private TypeName mContext;
    private TypeName mOnRegisterType;
    private TypeName mRegisterType;

    private TypeName mResolver;

    private TypeName mString;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        mFiler = processingEnv.getFiler();
        mElements = processingEnv.getElementUtils();
        mLog = new Logger(processingEnv.getMessager());

        mContext = TypeName.get(mElements.getTypeElement(Constants.CONTEXT_TYPE).asType());
        mOnRegisterType = TypeName.get(mElements.getTypeElement(Constants.ON_REGISTER_TYPE).asType());
        mRegisterType = TypeName.get(mElements.getTypeElement(Constants.REGISTER_TYPE).asType());

        mResolver = TypeName.get(mElements.getTypeElement(Constants.RESOLVER_TYPE).asType());

        mString = TypeName.get(String.class);
    }

    @Override
    public boolean process(Set set, RoundEnvironment roundEnv) {
        if (CollectionUtils.isEmpty(set)) {
            return false;
        }

        Set appSet = roundEnv.getElementsAnnotatedWith(AppInfo.class);
        String registerPackageName = getRegisterPackageName(appSet);

        Map resolverMap = findAnnotation(roundEnv);
        if (!resolverMap.isEmpty()) {
            createRegister(registerPackageName, resolverMap);
        }
        return true;
    }

    private Map findAnnotation(RoundEnvironment roundEnv) {
        Set set = roundEnv.getElementsAnnotatedWith(Resolver.class);
        Map resolverMap = new HashMap<>();

        for (Element element: set) {
            if (element instanceof TypeElement) {
                TypeElement typeElement = (TypeElement) element;

                Set modifiers = typeElement.getModifiers();
                Validate.isTrue(modifiers.contains(Modifier.PUBLIC), "The modifier public is missing on %s.",
                    typeElement.getQualifiedName());

                List interfaces = typeElement.getInterfaces();
                if (CollectionUtils.isEmpty(interfaces)) {
                    mLog.w(String.format(
                        "The annotation Resolver must be used in a subclass of [ExceptionResolver] on %s.",
                        typeElement.getQualifiedName()));
                    continue;
                }
                for (TypeMirror typeMirror: interfaces) {
                    if (mResolver.equals(TypeName.get(typeMirror))) {
                        resolverMap.put(getGroup(typeElement), typeElement);
                        break;
                    } else {
                        mLog.w(String.format(
                            "The annotation Resolver must be used in a subclass of [ExceptionResolver] on %s.",
                            typeElement.getQualifiedName()));
                    }
                }
            }
        }
        return resolverMap;
    }

    private void createRegister(String registerPackageName, Map resolverMap) {
        TypeName typeName = ParameterizedTypeName.get(ClassName.get(Map.class), mString, mResolver);
        FieldSpec mapField = FieldSpec.builder(typeName, "mMap", Modifier.PRIVATE).build();

        CodeBlock.Builder rootCode = CodeBlock.builder().addStatement("this.mMap = new $T<>()", HashMap.class);
        for (Map.Entry entry: resolverMap.entrySet()) {
            String group = entry.getKey();
            TypeElement resolver = entry.getValue();
            mLog.i(String.format("------ Processing %s ------", resolver.getSimpleName()));
            rootCode.addStatement("this.mMap.put($S, new $T())", group, resolver);
        }

        MethodSpec rootMethod = MethodSpec.constructorBuilder()
            .addModifiers(Modifier.PUBLIC)
            .addCode(rootCode.build())
            .build();

        MethodSpec registerMethod = MethodSpec.methodBuilder("onRegister")
            .addAnnotation(Override.class)
            .addModifiers(Modifier.PUBLIC)
            .addParameter(mContext, "context")
            .addParameter(mString, "group")
            .addParameter(mRegisterType, "register")
            .addStatement("$T resolver = mMap.get(group)", mResolver)
            .beginControlFlow("if(resolver == null)")
            .addStatement("resolver = mMap.get($S)", "default")
            .endControlFlow()
            .beginControlFlow("if(resolver != null)")
            .addStatement("register.setResolver(resolver)")
            .endControlFlow()
            .build();

        TypeSpec adapterClass = TypeSpec.classBuilder("ResolverRegister")
            .addJavadoc(Constants.DOC_EDIT_WARN)
            .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
            .addSuperinterface(mOnRegisterType)
            .addField(mapField)
            .addMethod(rootMethod)
            .addMethod(registerMethod)
            .build();

        JavaFile javaFile = JavaFile.builder(registerPackageName, adapterClass).build();
        try {
            javaFile.writeTo(mFiler);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    private String getGroup(TypeElement type) {
        Resolver resolver = type.getAnnotation(Resolver.class);
        if (resolver != null) {
            return resolver.value();
        }
        throw new IllegalStateException(String.format("The type is not a Resolver: %1$s.", type));
    }

    @Override
    protected void addAnnotation(Set> classSet) {
        classSet.add(Resolver.class);
        classSet.add(AppInfo.class);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy