class MotanAsyncProcessor extends AbstractProcessor {
    protected static String ASYNC = MotanConstants.ASYNC_SUFFIX;

    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        HashSet<String> types = new HashSet<>();
        types.add(MotanAsync.class.getName());
        return types;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (roundEnv.processingOver()) {
            return true;
        }
        for (Element elem : roundEnv.getElementsAnnotatedWith(MotanAsync.class)) {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "MotanAsyncProcessor will process " + elem);
            try {
                writeAsyncClass(elem);
                processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "MotanAsyncProcessor done for " + elem);
            } catch (Exception e) {
                processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
                        "MotanAsyncProcessor process " + elem + " fail. exception:" + e.getMessage());
                e.printStackTrace();
            }
        }
        return true;
    }

    private void writeAsyncClass(Element elem) throws Exception {<FILL_FUNCTION_BODY>}

    private void addMethods(TypeElement interfaceClazz, TypeSpec.Builder classBuilder) {
        List<? extends Element> elements = interfaceClazz.getEnclosedElements();
        if (elements != null && !elements.isEmpty()) {
            for (Element e : elements) {
                if (ElementKind.METHOD.equals(e.getKind())) {
                    ExecutableElement method = (ExecutableElement) e;
                    MethodSpec.Builder methodBuilder =
                            MethodSpec.methodBuilder(method.getSimpleName().toString() + ASYNC)
                                    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).returns(ResponseFuture.class)
                                    .addTypeVariables(getTypeNames(method.getTypeParameters()));
                    // add method params
                    List<? extends VariableElement> vars = method.getParameters();
                    for (VariableElement var : vars) {
                        methodBuilder.addParameter(ParameterSpec.builder(TypeName.get(var.asType()), var.getSimpleName().toString())
                                .build());
                    }
                    classBuilder.addMethod(methodBuilder.build());
                }
            }
        }
    }

    private List<TypeVariableName> getTypeNames(List<? extends TypeParameterElement> types) {
        List<TypeVariableName> result = new ArrayList<>();
        if (types != null && !types.isEmpty()) {
            for (TypeParameterElement type : types) {
                result.add(TypeVariableName.get(type));
            }
        }
        return result;
    }

    private void addSuperInterfaceMethods(List<? extends TypeMirror> superInterfaces, TypeSpec.Builder classBuilder) {
        if (superInterfaces != null && !superInterfaces.isEmpty()) {
            for (TypeMirror tm : superInterfaces) {
                try {
                    if (tm.getKind().equals(TypeKind.DECLARED)) {
                        TypeElement de = (TypeElement) ((DeclaredType) tm).asElement();
                        addMethods(de, classBuilder);
                        addSuperInterfaceMethods(de.getInterfaces(), classBuilder);
                    }
                } catch (Exception e) {
                    processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
                            "MotanAsyncProcessor process superinterface " + tm.toString() + " fail. exception:" + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }

}


        if (elem.getKind().isInterface()) {
            TypeElement interfaceClazz = (TypeElement) elem;
            String className = interfaceClazz.getSimpleName().toString();
            TypeSpec.Builder classBuilder =
                    TypeSpec.interfaceBuilder(className + ASYNC).addModifiers(Modifier.PUBLIC)
                            .addSuperinterface(TypeName.get(elem.asType()));

            // add class generic type
            classBuilder.addTypeVariables(getTypeNames(interfaceClazz.getTypeParameters()));

            // add direct method
            addMethods(interfaceClazz, classBuilder);

            // add method form superinterface
            addSuperInterfaceMethods(interfaceClazz.getInterfaces(), classBuilder);

            // write class
            JavaFile javaFile =
                    JavaFile.builder(processingEnv.getElementUtils().getPackageOf(interfaceClazz).getQualifiedName().toString(),
                            classBuilder.build()).build();

            // use StandardLocation.SOURCE_OUTPUT  e.g.:target/generated-sources/annotations/
            // you can set configuration <generatedSourcesDirectory> in maven-compiler-plugin to change it
            javaFile.writeTo(processingEnv.getFiler());
        } else {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
                    "MotanAsyncProcessor not process, because " + elem + " not a interface.");
        }
    
<methods>public Iterable<? extends javax.annotation.processing.Completion> getCompletions(javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror, javax.lang.model.element.ExecutableElement, java.lang.String) ,public Set<java.lang.String> getSupportedAnnotationTypes() ,public Set<java.lang.String> getSupportedOptions() ,public javax.lang.model.SourceVersion getSupportedSourceVersion() ,public synchronized void init(javax.annotation.processing.ProcessingEnvironment) ,public abstract boolean process(Set<? extends javax.lang.model.element.TypeElement>, javax.annotation.processing.RoundEnvironment) <variables>static final boolean $assertionsDisabled,private boolean initialized,protected javax.annotation.processing.ProcessingEnvironment processingEnv